1
1
module Data.Codec.Argonaut.Sum
2
- ( Encoding
3
- , class GFields
2
+ ( Encoding (..)
4
3
, class GCases
4
+ , class GFields
5
5
, defaultEncoding
6
6
, enumSum
7
7
, gCasesDecode
8
8
, gCasesEncode
9
+ , gFieldsDecode
10
+ , gFieldsEncode
9
11
, sum
10
12
, sumWith
11
13
, taggedSum
12
- , gFieldsDecode
13
- , gFieldsEncode
14
14
) where
15
15
16
16
import Prelude
@@ -40,6 +40,7 @@ import Foreign.Object.ST as FOST
40
40
import Prim.Row as Row
41
41
import Record as Record
42
42
import Type.Proxy (Proxy (..))
43
+ import Unsafe.Coerce (unsafeCoerce )
43
44
44
45
-- | A helper for defining JSON codecs for "enum" sum types, where every
45
46
-- | 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
99
100
100
101
-- ------------------------------------------------------------------------------
101
102
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
+ }
108
112
109
113
defaultEncoding ∷ Encoding
110
- defaultEncoding =
114
+ defaultEncoding = EncodeTagValue
111
115
{ tagKey: " tag"
112
116
, valuesKey: " values"
113
117
, unwrapSingleArguments: false
@@ -144,20 +148,14 @@ instance gCasesConstructorNoArgs ∷
144
148
gCasesEncode encoding _ _ =
145
149
let
146
150
name = reflectSymbol @name Proxy ∷ String
147
- value =
148
- ( if encoding.omitEmptyArguments then Nothing
149
- else Just $ CA .encode CA .jarray []
150
- ) ∷ Maybe Json
151
151
in
152
- encodeTagged encoding name value
152
+ encodeCase encoding name []
153
153
154
154
gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name NoArguments )
155
155
gCasesDecode encoding _ json = do
156
- obj ← CA .decode jobject json ∷ _ (Object Json )
157
156
let name = reflectSymbol @name Proxy ∷ String
158
157
159
- checkTag encoding obj name
160
- parseNoFields encoding obj
158
+ parseNoFields encoding json name
161
159
pure $ Constructor NoArguments
162
160
163
161
else instance gCasesConstructorSingleArg ∷
@@ -170,20 +168,14 @@ else instance gCasesConstructorSingleArg ∷
170
168
let
171
169
codec = Record .get (Proxy @name) r ∷ JsonCodec a
172
170
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
177
171
in
178
- encodeTagged encoding name ( Just value)
172
+ encodeCase encoding name [ CA .encode codec x ]
179
173
180
174
gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name (Argument a ))
181
175
gCasesDecode encoding r json = do
182
- obj ← CA .decode jobject json ∷ _ (Object Json )
183
176
let name = reflectSymbol @name Proxy ∷ String
184
- checkTag encoding obj name
185
177
186
- field ← parseSingleField encoding obj ∷ _ Json
178
+ field ← parseSingleField encoding json name ∷ _ Json
187
179
let codec = Record .get (Proxy @name) r ∷ JsonCodec a
188
180
result ← CA .decode codec field ∷ _ a
189
181
pure $ Constructor (Argument result)
@@ -200,17 +192,14 @@ else instance gCasesConstructorManyArgs ∷
200
192
codecs = Record .get (Proxy @name) r ∷ codecs
201
193
name = reflectSymbol @name Proxy ∷ String
202
194
jsons = gFieldsEncode encoding codecs rep ∷ Array Json
203
- value = CA .encode CA .jarray jsons ∷ Json
204
195
in
205
- encodeTagged encoding name ( Just value)
196
+ encodeCase encoding name jsons
206
197
207
198
gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name args )
208
199
gCasesDecode encoding r json = do
209
- obj ← CA .decode jobject json ∷ _ (Object Json )
210
200
let name = reflectSymbol @name Proxy ∷ String
211
- checkTag encoding obj name
212
201
213
- jsons ← parseManyFields encoding obj ∷ _ (Array Json )
202
+ jsons ← parseManyFields encoding json name ∷ _ (Array Json )
214
203
let codecs = Record .get (Proxy @name) r ∷ codecs
215
204
result ← gFieldsDecode encoding codecs jsons ∷ _ args
216
205
pure $ Constructor result
@@ -292,58 +281,79 @@ instance gFieldsProduct ∷
292
281
293
282
-- ------------------------------------------------------------------------------
294
283
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
297
286
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 <> " `" ))
300
289
) ∷ _ Json
301
290
tag ← CA .decode CA .string val ∷ _ String
302
291
unless (tag == expectedTag)
303
292
$ throwError
304
293
$ TypeMismatch (" Expecting tag `" <> expectedTag <> " `, got `" <> tag <> " `" )
305
294
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
323
301
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 <> " `" ))
326
304
) ∷ _ 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