/
TaggedSumRep.purs
131 lines (115 loc) · 4.6 KB
/
TaggedSumRep.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
module Yoga.JSON.Generics.TaggedSumRep where
import Prelude
import Control.Alt ((<|>))
import Control.Monad.Except (withExcept)
import Data.Generic.Rep (NoArguments)
import Data.Generic.Rep as GR
import Data.Maybe (maybe)
import Data.Tuple.Nested ((/\))
import Foreign (Foreign, ForeignError(..), fail)
import Foreign as Foreign
import Foreign.Object (Object)
import Foreign.Object as Object
import Type.Prelude (class IsSymbol, Proxy(..), reflectSymbol)
import Yoga.JSON (undefined)
import Yoga.JSON as JSON
type Options =
{ typeTag ∷ String, valueTag ∷ String, toConstructorName ∷ String → String }
defaultOptions ∷ Options
defaultOptions = { typeTag: "type", valueTag: "value", toConstructorName: identity }
genericReadForeignTaggedSum ∷
∀ a rep.
GR.Generic a rep ⇒
ReadGenericTaggedSumRep rep ⇒
Options →
Foreign →
Foreign.F a
genericReadForeignTaggedSum options f =
GR.to <$> genericReadForeignTaggedSumRep options f
-- | Generic Tagged Sum Representations, tagged with a "type" field
class ReadGenericTaggedSumRep rep where
genericReadForeignTaggedSumRep ∷ Options → Foreign → Foreign.F rep
instance
( ReadGenericTaggedSumRep a
, ReadGenericTaggedSumRep b
) ⇒
ReadGenericTaggedSumRep (GR.Sum a b) where
genericReadForeignTaggedSumRep options f = GR.Inl <$> genericReadForeignTaggedSumRep options f
<|> GR.Inr <$> genericReadForeignTaggedSumRep options f
else instance
( IsSymbol name
) ⇒
ReadGenericTaggedSumRep (GR.Constructor name NoArguments) where
genericReadForeignTaggedSumRep { typeTag, toConstructorName } f = do
o ∷ Object Foreign ← JSON.read' f
typeFgn ← maybe (fail ((ErrorAtProperty typeTag) (ForeignError ("Missing type tag: " <> typeTag)))) pure (Object.lookup typeTag o)
typeStr ← JSON.read' typeFgn
if typeStr == name then withExcept (map $ ErrorAtProperty name) $
pure (GR.Constructor GR.NoArguments)
else
fail $ ForeignError $ "Wrong type tag " <> typeStr <> " where " <> typeTag
<> " was expected."
where
nameP = Proxy ∷ Proxy name
name = toConstructorName (reflectSymbol nameP)
else instance
( ReadGenericTaggedSumRep a
, IsSymbol name
) ⇒
ReadGenericTaggedSumRep (GR.Constructor name a) where
genericReadForeignTaggedSumRep options@{ typeTag, valueTag, toConstructorName } f = do
o ∷ Object Foreign ← JSON.read' f
typeFgn ← maybe (fail ((ErrorAtProperty typeTag) (ForeignError ("Missing type tag: " <> typeTag)))) pure (Object.lookup typeTag o)
typeStr ← JSON.read' typeFgn
value ← maybe (fail ((ErrorAtProperty valueTag) (ForeignError ("Missing value tag: " <> valueTag)))) pure (Object.lookup valueTag o)
if typeStr == name then withExcept (map $ ErrorAtProperty name) $
GR.Constructor <$> genericReadForeignTaggedSumRep options value
else
fail $ ForeignError $ "Wrong constructor name tag " <> typeStr <> " where " <> name
<> " was expected."
where
nameP = Proxy ∷ Proxy name
name = toConstructorName (reflectSymbol nameP)
instance (JSON.ReadForeign a) ⇒ ReadGenericTaggedSumRep (GR.Argument a) where
genericReadForeignTaggedSumRep _ f = GR.Argument <$> JSON.readImpl f
-- Write
genericWriteForeignTaggedSum ∷
∀ a rep.
GR.Generic a rep ⇒
WriteGenericTaggedSumRep rep ⇒
Options →
a →
Foreign
genericWriteForeignTaggedSum options r =
genericWriteForeignTaggedSumRep options (GR.from r)
-- | Generic Tagged Sum Representations, tagged with a "type" field
class WriteGenericTaggedSumRep rep where
genericWriteForeignTaggedSumRep ∷ Options → rep → Foreign
instance
( WriteGenericTaggedSumRep a
, WriteGenericTaggedSumRep b
) ⇒
WriteGenericTaggedSumRep (GR.Sum a b) where
genericWriteForeignTaggedSumRep options = case _ of
GR.Inl a → genericWriteForeignTaggedSumRep options a
GR.Inr b → genericWriteForeignTaggedSumRep options b
instance
( WriteGenericTaggedSumRep a
, IsSymbol name
) ⇒
WriteGenericTaggedSumRep (GR.Constructor name a) where
genericWriteForeignTaggedSumRep options@{ typeTag, valueTag, toConstructorName } (GR.Constructor a) = do
JSON.write
( Object.fromFoldable
[ typeTag /\ JSON.write name
, valueTag /\ genericWriteForeignTaggedSumRep options a
]
)
where
nameP = Proxy ∷ Proxy name
name = toConstructorName (reflectSymbol nameP)
instance (JSON.WriteForeign a) ⇒ WriteGenericTaggedSumRep (GR.Argument a) where
genericWriteForeignTaggedSumRep _ (GR.Argument a) = JSON.writeImpl a
instance
WriteGenericTaggedSumRep GR.NoArguments where
genericWriteForeignTaggedSumRep _ GR.NoArguments = undefined