11module 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
1616import Prelude
@@ -40,6 +40,7 @@ import Foreign.Object.ST as FOST
4040import Prim.Row as Row
4141import Record as Record
4242import 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
109113defaultEncoding ∷ 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
163161else 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