Skip to content

Commit 019b2f7

Browse files
committed
Refactor encoding
1 parent ea7d3bf commit 019b2f7

File tree

2 files changed

+222
-202
lines changed

2 files changed

+222
-202
lines changed

src/Data/Codec/Argonaut/Sum.purs

Lines changed: 88 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
module Data.Codec.Argonaut.Sum
2-
( Encoding
3-
, class GFields
2+
( Encoding(..)
43
, class GCases
4+
, class GFields
55
, defaultEncoding
66
, enumSum
77
, gCasesDecode
88
, gCasesEncode
9+
, gFieldsDecode
10+
, gFieldsEncode
911
, sum
1012
, sumWith
1113
, taggedSum
12-
, gFieldsDecode
13-
, gFieldsEncode
1414
) where
1515

1616
import Prelude
@@ -40,6 +40,7 @@ import Foreign.Object.ST as FOST
4040
import Prim.Row as Row
4141
import Record as Record
4242
import Type.Proxy (Proxy(..))
43+
import Unsafe.Coerce (unsafeCoerce)
4344

4445
-- | A helper for defining JSON codecs for "enum" sum types, where every
4546
-- | constructor is nullary, and the type will be encoded as a string.
@@ -99,15 +100,18 @@ taggedSum name printTag parseTag f g = Codec.codec decodeCase encodeCase
99100

100101
--------------------------------------------------------------------------------
101102

102-
type Encoding =
103-
{ tagKey String
104-
, valuesKey String
105-
, unwrapSingleArguments Boolean
106-
, omitEmptyArguments Boolean
107-
}
103+
data Encoding
104+
= EncodeCtorAsTag
105+
{ unwrapSingleArguments Boolean }
106+
| EncodeTagValue
107+
{ tagKey String
108+
, valuesKey String
109+
, omitEmptyArguments Boolean
110+
, unwrapSingleArguments Boolean
111+
}
108112

109113
defaultEncoding Encoding
110-
defaultEncoding =
114+
defaultEncoding = EncodeTagValue
111115
{ tagKey: "tag"
112116
, valuesKey: "values"
113117
, unwrapSingleArguments: false
@@ -144,20 +148,14 @@ instance gCasesConstructorNoArgs ∷
144148
gCasesEncode encoding _ _ =
145149
let
146150
name = reflectSymbol @name Proxy String
147-
value =
148-
( if encoding.omitEmptyArguments then Nothing
149-
else Just $ CA.encode CA.jarray []
150-
) Maybe Json
151151
in
152-
encodeTagged encoding name value
152+
encodeCase encoding name []
153153

154154
gCasesDecode Encoding Record r Json Either JsonDecodeError (Constructor name NoArguments)
155155
gCasesDecode encoding _ json = do
156-
obj ← CA.decode jobject json _ (Object Json)
157156
let name = reflectSymbol @name Proxy String
158157

159-
checkTag encoding obj name
160-
parseNoFields encoding obj
158+
parseNoFields encoding json name
161159
pure $ Constructor NoArguments
162160

163161
else instance gCasesConstructorSingleArg
@@ -170,20 +168,14 @@ else instance gCasesConstructorSingleArg ∷
170168
let
171169
codec = Record.get (Proxy @name) r JsonCodec a
172170
name = reflectSymbol @name Proxy String
173-
value =
174-
( if encoding.unwrapSingleArguments then CA.encode codec x
175-
else CA.encode CA.jarray [ CA.encode codec x ]
176-
) Json
177171
in
178-
encodeTagged encoding name (Just value)
172+
encodeCase encoding name [ CA.encode codec x ]
179173

180174
gCasesDecode Encoding Record r Json Either JsonDecodeError (Constructor name (Argument a))
181175
gCasesDecode encoding r json = do
182-
obj ← CA.decode jobject json _ (Object Json)
183176
let name = reflectSymbol @name Proxy String
184-
checkTag encoding obj name
185177

186-
field ← parseSingleField encoding obj _ Json
178+
field ← parseSingleField encoding json name _ Json
187179
let codec = Record.get (Proxy @name) r JsonCodec a
188180
result ← CA.decode codec field _ a
189181
pure $ Constructor (Argument result)
@@ -200,17 +192,14 @@ else instance gCasesConstructorManyArgs ∷
200192
codecs = Record.get (Proxy @name) r codecs
201193
name = reflectSymbol @name Proxy String
202194
jsons = gFieldsEncode encoding codecs rep Array Json
203-
value = CA.encode CA.jarray jsons Json
204195
in
205-
encodeTagged encoding name (Just value)
196+
encodeCase encoding name jsons
206197

207198
gCasesDecode Encoding Record r Json Either JsonDecodeError (Constructor name args)
208199
gCasesDecode encoding r json = do
209-
obj ← CA.decode jobject json _ (Object Json)
210200
let name = reflectSymbol @name Proxy String
211-
checkTag encoding obj name
212201

213-
jsons ← parseManyFields encoding obj _ (Array Json)
202+
jsons ← parseManyFields encoding json name _ (Array Json)
214203
let codecs = Record.get (Proxy @name) r codecs
215204
result ← gFieldsDecode encoding codecs jsons _ args
216205
pure $ Constructor result
@@ -292,58 +281,79 @@ instance gFieldsProduct ∷
292281

293282
--------------------------------------------------------------------------------
294283

295-
checkTag Encoding Object Json String Either JsonDecodeError Unit
296-
checkTag encoding obj expectedTag = do
284+
checkTag String Object Json String Either JsonDecodeError Unit
285+
checkTag tagKey obj expectedTag = do
297286
val ←
298-
( Obj.lookup encoding.tagKey obj
299-
# note (TypeMismatch ("Expecting a tag property `" <> encoding.tagKey <> "`"))
287+
( Obj.lookup tagKey obj
288+
# note (TypeMismatch ("Expecting a tag property `" <> tagKey <> "`"))
300289
) _ Json
301290
tag ← CA.decode CA.string val _ String
302291
unless (tag == expectedTag)
303292
$ throwError
304293
$ TypeMismatch ("Expecting tag `" <> expectedTag <> "`, got `" <> tag <> "`")
305294

306-
parseSingleField Encoding Object Json Either JsonDecodeError Json
307-
parseSingleField encoding obj = do
308-
val ←
309-
( Obj.lookup encoding.valuesKey obj
310-
# note (TypeMismatch ("Expecting a value property `" <> encoding.valuesKey <> "`"))
311-
) _ Json
312-
if encoding.unwrapSingleArguments then
313-
pure val
314-
else do
315-
fields ← CA.decode CA.jarray val
316-
case fields of
317-
[ head ] → pure head
318-
_ → throwError $ TypeMismatch "Expecting exactly one element"
319-
320-
parseNoFields Encoding Object Json Either JsonDecodeError Unit
321-
parseNoFields encoding obj = do
322-
when (not encoding.omitEmptyArguments) do
295+
parseSingleField Encoding Json String Either JsonDecodeError Json
296+
parseSingleField encoding json expectedTag = case encoding of
297+
EncodeCtorAsTag { unwrapSingleArguments } → unsafeCoerce "todo"
298+
EncodeTagValue { tagKey, valuesKey, unwrapSingleArguments } → do
299+
obj ← CA.decode jobject json
300+
checkTag tagKey obj expectedTag
323301
val ←
324-
( Obj.lookup encoding.valuesKey obj
325-
# note (TypeMismatch ("Expecting a value property `" <> encoding.valuesKey <> "`"))
302+
( Obj.lookup valuesKey obj
303+
# note (TypeMismatch ("Expecting a value property `" <> valuesKey <> "`"))
326304
) _ Json
327-
fields ← CA.decode CA.jarray val _ (Array Json)
328-
when (fields /= [])
329-
$ throwError
330-
$ TypeMismatch "Expecting an empty array"
331-
332-
parseManyFields Encoding Object Json Either JsonDecodeError (Array Json)
333-
parseManyFields encoding obj = do
334-
val ←
335-
( Obj.lookup encoding.valuesKey obj
336-
# note (TypeMismatch ("Expecting a value property `" <> encoding.valuesKey <> "`"))
337-
) _ Json
338-
CA.decode CA.jarray val
339-
340-
encodeTagged Encoding String Maybe Json Json
341-
encodeTagged encoding tag maybeJson =
342-
let
343-
tagEntry =
344-
Just (encoding.tagKey /\ CA.encode CA.string tag) Maybe (String /\ Json)
345-
valEntry =
346-
map (\json → (encoding.valuesKey /\ json)) maybeJson Maybe (String /\ Json)
347-
in
348-
encode jobject $ Obj.fromFoldable $ catMaybes
349-
[ tagEntry, valEntry ]
305+
if unwrapSingleArguments then
306+
pure val
307+
else do
308+
fields ← CA.decode CA.jarray val
309+
case fields of
310+
[ head ] → pure head
311+
_ → throwError $ TypeMismatch "Expecting exactly one element"
312+
313+
parseNoFields Encoding Json String Either JsonDecodeError Unit
314+
parseNoFields encoding json expectedTag =
315+
case encoding of
316+
EncodeCtorAsTag { unwrapSingleArguments } → unsafeCoerce "todo"
317+
EncodeTagValue { tagKey, valuesKey, omitEmptyArguments } →
318+
do
319+
obj ← CA.decode jobject json
320+
checkTag tagKey obj expectedTag
321+
when (not omitEmptyArguments) do
322+
val ←
323+
( Obj.lookup valuesKey obj
324+
# note (TypeMismatch ("Expecting a value property `" <> valuesKey <> "`"))
325+
) _ Json
326+
fields ← CA.decode CA.jarray val _ (Array Json)
327+
when (fields /= [])
328+
$ throwError
329+
$ TypeMismatch "Expecting an empty array"
330+
331+
parseManyFields Encoding Json String Either JsonDecodeError (Array Json)
332+
parseManyFields encoding json expectedTag =
333+
case encoding of
334+
EncodeCtorAsTag { unwrapSingleArguments } → unsafeCoerce "todo"
335+
EncodeTagValue { tagKey, valuesKey } → do
336+
obj ← CA.decode jobject json
337+
checkTag tagKey obj expectedTag
338+
val ←
339+
( Obj.lookup valuesKey obj
340+
# note (TypeMismatch ("Expecting a value property `" <> valuesKey <> "`"))
341+
) _ Json
342+
CA.decode CA.jarray val
343+
344+
encodeCase Encoding String Array Json Json
345+
encodeCase encoding tag jsons =
346+
case encoding of
347+
EncodeCtorAsTag { unwrapSingleArguments } → unsafeCoerce "todo"
348+
EncodeTagValue { tagKey, valuesKey, unwrapSingleArguments, omitEmptyArguments } →
349+
let
350+
tagEntry =
351+
Just (tagKey /\ CA.encode CA.string tag) Maybe (String /\ Json)
352+
valEntry =
353+
case jsons of
354+
[] | omitEmptyArguments → Nothing
355+
[ json ] | unwrapSingleArguments → Just (valuesKey /\ json)
356+
manyJsons → Just (valuesKey /\ CA.encode CA.jarray manyJsons)
357+
in
358+
encode jobject $ Obj.fromFoldable $ catMaybes
359+
[ tagEntry, valEntry ]

0 commit comments

Comments
 (0)