-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClass.hs
668 lines (608 loc) · 25.2 KB
/
Class.hs
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
{-# LANGUAGE DefaultSignatures, FlexibleContexts, FlexibleInstances #-}
{-# LANGUAGE EmptyCase #-}
-- | Definition for ron conversion classes, and for using 'GHC.Generics' to
-- encode any datatype into RON.
module Data.Ron.Class
( ToRon (..), FromRon (..)
, ParseResult
-- * Settings for generic encoding
, RonSettings (..)
, RonFlags (..)
, strictRonSettings, laxRonSettings
-- * Generic encoding
, toRonGeneric
, fromRonGeneric
, GToRon, GFromRon
) where
import Control.Applicative (liftA2)
import Control.Arrow ((***))
import Data.ByteString (ByteString)
import Data.Complex (Complex ((:+)))
import Data.Foldable (toList)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.Map.Strict (Map)
import Data.Proxy (Proxy (..))
import Data.Ron.Class.Internal (productSize, ProductSize)
import Data.Scientific (fromFloatDigits, toRealFloat, Scientific)
import Data.Text (Text, pack, unpack)
import Data.Text.Encoding (encodeUtf8)
import Data.Vector (Vector)
import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Generics
( Generic (Rep, from, to), V1, U1 (..), (:+:)(..), (:*:)(..)
, K1 (..), M1 (..)
, C, S, D, R
, Constructor (conName, conIsRecord), Selector (selName), Datatype (datatypeName)
)
import qualified Data.ByteString as BS
import qualified Data.Map.Strict as Map
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import qualified Data.Vector as Vector
import Data.Ron.Value
import Prelude hiding (fail)
-- | When decoding from ron, this type is used to indicate decode failure.
-- During decoding, multiple failures may be concatenated with a semicolon, and
-- for some functions the string will be thrown with
-- 'Data.Ron.Deserialize.DecodeError'. When implementing your own decoding
-- functions, you should put short one-sentence error descriptions.
--
-- For the next major release, we plan to replace it with a better mechanism
-- that reports error locations and supports long-form content.
type ParseResult = Either String
fail :: String -> ParseResult a
fail = Left
guard :: String -> Bool -> ParseResult ()
guard _ True = pure ()
guard msg False = fail msg
-- | Like 'Control.Applicative.(<|>)' but collect errors from both sides
(<<|>>) :: ParseResult a -> ParseResult a -> ParseResult a
pa <<|>> pb = case pa of
Right a -> pure a
Left ea -> case pb of
Right b -> pure b
Left eb -> fail $ ea <> "; "<> eb
-- | A class of values that can be encoded to RON format.
--
-- There are several ways to define an instance:
--
-- 1. By producing a 'Value' by hand
-- 2. By using 'toRonGeneric'
-- 3. By @DerivingVia@ extension and using 'Data.Ron.Class.Deriving.RonWith'
--
-- When using the second option, the encoding parameters are specified with
-- 'RonSettings'. With the third option, the same parameters are specified by a
-- list of settings found in 'Data.Ron.Class.Deriving'.
--
-- The default implementation uses generic encoding with 'laxRonSettings'. You
-- can use other settings like this:
--
-- @
-- instance ToRon MyType where
-- toRon = toRonGeneric strictRonSettings
-- { encodeFlags = RonFlags
-- { implicitSome = True
-- , skipSingleConstructor = True
-- }
-- }
-- @
--
-- Or like this:
--
-- @
-- deriving via (RonWith '[UseStrict, EncodeWith SkipSingleConstructor, EncodeWith ImplicitSome])
-- instance ToRon MyType
-- @
class ToRon a where
toRon :: a -> Value
default toRon :: (Generic a, GToRon (Rep a)) => a -> Value
toRon = toRonDefault
-- | A class of values that can be restored from RON format
--
-- There are several ways to define an instance:
--
-- 1. By deconstructing a 'Value' by hand and producing a value of your type
-- 2. By using 'fromRonGeneric'
-- 3. By @DerivingVia@ extension and using 'Data.Ron.Class.Deriving.RonWith'
--
-- The default implementation uses generic decoding with 'laxRonSettings'. You
-- can use other settings like this:
--
-- @
-- instance FromRon MyType where
-- fromRon = fromRonGeneric strictRonSettings
-- { decodeFlags = RonFlags
-- { implicitSome = True
-- , skipSingleConstructor = True
-- }
-- }
-- @
--
-- Or like this:
--
-- @
-- deriving via (RonWith '[UseStrict, DecodeWith SkipSingleConstructor, DecodeWith ImplicitSome])
-- instance FromRon MyType
-- @
class FromRon a where
fromRon :: Value -> ParseResult a
default fromRon :: (Generic a, GFromRon (Rep a)) => Value -> ParseResult a
fromRon = fromRonDefault
intInRange :: forall a. (Bounded a, Num a, Integral a) => Integer -> ParseResult a
intInRange i
| i >= minVal && i <= maxVal = pure . fromInteger $ i
| otherwise = fail $ "Value " <> show i <> " is not in valid range"
where
minVal = toInteger (minBound @a)
maxVal = toInteger (maxBound @a)
instance ToRon Int where
toRon = Integral . toInteger
instance FromRon Int where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Int8 where
toRon = Integral . toInteger
instance FromRon Int8 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Int16 where
toRon = Integral . toInteger
instance FromRon Int16 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Int32 where
toRon = Integral . toInteger
instance FromRon Int32 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Int64 where
toRon = Integral . toInteger
instance FromRon Int64 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Word where
toRon = Integral . toInteger
instance FromRon Word where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Word8 where
toRon = Integral . toInteger
instance FromRon Word8 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Word16 where
toRon = Integral . toInteger
instance FromRon Word16 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Word32 where
toRon = Integral . toInteger
instance FromRon Word32 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Word64 where
toRon = Integral . toInteger
instance FromRon Word64 where
fromRon (Integral i) = intInRange i
fromRon _ = fail "Not an integer"
instance ToRon Integer where
toRon = Integral
instance FromRon Integer where
fromRon (Integral i) = pure i
fromRon _ = fail "Not an integer"
instance ToRon Scientific where
toRon = Floating
instance FromRon Scientific where
fromRon (Integral x) = pure . fromInteger $ x
fromRon (Floating x) = pure x
fromRon _ = fail "Not a floating"
instance ToRon Double where
toRon x
| isNaN x = Unit "NaN"
| isInfinite x = Unit "inf"
| otherwise = Floating . fromFloatDigits $ x
instance FromRon Double where
fromRon (Integral x) = pure . fromInteger $ x
fromRon (Floating x) = pure . toRealFloat $ x
fromRon (Unit "inf") = pure $! read "Infinity"
fromRon (Unit "NaN") = pure $! read "NaN"
fromRon _ = fail "Not a floating"
instance ToRon Float where
toRon x
| isNaN x = Unit "NaN"
| isInfinite x = Unit "inf"
| otherwise = Floating . fromFloatDigits $ x
instance FromRon Float where
fromRon (Integral x) = pure . fromInteger $ x
fromRon (Floating x) = pure . toRealFloat $ x
fromRon (Unit "inf") = pure $! read "Infinity"
fromRon (Unit "NaN") = pure $! read "NaN"
fromRon _ = fail "Not a floating"
instance (ToRon a) => ToRon (Complex a) where
toRon (r :+ im) = Tuple "Complex" (Vector.fromList [toRon r, toRon im])
instance (Num a, FromRon a) => FromRon (Complex a) where
fromRon v@(Integral _) = (:+ 0) <$> fromRon v
fromRon v@(Floating _) = (:+ 0) <$> fromRon v
fromRon (Tuple name vals) = do
guard "Incorrect Complex tuple name" $ name == "" || name == "Complex"
case Vector.toList vals of
[r, im] -> liftA2 (:+) (fromRon r) (fromRon im)
_ -> fail "Incorrect amount of values in complex coordinates"
fromRon _ = fail "Incorrect Complex value"
instance ToRon Char where
toRon = Char
instance FromRon Char where
fromRon (Char x) = pure x
fromRon _ = fail "Expected Char"
instance ToRon Text where
toRon = String
instance FromRon Text where
fromRon (String x) = pure x
fromRon _ = fail "Not text"
instance ToRon ByteString where
toRon = List . Vector.fromList . map (Integral . toInteger) . BS.unpack
instance FromRon ByteString where
fromRon (List bytes) = fmap BS.pack . traverse asWord8 . Vector.toList $ bytes
where
asWord8 (Integral x) = intInRange x
asWord8 _ = fail "Not a byte in list"
fromRon (String s) = pure . encodeUtf8 $ s
fromRon _ = fail "Not a bytestring"
instance ToRon Bool where
toRon True = Unit "true"
toRon False = Unit "false"
instance FromRon Bool where
fromRon (Unit name)
| name == "True" || name == "true" = pure True
| name == "False" || name == "false" = pure False
| otherwise = fail $ "Invalid enum value: " <> show name
fromRon _ = fail "Not a boolean"
instance (ToRon a) => ToRon (Vector.Vector a) where
toRon = List . Vector.map toRon
instance (FromRon a) => FromRon (Vector.Vector a) where
fromRon (List xs) = traverse fromRon xs
fromRon _ = fail "Not a list"
instance (ToRon a) => ToRon [a] where
toRon = List . Vector.fromList . map toRon
instance (FromRon a) => FromRon [a] where
fromRon (List xs) = Vector.toList <$> traverse fromRon xs
fromRon _ = fail "Not a list"
instance {-# OVERLAPPING #-} ToRon [Char] where
toRon = String . pack
instance {-# OVERLAPPING #-} FromRon [Char] where
fromRon = fmap unpack . fromRon
instance (ToRon a) => ToRon (NonEmpty a) where
toRon (x:|xs) = toRon $ x:xs
instance (FromRon a) => FromRon (NonEmpty a) where
fromRon v = fromRon v >>= \case
[] -> fail "Expected non-empty list"
x:xs -> pure $ x:|xs
instance (ToRon k, ToRon v) => ToRon (Map.Map k v) where
toRon = Map . Map.fromList . map (toRon *** toRon) . Map.toAscList
instance (FromRon k, FromRon v, Ord k) => FromRon (Map.Map k v) where
fromRon (Map xs) = Map.fromList <$>
traverse tupleFromRon (Map.toAscList xs)
where tupleFromRon (a, b) = liftA2 (,) (fromRon a) (fromRon b)
fromRon _ = fail "Not a map"
instance (ToRon a) => ToRon (Set.Set a) where
toRon = toRon . Set.toAscList
instance (FromRon a, Ord a) => FromRon (Set.Set a) where
fromRon = fmap Set.fromList . fromRon
instance (ToRon a) => ToRon (Seq.Seq a) where
toRon = toRon . toList
instance (FromRon a) => FromRon (Seq.Seq a) where
fromRon = fmap Seq.fromList . fromRon
instance ToRon () where
toRon () = Unit ""
instance FromRon () where
fromRon (Unit name)
| name == "" = pure ()
| otherwise = fail "Not a unit enum value"
fromRon _ = fail "Not a unit"
instance (ToRon a) => ToRon (Maybe a) where
toRon (Just x) = Tuple "Some" (Vector.singleton $ toRon x)
toRon Nothing = Unit "None"
instance (FromRon a) => FromRon (Maybe a) where
fromRon (Tuple name xs)
| (name == "Just" || name == "Some") && Vector.length xs == 1
= Just <$> fromRon (Vector.unsafeHead xs)
| otherwise = fail "Not a Maybe enum"
fromRon (Unit name)
| name == "Nothing" || name == "None" = pure Nothing
| otherwise = fail $ "Incorrect Maybe name: " <> show name
fromRon _ = fail "Not a named tuple or unit"
instance (ToRon a, ToRon b) => ToRon (Either a b) where
toRon (Left x) = Tuple "Left" (Vector.singleton $ toRon x)
toRon (Right x) = Tuple "Right" (Vector.singleton $ toRon x)
instance (FromRon a, FromRon b) => FromRon (Either a b) where
fromRon (Tuple name xs)
| Vector.length xs == 1 =
if | name == "Left" -> Left <$> fromRon (Vector.unsafeHead xs)
| name == "Right" -> Right <$> fromRon (Vector.unsafeHead xs)
| otherwise -> fail "Not an Either enum"
| otherwise = fail "Incorrect amount of arguments to Either"
fromRon _ = fail "Not an Either value"
instance (ToRon a1, ToRon a2) => ToRon (a1, a2) where
toRon (a1, a2) = Tuple "" . Vector.fromList $ [toRon a1, toRon a2]
instance (FromRon a1, FromRon a2) => FromRon (a1, a2) where
fromRon (Tuple name xs)
| name == "" = case Vector.toList xs of
[a1, a2] -> liftA2 (,) (fromRon a1) (fromRon a2)
_ -> fail "Incorrect amount of tuple values"
| otherwise = fail "Incorrect tuple name"
fromRon _ = fail "Not a tuple"
--- Generic instance
-- | Part of 'RonSettings' that applies to both encoding and decoding, and
-- separately
data RonFlags = RonFlags
{ implicitSome :: !Bool
-- ^ Like ron-rs's @implicit_some@. When set to True, 'Nothing' in record
-- fields is represented by omission of the field
, skipSingleConstructor :: !Bool
-- ^ When a datatype has a single constructor, encoding will omit it and
-- decoding will ignore it missing, turning the representation into a tuple
-- or an anonymous record.
} deriving (Eq, Show)
-- | Settings for use with 'Generic' RON encoding/decoding
data RonSettings = RonSettings
{ fieldModifier :: !(String -> String)
-- ^ Every field will be renamed using the supplied function
, constructorModifier :: !(String -> String)
-- ^ Every constructor will be renamed using the supplied function
, decodeFlags :: !RonFlags
-- ^ Options that apply to encoding separately from decoding
, encodeFlags :: !RonFlags
-- ^ Options that apply to decoding separately from encoding
}
data SumContext = SumContext
{ isSingleConstructor :: Bool
, sumTypeName :: String
} deriving (Eq, Show)
data ProductContext = ProductContext
{ prodTypeName :: String
, constructorName :: String
} deriving (Eq, Show)
-- | Encode ron using 'Generic' instance and provided 'RonSettings'.
--
-- With generic encoding sums are turned into sums, records into records, and
-- multi-param constructors into tuples.
toRonGeneric :: (Generic a, GToRon (Rep a)) => RonSettings -> a -> Value
toRonGeneric conf = toRonG conf . from
-- | Values are expected to exactly conform: all fields should have the same
-- name, all constructors should be present, no @Some@ omission
strictRonSettings :: RonSettings
strictRonSettings = RonSettings
{ fieldModifier = id
, constructorModifier = id
, decodeFlags = RonFlags
{ implicitSome = False
, skipSingleConstructor = False
}
, encodeFlags = RonFlags
{ implicitSome = False
, skipSingleConstructor = False
}
}
-- | Relaxes 'strictRonSettings' on constructor omission and implicitSome when
-- decoding, but encodes in the same strict way
laxRonSettings :: RonSettings
laxRonSettings = RonSettings
{ fieldModifier = id
, constructorModifier = id
, decodeFlags = RonFlags
{ implicitSome = True
, skipSingleConstructor = True
}
, encodeFlags = RonFlags
{ implicitSome = False
, skipSingleConstructor = False
}
}
toRonDefault :: (Generic a, GToRon (Rep a)) => a -> Value
toRonDefault = toRonGeneric laxRonSettings
-- | Internal class for converting to Ron. You might need it if you're writing
-- you own generic combinators
class GToRon f where
toRonG :: RonSettings -> f a -> Value
class GToRonSum f where
toRonSum :: RonSettings -> SumContext -> f a -> Value
class GToRonProduct f where
toRonProduct
:: RonSettings -> ProductContext -> f a -> Either (Vector Value) (Map Text Value)
class GToRonRec f where
toRonRec :: RonSettings -> f a -> Value
instance (Datatype d, GToRonSum f) => GToRon (M1 D d f) where
toRonG conf (M1 x) = toRonSum conf cont x
where cont = SumContext
{ isSingleConstructor = True
, sumTypeName = datatypeName (undefined :: t d f a)
}
instance GToRonSum V1 where
toRonSum _ _ x = case x of {}
instance (Constructor c, GToRonProduct f) => GToRonSum (M1 C c f) where
toRonSum conf cont (M1 x) =
let con = undefined :: t c f a
name = if isSingleConstructor cont
&& skipSingleConstructor (encodeFlags conf)
then ""
else pack . conName $ con
cont' = ProductContext
{ prodTypeName = sumTypeName cont
, constructorName = unpack name
}
xs = toRonProduct conf cont' x
in case (xs, conIsRecord con) of
(Right xs', True) -> Record name xs'
(Left xs', False) -> Tuple name xs'
(Right xs', _) | null xs' -> Unit name
(Left xs', _) | Vector.null xs' -> Unit name
_ -> error $ "Bad product: " <> take 128 (show xs)
instance (GToRonSum fl, GToRonSum fr) => GToRonSum (fl :+: fr) where
toRonSum conf cont (L1 x) = toRonSum conf cont' x
where cont' = cont
{isSingleConstructor = False}
toRonSum conf cont (R1 x) = toRonSum conf cont' x
where cont' = cont
{isSingleConstructor = False}
instance GToRonProduct U1 where
toRonProduct _ _ U1 = Left Vector.empty
instance {-# OVERLAPPING #-} (Selector s, ToRon c)
=> GToRonProduct (M1 S s (K1 R (Maybe c))) where
toRonProduct conf _cont (M1 (K1 x)) =
let field = selName (undefined :: t s (K1 R (Maybe c)) a)
in case x of
Nothing | implicitSome . encodeFlags $ conf ->
if null field
then Left . Vector.singleton . toRon $ Nothing @()
else Right Map.empty
Just x' | implicitSome . encodeFlags $ conf ->
if null field
then Left . Vector.singleton . toRon $ x'
else
let field' = pack $ fieldModifier conf field
value = toRon x'
in Right $ Map.singleton field' value
x'
| null field -> Left . Vector.singleton . toRon $ x'
| otherwise ->
let field' = pack $ fieldModifier conf field
in Right . Map.singleton field' $ toRon x'
instance (Selector s, GToRonRec f) => GToRonProduct (M1 S s f) where
toRonProduct conf _cont (M1 x) =
let field = selName (undefined :: t s f a)
value = toRonRec conf x
in case field of
"" -> Left . Vector.singleton $ value
_field ->
let field' = pack $ fieldModifier conf field
in Right $ Map.singleton field' value
instance (GToRonProduct pl, GToRonProduct pr)
=> GToRonProduct (pl :*: pr) where
toRonProduct conf cont (x :*: y) =
case (toRonProduct conf cont x, toRonProduct conf cont y) of
(Left xs, Left ys) -> Left $ xs <> ys
(Right xs, Right ys) -> Right $ Map.union xs ys
_ -> error "Incompatible product branches"
instance ToRon c => GToRonRec (K1 R c) where
toRonRec _ (K1 x) = toRon x
-- | Decode ron using 'Generic' instance and provided 'RonSettings'
--
-- With generic encoding sums are turned into sums, records into records, and
-- multi-param constructors into tuples.
fromRonGeneric
:: (Generic a, GFromRon (Rep a)) => RonSettings -> Value -> ParseResult a
fromRonGeneric conf = fmap to . fromRonG conf
fromRonDefault :: (Generic a, GFromRon (Rep a)) => Value -> ParseResult a
fromRonDefault = fromRonGeneric laxRonSettings
-- | Internal class for converting from Ron. You might need it if you're
-- writing you own generic combinators
class GFromRon f where
fromRonG :: RonSettings -> Value -> ParseResult (f a)
class GFromRonSum f where
fromRonSum :: RonSettings -> SumContext -> Value -> ParseResult (f a)
class GFromRonProduct f where
fromRonProduct
:: RonSettings
-> ProductContext
-> Either (Vector Value) (Map Text Value)
-> ParseResult (f a)
class GFromRonRec f where
fromRonRec :: RonSettings -> Value -> ParseResult (f a)
instance (Datatype d, GFromRonSum f) => GFromRon (M1 D d f) where
fromRonG conf x = M1 <$> fromRonSum conf cont x
where cont = SumContext
{ isSingleConstructor = True
, sumTypeName = datatypeName (undefined :: t d f a)
}
instance (Constructor c, GFromRonProduct f) => GFromRonSum (M1 C c f) where
fromRonSum conf cont x =
M1 <$> case x of
Unit n | name `matches` n
-> fromRonProduct conf cont' $ Left Vector.empty
| otherwise -> fail incorrectConstructor
Tuple n xs | name `matches` n -> fromRonProduct conf cont' $ Left xs
| otherwise -> fail incorrectConstructor
Record n xs | name `matches` n -> fromRonProduct conf cont' $ Right xs
| otherwise -> fail incorrectConstructor
_ -> fail $ "Incorrect value for type " <> sumTypeName cont
where
con = undefined :: t c f a
name = pack . conName $ con
matches target ron =
ron == target
|| ron == ""
&& isSingleConstructor cont
&& skipSingleConstructor (decodeFlags conf)
incorrectConstructor = "Incorrect constructor " <> constructorName <> " for type " <> sumTypeName cont
constructorName = case unpack name of
"" -> "<UNNAMED>"
n -> n
cont' = ProductContext
{ prodTypeName = sumTypeName cont
, constructorName
}
instance (GFromRonSum fl, GFromRonSum fr) => GFromRonSum (fl :+: fr) where
fromRonSum conf cont x =
(L1 <$> fromRonSum conf cont' x) <<|>> (R1 <$> fromRonSum conf cont' x)
where cont' = cont
{ isSingleConstructor = False }
instance GFromRonProduct U1 where
fromRonProduct _ _ (Left xs) | Vector.null xs = pure U1
fromRonProduct _ _ (Right xs) | Map.null xs = pure U1
fromRonProduct _ c _ = fail $ constructorName c <> ": expected empty structure"
instance {-# OVERLAPPING #-} (Selector s, FromRon c)
=> GFromRonProduct (M1 S s (K1 R (Maybe c))) where
fromRonProduct conf cont xs =
let field =
pack . fieldModifier conf $
selName (undefined :: t s (K1 R (Maybe c)) a)
ProductContext {constructorName} = cont
in case xs of
Left xs' -> case Vector.uncons xs' of
Nothing -> fail $ "Not enough elements in tuple " <> constructorName
Just (x, xs'')
| Vector.null xs'' -> M1 <$>
let tryUnwrapped
| implicitSome . decodeFlags $ conf =
K1 . Just <$> fromRon x
| otherwise =
fail $ constructorName <> ": not using decodeImplicitSome"
in fromRonRec conf x <<|>> tryUnwrapped
| otherwise -> fail $ "Trailing members in tuple " <> constructorName
Right xs'
| implicitSome . decodeFlags $ conf ->
case Map.lookup field xs' of
Nothing -> pure . M1 . K1 $ Nothing
Just x ->
let unwrapped = M1 . K1 . Just <$> fromRon x
wrapped = M1 <$> fromRonRec conf x
in wrapped <<|>> unwrapped
| otherwise -> case Map.lookup field xs' of
Nothing -> fail $ "Field " <> unpack field <> " not present in record " <> constructorName
Just x -> M1 <$> fromRonRec conf x
instance (Selector s, GFromRonRec f) => GFromRonProduct (M1 S s f) where
fromRonProduct conf cont xs =
let field = pack . fieldModifier conf $ selName (undefined :: t s f a)
ProductContext {constructorName} = cont
in case xs of
Left xs' -> case Vector.uncons xs' of
Nothing -> fail $ "Not enough elements in tuple " <> constructorName
Just (x, xs'') | Vector.null xs'' -> M1 <$> fromRonRec conf x
| otherwise -> fail $ "Trailing members in tuple " <> constructorName
Right xs' -> case Map.lookup field xs' of
Nothing -> fail $ "Field " <> unpack field <> " not present in record " <> constructorName
Just x -> M1 <$> fromRonRec conf x
instance (ProductSize pl, GFromRonProduct pl, GFromRonProduct pr)
=> GFromRonProduct (pl :*: pr) where
fromRonProduct conf cont (Left xs) =
let sizel = productSize (Proxy @pl)
(xsl, xsr) = Vector.splitAt sizel xs
in (:*:)
<$> fromRonProduct conf cont (Left xsl)
<*> fromRonProduct conf cont (Left xsr)
fromRonProduct conf cont xs = (:*:)
<$> fromRonProduct conf cont xs
<*> fromRonProduct conf cont xs
instance FromRon c => GFromRonRec (K1 R c) where
fromRonRec _ x = K1 <$> fromRon x