on master help sign in
Generics and TH support for lifted typeclasses
commit7cb9ac84da8fba61ef89a3759b84160cd0a333f3 authorRyan Scott <ryan.gl.scott@gmail.com> dateThu 24 Mar 2016, 15:35 (11 years ago) parent88a4dd9
7 files changed+1949−669
Data/Aeson.hs+5 Data/Aeson/TH.hs+1184−281 Data/Aeson/Types.hs+5 Data/Aeson/Types/Class.hs+16−2 Data/Aeson/Types/FromJSON.hs+249−122 Data/Aeson/Types/Generic.hs+21 Data/Aeson/Types/ToJSON.hs+469−264
Data/Aeson.hs+5
@@ -77,9 +77,14 @@ module Data.Aeson
7777 , GFromJSON(..)
7878 , GToJSON(..)
7979 , GToEncoding(..)
80+ , Zero
81+ , One
8082 , genericToJSON
83+ , genericLiftToJSON
8184 , genericToEncoding
85+ , genericLiftToEncoding
8286 , genericParseJSON
87+ , genericLiftParseJSON
8388 , defaultOptions
8489
8590 -- * Inspecting @'Value's@
Data/Aeson/TH.hs+1184−281
@@ -1,5 +1,9 @@
1−{-# LANGUAGE CPP, FlexibleInstances, NamedFieldPuns,
2− NoImplicitPrelude, UndecidableInstances #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE NamedFieldPuns #-}
5+{-# LANGUAGE NoImplicitPrelude #-}
6+{-# LANGUAGE UndecidableInstances #-}
37#if __GLASGOW_HASKELL__ >= 800
48-- a) THQ works on cross-compilers and unregisterised GHCs
59-- b) may make compilation faster as no dynamic loading is ever needed (not sure about this)
@@ -87,19 +91,32 @@ module Data.Aeson.TH
8791
8892 -- * FromJSON and ToJSON derivation
8993 , deriveJSON
94+ , deriveJSON1
95+ , deriveJSON2
9096
9197 , deriveToJSON
98+ , deriveToJSON1
99+ , deriveToJSON2
92100 , deriveFromJSON
101+ , deriveFromJSON1
102+ , deriveFromJSON2
93103
94104 , mkToJSON
105+ , mkLiftToJSON
106+ , mkLiftToJSON2
95107 , mkToEncoding
108+ , mkLiftToEncoding
109+ , mkLiftToEncoding2
96110 , mkParseJSON
111+ , mkLiftParseJSON
112+ , mkLiftParseJSON2
97113 ) where
98114
99115import Control.Applicative ( pure, (<$>), (<*>) )
100−import Data.Aeson ( toJSON, Object, (.=), (.:), (.:?)
101− , ToJSON, toEncoding, toJSON
102− , FromJSON, parseJSON
116+import Data.Aeson ( Object, (.=), (.:)
117+ , ToJSON(..), FromJSON(..)
118+ , ToJSON1(..), FromJSON1(..)
119+ , ToJSON2(..), FromJSON2(..)
103120 )
104121import Data.Aeson.Types ( Value(..), Parser
105122 , Options(..)
@@ -107,32 +124,42 @@ import Data.Aeson.Types ( Value(..), Parser
107124 , defaultOptions
108125 , defaultTaggedObject
109126 )
110−import Data.Aeson.Types.Internal ((<?>), JSONPathElement(Key))
111−import Control.Monad ( liftM2, return, mapM, fail )
127+import Data.Aeson.Types.Internal (Pair, (<?>), JSONPathElement(Key))
128+import Data.Aeson.Types.FromJSON (parseOptionalFieldWith)
129+import Control.Monad ( fail, liftM2, mapM, return, unless, when )
112130import Data.Bool ( Bool(False, True), otherwise, (&&), not )
113131import Data.Either ( Either(Left, Right) )
114132import Data.Eq ( (==) )
133+import Data.Foldable ( concatMap, foldr' )
115134import Data.Function ( ($), (.), flip )
116135import Data.Functor ( fmap )
117136import Data.Int ( Int )
118137import Data.List ( (++), all, any, find, foldl, foldl'
119138 , genericLength , intercalate , intersperse, length, map
120− , partition, zip
139+ , partition, union, zip, zip3
121140 )
141+import Data.List.NonEmpty ( NonEmpty((:|)), (<|) )
122142import Data.Map ( Map )
123−import Data.Maybe ( Maybe(Nothing, Just), catMaybes )
143+import Data.Maybe ( Maybe(Nothing, Just), catMaybes, fromMaybe, mapMaybe )
124144import Data.Monoid ( (<>), mconcat )
145+import Data.Set ( Set )
125146import Language.Haskell.TH
147+#if MIN_VERSION_template_haskell(2,8,0)
148+ hiding ( Arity )
149+#endif
126150import Language.Haskell.TH.Syntax ( VarStrictType )
127−import Prelude ( String, (-), Integer, error, foldr1, fromIntegral
128− , splitAt, zipWith
151+import Prelude ( Enum(..), Eq(..), Integer, Ord(..), String
152+ , concat, cycle, drop, elem, error, foldr1, fromIntegral
153+ , showChar, showParen, shows, showString, snd, splitAt
154+ , take, unzip, zipWith, (-), (||)
129155 )
156+#if MIN_VERSION_template_haskell(2,7,0) && !(MIN_VERSION_template_haskell(2,8,0))
157+import Language.Haskell.TH.Lib ( starK )
158+#endif
130159#if MIN_VERSION_template_haskell(2,8,0) && !(MIN_VERSION_template_haskell(2,10,0))
131−import Data.Foldable ( foldr' )
132−import qualified Data.Map as M ( singleton )
133160import Data.List ( nub )
134161import Language.Haskell.TH.Syntax ( mkNameG_tc )
135−import Prelude ( concatMap, uncurry )
162+import Prelude ( uncurry )
136163#endif
137164#if MIN_VERSION_template_haskell(2,11,0)
138165import Prelude ( head )
@@ -141,8 +168,13 @@ import Text.Printf ( printf )
141168import Text.Show ( show )
142169import qualified Data.Aeson as A
143170import qualified Data.Aeson.Encoding.Internal as E
171+import qualified Data.Foldable as F ( all )
144172import qualified Data.HashMap.Strict as H ( lookup, toList )
145−import qualified Data.Map as M ( fromList, findWithDefault )
173+import qualified Data.List.NonEmpty as NE ( drop, length, reverse, splitAt )
174+import qualified Data.Map as M ( fromList, findWithDefault, keys, lookup
175+ , singleton, size
176+ )
177+import qualified Data.Set as Set ( empty, insert, member )
146178import qualified Data.Text as T ( Text, pack, unpack )
147179import qualified Data.Vector as V ( unsafeIndex, null, length, create, fromList )
148180import qualified Data.Vector.Mutable as VM ( unsafeNew, unsafeWrite )
@@ -163,11 +195,33 @@ deriveJSON :: Options
163195 -- ^ Name of the type for which to generate 'ToJSON' and 'FromJSON'
164196 -- instances.
165197 -> Q [Dec]
166−deriveJSON opts name =
167− liftM2 (++)
168− (deriveToJSON opts name)
169− (deriveFromJSON opts name)
198+deriveJSON = deriveJSONBoth deriveToJSON deriveFromJSON
170199
200+-- | Generates both 'ToJSON1' and 'FromJSON1' instance declarations for the given
201+-- data type or data family instance constructor.
202+--
203+-- This is a convienience function which is equivalent to calling both
204+-- 'deriveToJSON1' and 'deriveFromJSON1'.
205+deriveJSON1 :: Options
206+ -- ^ Encoding options.
207+ -> Name
208+ -- ^ Name of the type for which to generate 'ToJSON1' and 'FromJSON1'
209+ -- instances.
210+ -> Q [Dec]
211+deriveJSON1 = deriveJSONBoth deriveToJSON1 deriveFromJSON1
212+
213+-- | Generates both 'ToJSON2' and 'FromJSON2' instance declarations for the given
214+-- data type or data family instance constructor.
215+--
216+-- This is a convienience function which is equivalent to calling both
217+-- 'deriveToJSON2' and 'deriveFromJSON2'.
218+deriveJSON2 :: Options
219+ -- ^ Encoding options.
220+ -> Name
221+ -- ^ Name of the type for which to generate 'ToJSON2' and 'FromJSON2'
222+ -- instances.
223+ -> Q [Dec]
224+deriveJSON2 = deriveJSONBoth deriveToJSON2 deriveFromJSON2
171225
172226--------------------------------------------------------------------------------
173227-- ToJSON
@@ -190,69 +244,130 @@ deriveToJSON :: Options
190244 -- ^ Name of the type for which to generate a 'ToJSON' instance
191245 -- declaration.
192246 -> Q [Dec]
193−deriveToJSON opts name =
194− withType name $ \name' tvbs cons mbTys -> fmap (:[]) $ fromCons name' tvbs cons mbTys
195− where
196− fromCons :: Name -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec
197− fromCons name' tvbs cons mbTys = do
198− (instanceCxt, instanceType) <- buildTypeInstance name' ''ToJSON tvbs mbTys
199− instanceD (return instanceCxt)
200− (return instanceType)
201− [ funD 'toJSON
202− [ clause []
203− (normalB $ consToValue opts cons)
204− []
205− ]
206− , funD 'toEncoding
207− [ clause []
208− (normalB $ consToEncoding opts cons)
209− []
210− ]
211− ]
247+deriveToJSON = deriveToJSONCommon toJSONClass
248+
249+-- | Generates a 'ToJSON1' instance declaration for the given data type or
250+-- data family instance constructor.
251+deriveToJSON1 :: Options
252+ -- ^ Encoding options.
253+ -> Name
254+ -- ^ Name of the type for which to generate a 'ToJSON1' instance
255+ -- declaration.
256+ -> Q [Dec]
257+deriveToJSON1 = deriveToJSONCommon toJSON1Class
258+
259+-- | Generates a 'ToJSON2' instance declaration for the given data type or
260+-- data family instance constructor.
261+deriveToJSON2 :: Options
262+ -- ^ Encoding options.
263+ -> Name
264+ -- ^ Name of the type for which to generate a 'ToJSON2' instance
265+ -- declaration.
266+ -> Q [Dec]
267+deriveToJSON2 = deriveToJSONCommon toJSON2Class
268+
269+deriveToJSONCommon :: JSONClass
270+ -- ^ The ToJSON variant being derived.
271+ -> Options
272+ -- ^ Encoding options.
273+ -> Name
274+ -- ^ Name of the type for which to generate an instance.
275+ -> Q [Dec]
276+deriveToJSONCommon = deriveJSONClass [ (ToJSON, \jc _ -> consToValue jc)
277+ , (ToEncoding, \jc _ -> consToEncoding jc)
278+ ]
212279
213280-- | Generates a lambda expression which encodes the given data type or
214281-- data family instance constructor as a 'Value'.
215282mkToJSON :: Options -- ^ Encoding options.
216283 -> Name -- ^ Name of the type to encode.
217284 -> Q Exp
218−mkToJSON opts name = withType name (\_ _ cons _ -> consToValue opts cons)
285+mkToJSON = mkToJSONCommon toJSONClass
286+
287+-- | Generates a lambda expression which encodes the given data type or
288+-- data family instance constructor as a 'Value' by using the given encoding
289+-- function on occurrences of the last type parameter.
290+mkLiftToJSON :: Options -- ^ Encoding options.
291+ -> Name -- ^ Name of the type to encode.
292+ -> Q Exp
293+mkLiftToJSON = mkToJSONCommon toJSON1Class
294+
295+-- | Generates a lambda expression which encodes the given data type or
296+-- data family instance constructor as a 'Value' by using the given encoding
297+-- functions on occurrences of the last two type parameters.
298+mkLiftToJSON2 :: Options -- ^ Encoding options.
299+ -> Name -- ^ Name of the type to encode.
300+ -> Q Exp
301+mkLiftToJSON2 = mkToJSONCommon toJSON2Class
302+
303+mkToJSONCommon :: JSONClass -- ^ Which class's method is being derived.
304+ -> Options -- ^ Encoding options.
305+ -> Name -- ^ Name of the encoded type.
306+ -> Q Exp
307+mkToJSONCommon = mkFunCommon (\jc _ -> consToValue jc)
219308
220309-- | Generates a lambda expression which encodes the given data type or
221310-- data family instance constructor as a JSON string.
222311mkToEncoding :: Options -- ^ Encoding options.
223312 -> Name -- ^ Name of the type to encode.
224313 -> Q Exp
225−mkToEncoding opts name = withType name (\_ _ cons _ -> consToEncoding opts cons)
314+mkToEncoding = mkToEncodingCommon toJSONClass
315+
316+-- | Generates a lambda expression which encodes the given data type or
317+-- data family instance constructor as a JSON string by using the given encoding
318+-- function on occurrences of the last type parameter.
319+mkLiftToEncoding :: Options -- ^ Encoding options.
320+ -> Name -- ^ Name of the type to encode.
321+ -> Q Exp
322+mkLiftToEncoding = mkToEncodingCommon toJSON1Class
323+
324+-- | Generates a lambda expression which encodes the given data type or
325+-- data family instance constructor as a JSON string by using the given encoding
326+-- functions on occurrences of the last two type parameters.
327+mkLiftToEncoding2 :: Options -- ^ Encoding options.
328+ -> Name -- ^ Name of the type to encode.
329+ -> Q Exp
330+mkLiftToEncoding2 = mkToEncodingCommon toJSON2Class
331+
332+mkToEncodingCommon :: JSONClass -- ^ Which class's method is being derived.
333+ -> Options -- ^ Encoding options.
334+ -> Name -- ^ Name of the encoded type.
335+ -> Q Exp
336+mkToEncodingCommon = mkFunCommon (\jc _ -> consToEncoding jc)
226337
227338-- | Helper function used by both 'deriveToJSON' and 'mkToJSON'. Generates
228339-- code to generate a 'Value' of a number of constructors. All constructors
229340-- must be from the same type.
230−consToValue :: Options
231− -- ^ Encoding options.
232− -> [Con]
233− -- ^ Constructors for which to generate JSON generating code.
234− -> Q Exp
235−
236−consToValue _ [] = error $ "Data.Aeson.TH.consToValue: "
237− ++ "Not a single constructor given!"
341+consToValue :: JSONClass
342+ -- ^ The ToJSON variant being derived.
343+ -> Options
344+ -- ^ Encoding options.
345+ -> [Con]
346+ -- ^ Constructors for which to generate JSON generating code.
347+ -> Q Exp
238348
239−-- A single constructor is directly encoded. The constructor itself may be
240−-- forgotten.
241−consToValue opts [con] = do
242− value <- newName "value"
243− lam1E (varP value) $ caseE (varE value) [argsToValue opts False con]
349+consToValue _ _ [] = error $ "Data.Aeson.TH.consToValue: "
350+ ++ "Not a single constructor given!"
244351
245−consToValue opts cons = do
352+consToValue jc opts cons = do
246353 value <- newName "value"
247− lam1E (varP value) $ caseE (varE value) matches
354+ tjs <- newNameList "_tj" $ arityInt jc
355+ tjls <- newNameList "_tjl" $ arityInt jc
356+ let zippedTJs = zip tjs tjls
357+ interleavedTJs = interleave tjs tjls
358+ lamE (map varP $ interleavedTJs ++ [value]) $
359+ caseE (varE value) (matches zippedTJs)
248360 where
249− matches
250− | allNullaryToStringTag opts && all isNullary cons =
361+ matches tjs = case cons of
362+ -- A single constructor is directly encoded. The constructor itself may be
363+ -- forgotten.
364+ [con] -> [argsToValue jc tjs opts False con]
365+ _ | allNullaryToStringTag opts && all isNullary cons ->
251366 [ match (conP conName []) (normalB $ conStr opts conName) []
252367 | con <- cons
253368 , let conName = getConName con
254369 ]
255− | otherwise = [argsToValue opts True con | con <- cons]
370+ | otherwise -> [argsToValue jc tjs opts True con | con <- cons]
256371
257372conStr :: Options -> Name -> Q Exp
258373conStr opts = appE [|String|] . conTxt opts
@@ -266,35 +381,39 @@ conStringE opts = stringE . constructorTagModifier opts . nameBase
266381-- | Helper function used by both 'deriveToJSON' and 'mkToEncoding'. Generates
267382-- code to write out a value for a number of constructors. All constructors
268383-- must be from the same type.
269−consToEncoding :: Options
270− -- ^ Encoding options.
384+consToEncoding :: JSONClass
385+ -- ^ The ToJSON variant being derived.
386+ -> Options
387+ -- ^ Encoding options.
271388 -> [Con]
272389 -- ^ Constructors for which to generate JSON generating code.
273390 -> Q Exp
274391
275−consToEncoding _ [] = error $ "Data.Aeson.TH.consToEncoding: "
276− ++ "Not a single constructor given!"
392+consToEncoding _ _ [] = error $ "Data.Aeson.TH.consToEncoding: "
393+ ++ "Not a single constructor given!"
277394
278−-- A single constructor is directly encoded. The constructor itself may be
279−-- forgotten.
280−consToEncoding opts [con] = do
395+consToEncoding jc opts cons = do
281396 value <- newName "value"
282− lam1E (varP value) $ caseE (varE value) [argsToEncoding opts False con]
283−
284−-- Encode just the name of the constructor of a sum type iff all the
285−-- constructors are nullary.
286−consToEncoding opts cons = do
287− value <- newName "value"
288− lam1E (varP value) $ caseE (varE value) matches
397+ tes <- newNameList "_te" $ arityInt jc
398+ tels <- newNameList "_tel" $ arityInt jc
399+ let zippedTEs = zip tes tels
400+ interleavedTEs = interleave tes tels
401+ lamE (map varP $ interleavedTEs ++ [value]) $
402+ caseE (varE value) (matches zippedTEs)
289403 where
290− matches
291− | allNullaryToStringTag opts && all isNullary cons =
404+ matches tes = case cons of
405+ -- A single constructor is directly encoded. The constructor itself may be
406+ -- forgotten.
407+ [con] -> [argsToEncoding jc tes opts False con]
408+ -- Encode just the name of the constructor of a sum type iff all the
409+ -- constructors are nullary.
410+ _ | allNullaryToStringTag opts && all isNullary cons ->
292411 [ match (conP conName [])
293412 (normalB $ encStr opts conName) []
294413 | con <- cons
295414 , let conName = getConName con
296415 ]
297− | otherwise = [argsToEncoding opts True con | con <- cons]
416+ | otherwise -> [argsToEncoding jc tes opts True con | con <- cons]
298417
299418encStr :: Options -> Name -> Q Exp
300419encStr opts = appE [|E.text|] . conTxt opts
@@ -332,20 +451,25 @@ nullarySumToValue opts multiCons conName =
332451 _ -> sumToValue opts multiCons conName [e|toJSON ([] :: [()])|]
333452
334453-- | Generates code to generate the JSON encoding of a single constructor.
335−argsToValue :: Options -> Bool -> Con -> Q Match
454+argsToValue :: JSONClass -> [(Name, Name)] -> Options -> Bool -> Con -> Q Match
336455-- Nullary constructors. Generates code that explicitly matches against the
337456-- constructor even though it doesn't contain data. This is useful to prevent
338457-- type errors.
339−argsToValue opts multiCons (NormalC conName []) =
458+argsToValue jc tjs opts multiCons (NormalC conName []) = do
459+ ([], _) <- reifyConTys jc tjs conName
340460 match (conP conName [])
341461 (normalB (nullarySumToValue opts multiCons conName))
342462 []
343463
344464-- Polyadic constructors with special case for unary constructors.
345−argsToValue opts multiCons (NormalC conName ts) = do
465+argsToValue jc tjs opts multiCons (NormalC conName ts) = do
466+ (argTys, tvMap) <- reifyConTys jc tjs conName
346467 let len = length ts
347− args <- mapM newName ["arg" ++ show n | n <- [1..len]]
348− js <- case [[|toJSON|] `appE` varE arg | arg <- args] of
468+ args <- newNameList "arg" len
469+ js <- case [ dispatchToJSON jc conName tvMap argTy
470+ `appE` varE arg
471+ | (arg, argTy) <- zip args argTys
472+ ] of
349473 -- Single argument is directly converted.
350474 [e] -> return e
351475 -- Multiple arguments are converted to a JSON array.
@@ -370,10 +494,11 @@ argsToValue opts multiCons (NormalC conName ts) = do
370494 []
371495
372496-- Records.
373−argsToValue opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
374− (True,True,[(_,st,ty)]) -> argsToValue opts multiCons (NormalC conName [(st,ty)])
497+argsToValue jc tjs opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
498+ (True,True,[(_,st,ty)]) -> argsToValue jc tjs opts multiCons (NormalC conName [(st,ty)])
375499 _ -> do
376− args <- mapM newName ["arg" ++ show n | (_, n) <- zip ts [1 :: Integer ..]]
500+ (argTys, tvMap) <- reifyConTys jc tjs conName
501+ args <- newNameList "arg" $ length ts
377502 let exp = [|A.object|] `appE` pairs
378503
379504 pairs | omitNothingFields opts = infixApp maybeFields
@@ -381,7 +506,7 @@ argsToValue opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, no
381506 restFields
382507 | otherwise = listE $ map toPair argCons
383508
384− argCons = zip args ts
509+ argCons = zip3 args argTys ts
385510
386511 maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)
387512
@@ -389,17 +514,18 @@ argsToValue opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, no
389514
390515 (maybes, rest) = partition isMaybe argCons
391516
392− maybeToPair (arg, (field, _, _)) =
393− infixApp (infixE (Just $ toFieldName field)
394− [|(.=)|]
395− Nothing)
517+ maybeToPair (arg, argTy, (field, _, _)) =
518+ infixApp ([|keyValuePairWith|]
519+ `appE` dispatchToJSON jc conName tvMap argTy
520+ `appE` toFieldName field)
396521 [|(<$>)|]
397522 (varE arg)
398523
399− toPair (arg, (field, _, _)) =
400− infixApp (toFieldName field)
401− [|(.=)|]
402− (varE arg)
524+ toPair (arg, argTy, (field, _, _)) =
525+ [|keyValuePairWith|]
526+ `appE` dispatchToJSON jc conName tvMap argTy
527+ `appE` toFieldName field
528+ `appE` varE arg
403529
404530 toFieldName field = [|T.pack|] `appE` fieldLabelExp opts field
405531
@@ -424,33 +550,35 @@ argsToValue opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, no
424550 ) []
425551
426552-- Infix constructors.
427−argsToValue opts multiCons (InfixC _ conName _) = do
553+argsToValue jc tjs opts multiCons (InfixC _ conName _) = do
554+ ([alTy, arTy], tvMap) <- reifyConTys jc tjs conName
428555 al <- newName "argL"
429556 ar <- newName "argR"
430557 match (infixP (varP al) conName (varP ar))
431558 ( normalB
432559 $ sumToValue opts multiCons conName
433− $ [|toJSON|] `appE` listE [ [|toJSON|] `appE` varE a
434− | a <- [al,ar]
560+ $ [|toJSON|] `appE` listE [ dispatchToJSON jc conName tvMap aTy
561+ `appE` varE a
562+ | (a, aTy) <- [(al,alTy), (ar,arTy)]
435563 ]
436564 )
437565 []
438566-- Existentially quantified constructors.
439−argsToValue opts multiCons (ForallC _ _ con) =
440− argsToValue opts multiCons con
567+argsToValue jc tjs opts multiCons (ForallC _ _ con) =
568+ argsToValue jc tjs opts multiCons con
441569
442570#if MIN_VERSION_template_haskell(2,11,0)
443571-- GADTs.
444−argsToValue opts multiCons (GadtC conNames ts _) =
445− argsToValue opts multiCons $ NormalC (head conNames) ts
572+argsToValue jc tjs opts multiCons (GadtC conNames ts _) =
573+ argsToValue jc tjs opts multiCons $ NormalC (head conNames) ts
446574
447−argsToValue opts multiCons (RecGadtC conNames ts _) =
448− argsToValue opts multiCons $ RecC (head conNames) ts
575+argsToValue jc tjs opts multiCons (RecGadtC conNames ts _) =
576+ argsToValue jc tjs opts multiCons $ RecC (head conNames) ts
449577#endif
450578
451−isMaybe :: (a, (b, c, Type)) -> Bool
452−isMaybe (_, (_, _, AppT (ConT t) _)) = t == ''Maybe
453−isMaybe _ = False
579+isMaybe :: (a, b, (c, d, Type)) -> Bool
580+isMaybe (_, _, (_, _, AppT (ConT t) _)) = t == ''Maybe
581+isMaybe _ = False
454582
455583(<^>) :: ExpQ -> ExpQ -> ExpQ
456584(<^>) a b = infixApp a [|(<>)|] b
@@ -468,7 +596,7 @@ array :: ExpQ -> ExpQ
468596array exp = [|E.wrapArray|] `appE` exp
469597
470598object :: ExpQ -> ExpQ
471−object exp = [|E.wrapObject|] `appE` exp
599+object exp = [|E.wrapObject|] `appE` exp
472600
473601sumToEncoding :: Options -> Bool -> Name -> Q Exp -> Q Exp
474602sumToEncoding opts multiCons conName exp
@@ -495,35 +623,41 @@ nullarySumToEncoding opts multiCons conName =
495623 _ -> sumToEncoding opts multiCons conName [e|toEncoding ([] :: [()])|]
496624
497625-- | Generates code to generate the JSON encoding of a single constructor.
498−argsToEncoding :: Options -> Bool -> Con -> Q Match
626+argsToEncoding :: JSONClass -> [(Name, Name)] -> Options -> Bool -> Con -> Q Match
499627-- Nullary constructors. Generates code that explicitly matches against the
500628-- constructor even though it doesn't contain data. This is useful to prevent
501629-- type errors.
502−argsToEncoding opts multiCons (NormalC conName []) =
630+argsToEncoding jc tes opts multiCons (NormalC conName []) = do
631+ ([], _) <- reifyConTys jc tes conName
503632 match (conP conName [])
504633 (normalB (nullarySumToEncoding opts multiCons conName))
505634 []
506635
507636-- Polyadic constructors with special case for unary constructors.
508−argsToEncoding opts multiCons (NormalC conName ts) = do
637+argsToEncoding jc tes opts multiCons (NormalC conName ts) = do
638+ (argTys, tvMap) <- reifyConTys jc tes conName
509639 let len = length ts
510− args <- mapM newName ["arg" ++ show n | n <- [1..len]]
511− js <- case args of
640+ args <- newNameList "arg" len
641+ js <- case zip args argTys of
512642 -- Single argument is directly converted.
513− [e] -> return ([|toEncoding|] `appE` varE e)
643+ [(e,eTy)] -> return (dispatchToEncoding jc conName tvMap eTy
644+ `appE` varE e)
514645 -- Multiple arguments are converted to a JSON array.
515646 es ->
516− return (array (foldr1 (<%>) [[|toEncoding|] `appE` varE x | x <- es]))
647+ return (array (foldr1 (<%>) [ dispatchToEncoding jc conName tvMap xTy
648+ `appE` varE x
649+ | (x,xTy) <- es
650+ ]))
517651 match (conP conName $ map varP args)
518652 (normalB $ sumToEncoding opts multiCons conName js)
519653 []
520654
521655-- Records.
522−argsToEncoding opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
523− (True,True,[(_,st,ty)]) -> argsToEncoding opts multiCons (NormalC conName [(st,ty)])
656+argsToEncoding jc tes opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
657+ (True,True,[(_,st,ty)]) -> argsToEncoding jc tes opts multiCons (NormalC conName [(st,ty)])
524658 _ -> do
525− args <- mapM newName ["arg" ++ show n | (_, n) <- zip ts [1 :: Integer ..]]
526−
659+ args <- newNameList "arg" $ length ts
660+ (argTys, tvMap) <- reifyConTys jc tes conName
527661 let exp = object objBody
528662
529663 objBody = [|mconcat|] `appE`
@@ -533,7 +667,7 @@ argsToEncoding opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts,
533667 restFields
534668 | otherwise = listE (map toPair argCons)
535669
536− argCons = zip args ts
670+ argCons = zip3 args argTys ts
537671
538672 maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)
539673
@@ -541,7 +675,7 @@ argsToEncoding opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts,
541675
542676 (maybes, rest) = partition isMaybe argCons
543677
544− maybeToPair (arg, (field, _, _)) =
678+ maybeToPair (arg, argTy, (field, _, _)) =
545679 infixApp
546680 (infixApp
547681 (infixE
@@ -549,12 +683,14 @@ argsToEncoding opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts,
549683 [|(<>)|]
550684 Nothing)
551685 [|(.)|]
552− [|toEncoding|])
686+ (dispatchToEncoding jc conName tvMap argTy))
553687 [|(<$>)|]
554688 (varE arg)
555689
556− toPair (arg, (field, _, _)) =
557− toFieldName field <:> [|toEncoding|] `appE` varE arg
690+ toPair (arg, argTy, (field, _, _)) =
691+ toFieldName field
692+ <:> dispatchToEncoding jc conName tvMap argTy
693+ `appE` varE arg
558694
559695 toFieldName field = [|E.text|] `appE`
560696 ([|T.pack|] `appE` fieldLabelExp opts field)
@@ -575,28 +711,30 @@ argsToEncoding opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts,
575711 ) []
576712
577713-- Infix constructors.
578−argsToEncoding opts multiCons (InfixC _ conName _) = do
714+argsToEncoding jc tes opts multiCons (InfixC _ conName _) = do
579715 al <- newName "argL"
580716 ar <- newName "argR"
717+ ([alTy,arTy], tvMap) <- reifyConTys jc tes conName
581718 match (infixP (varP al) conName (varP ar))
582719 ( normalB
583720 $ sumToEncoding opts multiCons conName
584− $ [|toEncoding|] `appE` listE [ [|toJSON|] `appE` varE a
585− | a <- [al,ar]
586− ]
721+ $ array (foldr1 (<%>) [ dispatchToEncoding jc conName tvMap aTy
722+ `appE` varE a
723+ | (a,aTy) <- [(al,alTy), (ar,arTy)]
724+ ])
587725 )
588726 []
589727-- Existentially quantified constructors.
590−argsToEncoding opts multiCons (ForallC _ _ con) =
591− argsToEncoding opts multiCons con
728+argsToEncoding jc tes opts multiCons (ForallC _ _ con) =
729+ argsToEncoding jc tes opts multiCons con
592730
593731#if MIN_VERSION_template_haskell(2,11,0)
594732-- GADTs.
595−argsToEncoding opts multiCons (GadtC conNames ts _) =
596− argsToEncoding opts multiCons $ NormalC (head conNames) ts
733+argsToEncoding jc tes opts multiCons (GadtC conNames ts _) =
734+ argsToEncoding jc tes opts multiCons $ NormalC (head conNames) ts
597735
598−argsToEncoding opts multiCons (RecGadtC conNames ts _) =
599− argsToEncoding opts multiCons $ RecC (head conNames) ts
736+argsToEncoding jc tes opts multiCons (RecGadtC conNames ts _) =
737+ argsToEncoding jc tes opts multiCons $ RecC (head conNames) ts
600738#endif
601739
602740--------------------------------------------------------------------------------
@@ -611,33 +749,73 @@ deriveFromJSON :: Options
611749 -- ^ Name of the type for which to generate a 'FromJSON' instance
612750 -- declaration.
613751 -> Q [Dec]
614−deriveFromJSON opts name =
615− withType name $ \name' tvbs cons mbTys -> fmap (:[]) $ fromCons name' tvbs cons mbTys
616− where
617− fromCons :: Name -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec
618− fromCons name' tvbs cons mbTys = do
619− (instanceCxt, instanceType) <- buildTypeInstance name' ''FromJSON tvbs mbTys
620− instanceD (return instanceCxt)
621− (return instanceType)
622− [ funD 'parseJSON
623− [ clause []
624− (normalB $ consFromJSON name' opts cons)
625− []
626− ]
627− ]
752+deriveFromJSON = deriveFromJSONCommon fromJSONClass
753+
754+-- | Generates a 'FromJSON1' instance declaration for the given data type or
755+-- data family instance constructor.
756+deriveFromJSON1 :: Options
757+ -- ^ Encoding options.
758+ -> Name
759+ -- ^ Name of the type for which to generate a 'FromJSON1' instance
760+ -- declaration.
761+ -> Q [Dec]
762+deriveFromJSON1 = deriveFromJSONCommon fromJSON1Class
763+
764+-- | Generates a 'FromJSON2' instance declaration for the given data type or
765+-- data family instance constructor.
766+deriveFromJSON2 :: Options
767+ -- ^ Encoding options.
768+ -> Name
769+ -- ^ Name of the type for which to generate a 'FromJSON3' instance
770+ -- declaration.
771+ -> Q [Dec]
772+deriveFromJSON2 = deriveFromJSONCommon fromJSON2Class
773+
774+deriveFromJSONCommon :: JSONClass
775+ -- ^ The FromJSON variant being derived.
776+ -> Options
777+ -- ^ Encoding options.
778+ -> Name
779+ -- ^ Name of the type for which to generate an instance.
780+ -- declaration.
781+ -> Q [Dec]
782+deriveFromJSONCommon = deriveJSONClass [(ParseJSON, consFromJSON)]
628783
629784-- | Generates a lambda expression which parses the JSON encoding of the given
630785-- data type or data family instance constructor.
631786mkParseJSON :: Options -- ^ Encoding options.
632787 -> Name -- ^ Name of the encoded type.
633788 -> Q Exp
634−mkParseJSON opts name =
635− withType name (\name' _ cons _ -> consFromJSON name' opts cons)
789+mkParseJSON = mkParseJSONCommon fromJSONClass
790+
791+-- | Generates a lambda expression which parses the JSON encoding of the given
792+-- data type or data family instance constructor by using the given parsing
793+-- function on occurrences of the last type parameter.
794+mkLiftParseJSON :: Options -- ^ Encoding options.
795+ -> Name -- ^ Name of the encoded type.
796+ -> Q Exp
797+mkLiftParseJSON = mkParseJSONCommon fromJSON1Class
798+
799+-- | Generates a lambda expression which parses the JSON encoding of the given
800+-- data type or data family instance constructor by using the given parsing
801+-- functions on occurrences of the last two type parameters.
802+mkLiftParseJSON2 :: Options -- ^ Encoding options.
803+ -> Name -- ^ Name of the encoded type.
804+ -> Q Exp
805+mkLiftParseJSON2 = mkParseJSONCommon fromJSON2Class
806+
807+mkParseJSONCommon :: JSONClass -- ^ Which class's method is being derived.
808+ -> Options -- ^ Encoding options.
809+ -> Name -- ^ Name of the encoded type.
810+ -> Q Exp
811+mkParseJSONCommon = mkFunCommon consFromJSON
636812
637813-- | Helper function used by both 'deriveFromJSON' and 'mkParseJSON'. Generates
638814-- code to parse the JSON encoding of a number of constructors. All constructors
639815-- must be from the same type.
640−consFromJSON :: Name
816+consFromJSON :: JSONClass
817+ -- ^ The FromJSON variant being derived.
818+ -> Name
641819 -- ^ Name of the type to which the constructors belong.
642820 -> Options
643821 -- ^ Encoding options
@@ -645,21 +823,25 @@ consFromJSON :: Name
645823 -- ^ Constructors for which to generate JSON parsing code.
646824 -> Q Exp
647825
648−consFromJSON _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
826+consFromJSON _ _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
649827 ++ "Not a single constructor given!"
650828
651−consFromJSON tName opts [con] = do
829+consFromJSON jc tName opts cons = do
652830 value <- newName "value"
653− lam1E (varP value) (parseArgs tName opts con (Right value))
654−
655−consFromJSON tName opts cons = do
656− value <- newName "value"
657− lam1E (varP value) $ caseE (varE value) $
658− if allNullaryToStringTag opts && all isNullary cons
659− then allNullaryMatches
660− else mixedMatches
831+ pjs <- newNameList "_pj" $ arityInt jc
832+ pjls <- newNameList "_pjl" $ arityInt jc
833+ let zippedPJs = zip pjs pjls
834+ interleavedPJs = interleave pjs pjls
835+ lamE (map varP $ interleavedPJs ++ [value]) $ lamExpr value zippedPJs
661836
662837 where
838+ lamExpr value pjs = case cons of
839+ [con] -> parseArgs jc pjs tName opts con (Right value)
840+ _ -> caseE (varE value) $
841+ if allNullaryToStringTag opts && all isNullary cons
842+ then allNullaryMatches
843+ else mixedMatches pjs
844+
663845 allNullaryMatches =
664846 [ do txt <- newName "txt"
665847 match (conP 'String [varP txt])
@@ -693,12 +875,12 @@ consFromJSON tName opts cons = do
693875 []
694876 ]
695877
696− mixedMatches =
878+ mixedMatches pjs =
697879 case sumEncoding opts of
698880 TaggedObject {tagFieldName, contentsFieldName} ->
699− parseObject $ parseTaggedObject tagFieldName contentsFieldName
881+ parseObject $ parseTaggedObject pjs tagFieldName contentsFieldName
700882 ObjectWithSingleField ->
701− parseObject $ parseObjectWithSingleField
883+ parseObject $ parseObjectWithSingleField pjs
702884 TwoElemArray ->
703885 [ do arr <- newName "array"
704886 match (conP 'Array [varP arr])
@@ -706,7 +888,7 @@ consFromJSON tName opts cons = do
706888 [ liftM2 (,) (normalG $ infixApp ([|V.length|] `appE` varE arr)
707889 [|(==)|]
708890 (litE $ integerL 2))
709− (parse2ElemArray arr)
891+ (parse2ElemArray pjs arr)
710892 , liftM2 (,) (normalG [|otherwise|])
711893 (([|not2ElemArray|]
712894 `appE` (litE $ stringL $ show tName)
@@ -737,16 +919,16 @@ consFromJSON tName opts cons = do
737919 []
738920 ]
739921
740− parseTaggedObject typFieldName valFieldName obj = do
922+ parseTaggedObject pjs typFieldName valFieldName obj = do
741923 conKey <- newName "conKey"
742924 doE [ bindS (varP conKey)
743925 (infixApp (varE obj)
744926 [|(.:)|]
745927 ([|T.pack|] `appE` stringE typFieldName))
746− , noBindS $ parseContents conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
928+ , noBindS $ parseContents pjs conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
747929 ]
748930
749− parse2ElemArray arr = do
931+ parse2ElemArray pjs arr = do
750932 conKey <- newName "conKey"
751933 conVal <- newName "conVal"
752934 let letIx n ix =
@@ -761,7 +943,8 @@ consFromJSON tName opts cons = do
761943 (caseE (varE conKey)
762944 [ do txt <- newName "txt"
763945 match (conP 'String [varP txt])
764− (normalB $ parseContents txt
946+ (normalB $ parseContents pjs
947+ txt
765948 (Right conVal)
766949 'conNotFoundFail2ElemArray
767950 )
@@ -777,12 +960,12 @@ consFromJSON tName opts cons = do
777960 ]
778961 )
779962
780− parseObjectWithSingleField obj = do
963+ parseObjectWithSingleField pjs obj = do
781964 conKey <- newName "conKey"
782965 conVal <- newName "conVal"
783966 caseE ([e|H.toList|] `appE` varE obj)
784967 [ match (listP [tupP [varP conKey, varP conVal]])
785− (normalB $ parseContents conKey (Right conVal) 'conNotFoundFailObjectSingleField)
968+ (normalB $ parseContents pjs conKey (Right conVal) 'conNotFoundFailObjectSingleField)
786969 []
787970 , do other <- newName "other"
788971 match (varP other)
@@ -793,7 +976,7 @@ consFromJSON tName opts cons = do
793976 []
794977 ]
795978
796− parseContents conKey contents errorFun =
979+ parseContents pjs conKey contents errorFun =
797980 caseE (varE conKey)
798981 [ match wildP
799982 ( guardedB $
@@ -801,7 +984,7 @@ consFromJSON tName opts cons = do
801984 [|(==)|]
802985 ([|T.pack|] `appE`
803986 conNameExp opts con)
804− e <- parseArgs tName opts con contents
987+ e <- parseArgs jc pjs tName opts con contents
805988 return (g, e)
806989 | con <- cons
807990 ]
@@ -845,30 +1028,40 @@ parseNullaryMatches tName conName =
8451028 , matchFailed tName conName "Array"
8461029 ]
8471030
848−parseUnaryMatches :: Name -> [Q Match]
849−parseUnaryMatches conName =
1031+parseUnaryMatches :: JSONClass -> TyVarMap -> Type -> Name -> [Q Match]
1032+parseUnaryMatches jc tvMap argTy conName =
8501033 [ do arg <- newName "arg"
8511034 match (varP arg)
8521035 ( normalB $ infixApp (conE conName)
8531036 [|(<$>)|]
854− ([|parseJSON|] `appE` varE arg)
1037+ (dispatchParseJSON jc conName tvMap argTy
1038+ `appE` varE arg)
8551039 )
8561040 []
8571041 ]
8581042
859−parseRecord :: Options -> Name -> Name -> [VarStrictType] -> Name -> ExpQ
860−parseRecord opts tName conName ts obj =
1043+parseRecord :: JSONClass
1044+ -> TyVarMap
1045+ -> [Type]
1046+ -> Options
1047+ -> Name
1048+ -> Name
1049+ -> [VarStrictType]
1050+ -> Name
1051+ -> ExpQ
1052+parseRecord jc tvMap argTys opts tName conName ts obj =
8611053 foldl' (\a b -> infixApp a [|(<*>)|] b)
8621054 (infixApp (conE conName) [|(<$>)|] x)
8631055 xs
8641056 where
8651057 x:xs = [ [|lookupField|]
1058+ `appE` dispatchParseJSON jc conName tvMap argTy
8661059 `appE` (litE $ stringL $ show tName)
8671060 `appE` (litE $ stringL $ constructorTagModifier opts $ nameBase conName)
8681061 `appE` (varE obj)
8691062 `appE` ( [|T.pack|] `appE` fieldLabelExp opts field
8701063 )
871− | (field, _, _) <- ts
1064+ | ((field, _, _), argTy) <- zip ts argTys
8721065 ]
8731066
8741067getValField :: Name -> String -> [MatchQ] -> Q Exp
@@ -881,80 +1074,93 @@ getValField obj valFieldName matches = do
8811074 , noBindS $ caseE (varE val) matches
8821075 ]
8831076
1077+matchCases :: Either (String, Name) Name -> [MatchQ] -> Q Exp
1078+matchCases (Left (valFieldName, obj)) = getValField obj valFieldName
1079+matchCases (Right valName) = caseE (varE valName)
1080+
8841081-- | Generates code to parse the JSON encoding of a single constructor.
885−parseArgs :: Name -- ^ Name of the type to which the constructor belongs.
1082+parseArgs :: JSONClass -- ^ The FromJSON variant being derived.
1083+ -> [(Name, Name)] -- ^ The names of the encoding/decoding function arguments.
1084+ -> Name -- ^ Name of the type to which the constructor belongs.
8861085 -> Options -- ^ Encoding options.
8871086 -> Con -- ^ Constructor for which to generate JSON parsing code.
8881087 -> Either (String, Name) Name -- ^ Left (valFieldName, objName) or
8891088 -- Right valName
8901089 -> Q Exp
8911090-- Nullary constructors.
892−parseArgs _ _ (NormalC conName []) (Left _) =
1091+parseArgs jc pjs _ _ (NormalC conName []) (Left _) = do
1092+ ([], _) <- reifyConTys jc pjs conName
8931093 [|pure|] `appE` conE conName
894−parseArgs tName _ (NormalC conName []) (Right valName) =
1094+parseArgs jc pjs tName _ (NormalC conName []) (Right valName) = do
1095+ ([], _) <- reifyConTys jc pjs conName
8951096 caseE (varE valName) $ parseNullaryMatches tName conName
8961097
8971098-- Unary constructors.
898−parseArgs _ _ (NormalC conName [_]) (Left (valFieldName, obj)) =
899− getValField obj valFieldName $ parseUnaryMatches conName
900−parseArgs _ _ (NormalC conName [_]) (Right valName) =
901− caseE (varE valName) $ parseUnaryMatches conName
1099+parseArgs jc pjs _ _ (NormalC conName [_]) contents = do
1100+ ([argTy], tvMap) <- reifyConTys jc pjs conName
1101+ matchCases contents $ parseUnaryMatches jc tvMap argTy conName
9021102
9031103-- Polyadic constructors.
904−parseArgs tName _ (NormalC conName ts) (Left (valFieldName, obj)) =
905− getValField obj valFieldName $ parseProduct tName conName $ genericLength ts
906−parseArgs tName _ (NormalC conName ts) (Right valName) =
907− caseE (varE valName) $ parseProduct tName conName $ genericLength ts
1104+parseArgs jc pjs tName _ (NormalC conName ts) contents = do
1105+ (argTys, tvMap) <- reifyConTys jc pjs conName
1106+ let len = genericLength ts
1107+ matchCases contents $ parseProduct jc tvMap argTys tName conName len
9081108
9091109-- Records.
910−parseArgs tName opts (RecC conName ts) (Left (_, obj)) =
911− parseRecord opts tName conName ts obj
912−parseArgs tName opts (RecC conName ts) (Right valName) = case (unwrapUnaryRecords opts,ts) of
913− (True,[(_,st,ty)])-> parseArgs tName opts (NormalC conName [(st,ty)]) (Right valName)
1110+parseArgs jc pjs tName opts (RecC conName ts) (Left (_, obj)) = do
1111+ (argTys, tvMap) <- reifyConTys jc pjs conName
1112+ parseRecord jc tvMap argTys opts tName conName ts obj
1113+parseArgs jc pjs tName opts (RecC conName ts) (Right valName) = case (unwrapUnaryRecords opts,ts) of
1114+ (True,[(_,st,ty)])-> parseArgs jc pjs tName opts (NormalC conName [(st,ty)]) (Right valName)
9141115 _ -> do
9151116 obj <- newName "recObj"
1117+ (argTys, tvMap) <- reifyConTys jc pjs conName
9161118 caseE (varE valName)
917− [ match (conP 'Object [varP obj]) (normalB $ parseRecord opts tName conName ts obj) []
1119+ [ match (conP 'Object [varP obj]) (normalB $
1120+ parseRecord jc tvMap argTys opts tName conName ts obj) []
9181121 , matchFailed tName conName "Object"
9191122 ]
9201123
9211124-- Infix constructors. Apart from syntax these are the same as
9221125-- polyadic constructors.
923−parseArgs tName _ (InfixC _ conName _) (Left (valFieldName, obj)) =
924− getValField obj valFieldName $ parseProduct tName conName 2
925−parseArgs tName _ (InfixC _ conName _) (Right valName) =
926− caseE (varE valName) $ parseProduct tName conName 2
1126+parseArgs jc pjs tName _ (InfixC _ conName _) contents = do
1127+ (argTys, tvMap) <- reifyConTys jc pjs conName
1128+ matchCases contents $ parseProduct jc tvMap argTys tName conName 2
9271129
9281130-- Existentially quantified constructors. We ignore the quantifiers
9291131-- and proceed with the contained constructor.
930−parseArgs tName opts (ForallC _ _ con) contents =
931− parseArgs tName opts con contents
1132+parseArgs jc pjs tName opts (ForallC _ _ con) contents =
1133+ parseArgs jc pjs tName opts con contents
9321134
9331135#if MIN_VERSION_template_haskell(2,11,0)
9341136-- GADTs. We ignore the refined return type and proceed as if it were a
9351137-- NormalC or RecC.
936−parseArgs tName opts (GadtC conNames ts _) contents =
937− parseArgs tName opts (NormalC (head conNames) ts) contents
1138+parseArgs jc pjs tName opts (GadtC conNames ts _) contents =
1139+ parseArgs jc pjs tName opts (NormalC (head conNames) ts) contents
9381140
939−parseArgs tName opts (RecGadtC conNames ts _) contents =
940− parseArgs tName opts (RecC (head conNames) ts) contents
1141+parseArgs jc pjs tName opts (RecGadtC conNames ts _) contents =
1142+ parseArgs jc pjs tName opts (RecC (head conNames) ts) contents
9411143#endif
9421144
9431145-- | Generates code to parse the JSON encoding of an n-ary
9441146-- constructor.
945−parseProduct :: Name -- ^ Name of the type to which the constructor belongs.
1147+parseProduct :: JSONClass -- ^ The FromJSON variant being derived.
1148+ -> TyVarMap -- ^ Maps the last type variables to their decoding
1149+ -- function arguments.
1150+ -> [Type] -- ^ The argument types of the constructor.
1151+ -> Name -- ^ Name of the type to which the constructor belongs.
9461152 -> Name -- ^ 'Con'structor name.
9471153 -> Integer -- ^ 'Con'structor arity.
9481154 -> [Q Match]
949−parseProduct tName conName numArgs =
1155+parseProduct jc tvMap argTys tName conName numArgs =
9501156 [ do arr <- newName "arr"
9511157 -- List of: "parseJSON (arr `V.unsafeIndex` <IX>)"
952− let x:xs = [ [|parseJSON|]
1158+ let x:xs = [ dispatchParseJSON jc conName tvMap argTy
9531159 `appE`
9541160 infixApp (varE arr)
9551161 [|V.unsafeIndex|]
9561162 (litE $ integerL ix)
957− | ix <- [0 .. numArgs - 1]
1163+ | (argTy, ix) <- zip argTys [0 .. numArgs - 1]
9581164 ]
9591165 match (conP 'Array [varP arr])
9601166 (normalB $ condE ( infixApp ([|V.length|] `appE` varE arr)
@@ -977,7 +1183,6 @@ parseProduct tName conName numArgs =
9771183 , matchFailed tName conName "Array"
9781184 ]
9791185
980−
9811186--------------------------------------------------------------------------------
9821187-- Parsing errors
9831188--------------------------------------------------------------------------------
@@ -1002,17 +1207,25 @@ parseTypeMismatch tName conName expected actual =
10021207 , actual
10031208 ]
10041209
1005−class (FromJSON a) => LookupField a where
1006− lookupField :: String -> String -> Object -> T.Text -> Parser a
1210+class LookupField a where
1211+ lookupField :: (Value -> Parser a) -> String -> String
1212+ -> Object -> T.Text -> Parser a
1213+
1214+instance OVERLAPPABLE_ LookupField a where
1215+ lookupField = lookupFieldWith
10071216
1008−instance OVERLAPPABLE_ (FromJSON a) => LookupField a where
1009− lookupField tName rec obj key =
1010− case H.lookup key obj of
1011− Nothing -> unknownFieldFail tName rec (T.unpack key)
1012− Just v -> parseJSON v <?> Key key
1217+instance LookupField (Maybe a) where
1218+ lookupField pj _ _ = parseOptionalFieldWith pj
10131219
1014−instance (FromJSON a) => LookupField (Maybe a) where
1015− lookupField _ _ = (.:?)
1220+lookupFieldWith :: (Value -> Parser a) -> String -> String
1221+ -> Object -> T.Text -> Parser a
1222+lookupFieldWith pj tName rec obj key =
1223+ case H.lookup key obj of
1224+ Nothing -> unknownFieldFail tName rec (T.unpack key)
1225+ Just v -> pj v <?> Key key
1226+
1227+keyValuePairWith :: (v -> Value) -> T.Text -> v -> Pair
1228+keyValuePairWith tj name value = (name, tj value)
10161229
10171230unknownFieldFail :: String -> String -> String -> Parser fail
10181231unknownFieldFail tName rec key =
@@ -1063,6 +1276,120 @@ parseTypeMismatch' conName tName expected actual =
10631276 fail $ printf "When parsing the constructor %s of type %s expected %s but got %s."
10641277 conName tName expected actual
10651278
1279+--------------------------------------------------------------------------------
1280+-- Shared ToJSON and FromJSON code
1281+--------------------------------------------------------------------------------
1282+
1283+-- | Functionality common to 'deriveJSON', 'deriveJSON1', and 'deriveJSON2'.
1284+deriveJSONBoth :: (Options -> Name -> Q [Dec])
1285+ -- ^ Function which derives a flavor of 'ToJSON'.
1286+ -> (Options -> Name -> Q [Dec])
1287+ -- ^ Function which derives a flavor of 'FromJSON'.
1288+ -> Options
1289+ -- ^ Encoding options.
1290+ -> Name
1291+ -- ^ Name of the type for which to generate 'ToJSON' and 'FromJSON'
1292+ -- instances.
1293+ -> Q [Dec]
1294+deriveJSONBoth dtj dfj opts name =
1295+ liftM2 (++) (dtj opts name) (dfj opts name)
1296+
1297+-- | Functionality common to @deriveToJSON(1)(2)@ and @deriveFromJSON(1)(2)@.
1298+deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Con] -> Q Exp)]
1299+ -- ^ The class methods and the functions which derive them.
1300+ -> JSONClass
1301+ -- ^ The class for which to generate an instance.
1302+ -> Options
1303+ -- ^ Encoding options.
1304+ -> Name
1305+ -- ^ Name of the type for which to generate a class instance
1306+ -- declaration.
1307+ -> Q [Dec]
1308+deriveJSONClass consFuns jc opts name =
1309+ withType name $ \name' ctxt tvbs cons mbTys ->
1310+ fmap (:[]) $ fromCons name' ctxt tvbs cons mbTys
1311+ where
1312+ fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec
1313+ fromCons name' ctxt tvbs cons mbTys = do
1314+ (instanceCxt, instanceType)
1315+ <- buildTypeInstance name' jc ctxt tvbs mbTys
1316+ instanceD (return instanceCxt)
1317+ (return instanceType)
1318+ (methodDecs name' cons)
1319+
1320+ methodDecs :: Name -> [Con] -> [Q Dec]
1321+ methodDecs name' cons = flip map consFuns $ \(jf, jfMaker) ->
1322+ funD (jsonFunValName jf (arity jc))
1323+ [ clause []
1324+ (normalB $ jfMaker jc name' opts cons)
1325+ []
1326+ ]
1327+
1328+mkFunCommon :: (JSONClass -> Name -> Options -> [Con] -> Q Exp)
1329+ -- ^ The function which derives the expression.
1330+ -> JSONClass
1331+ -- ^ Which class's method is being derived.
1332+ -> Options
1333+ -- ^ Encoding options.
1334+ -> Name
1335+ -- ^ Name of the encoded type.
1336+ -> Q Exp
1337+mkFunCommon consFun jc opts name = withType name fromCons
1338+ where
1339+ fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Exp
1340+ fromCons name' ctxt tvbs cons mbTys = do
1341+ -- We force buildTypeInstance here since it performs some checks for whether
1342+ -- or not the provided datatype's kind matches the derived method's
1343+ -- typeclass, and produces errors if it can't.
1344+ !_ <- buildTypeInstance name' jc ctxt tvbs mbTys
1345+ consFun jc name' opts cons
1346+
1347+dispatchFunByType :: JSONClass
1348+ -> JSONFun
1349+ -> Name
1350+ -> TyVarMap
1351+ -> Bool -- True if we are using the function argument that works
1352+ -- on lists (e.g., [a] -> Value). False is we are using
1353+ -- the function argument that works on single values
1354+ -- (e.g., a -> Value).
1355+ -> Type
1356+ -> Q Exp
1357+dispatchFunByType _ jf _ tvMap list (VarT tyName) =
1358+ varE $ case M.lookup tyName tvMap of
1359+ Just (tfjExp, tfjlExp) -> if list then tfjlExp else tfjExp
1360+ Nothing -> jsonFunValOrListName list jf Arity0
1361+dispatchFunByType jc jf conName tvMap list (SigT ty _) =
1362+ dispatchFunByType jc jf conName tvMap list ty
1363+dispatchFunByType jc jf conName tvMap list (ForallT _ _ ty) =
1364+ dispatchFunByType jc jf conName tvMap list ty
1365+dispatchFunByType jc jf conName tvMap list ty = do
1366+ let tyCon :: Type
1367+ tyArgs :: [Type]
1368+ tyCon :| tyArgs = unapplyTy ty
1369+
1370+ numLastArgs :: Int
1371+ numLastArgs = min (arityInt jc) (length tyArgs)
1372+
1373+ lhsArgs, rhsArgs :: [Type]
1374+ (lhsArgs, rhsArgs) = splitAt (length tyArgs - numLastArgs) tyArgs
1375+
1376+ tyVarNames :: [Name]
1377+ tyVarNames = M.keys tvMap
1378+
1379+ itf <- isTyFamily tyCon
1380+ if any (`mentionsName` tyVarNames) lhsArgs
1381+ || itf && any (`mentionsName` tyVarNames) tyArgs
1382+ then outOfPlaceTyVarError jc conName
1383+ else appsE $ [ varE . jsonFunValOrListName list jf $ toEnum numLastArgs]
1384+ ++ zipWith (dispatchFunByType jc jf conName tvMap)
1385+ (cycle [False,True])
1386+ (interleave rhsArgs rhsArgs)
1387+
1388+dispatchToJSON, dispatchToEncoding, dispatchParseJSON
1389+ :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1390+dispatchToJSON jc n tvMap = dispatchFunByType jc ToJSON n tvMap False
1391+dispatchToEncoding jc n tvMap = dispatchFunByType jc ToEncoding n tvMap False
1392+dispatchParseJSON jc n tvMap = dispatchFunByType jc ParseJSON n tvMap False
10661393
10671394--------------------------------------------------------------------------------
10681395-- Utility functions
@@ -1077,12 +1404,13 @@ parseTypeMismatch' conName tName expected actual =
10771404
10781405-- Any other value will result in an exception.
10791406withType :: Name
1080− -> (Name -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q a)
1407+ -> (Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q a)
10811408 -- ^ Function that generates the actual code. Will be applied
1082− -- to the datatype/data family 'Name', type variable binders and
1083− -- constructors extracted from the given 'Name'. If the 'Name' is
1084− -- from a data family instance constructor, it will also have its
1085− -- instantiated types; otherwise, it will be 'Nothing'.
1409+ -- to the datatype/data family 'Name', datatype context, type
1410+ -- variable binders and constructors extracted from the given
1411+ -- 'Name'. If the 'Name' is from a data family instance
1412+ -- constructor, it will also have its instantiated types;
1413+ -- otherwise, it will be 'Nothing'.
10861414 -> Q a
10871415 -- ^ Resulting value in the 'Q'uasi monad.
10881416withType name f = do
@@ -1091,13 +1419,13 @@ withType name f = do
10911419 TyConI dec ->
10921420 case dec of
10931421#if MIN_VERSION_template_haskell(2,11,0)
1094− DataD _ _ tvbs _ cons _ -> f name tvbs cons Nothing
1095− NewtypeD _ _ tvbs _ con _ -> f name tvbs [con] Nothing
1422+ DataD ctxt _ tvbs _ cons _ -> f name ctxt tvbs cons Nothing
1423+ NewtypeD ctxt _ tvbs _ con _ -> f name ctxt tvbs [con] Nothing
10961424#else
1097− DataD _ _ tvbs cons _ -> f name tvbs cons Nothing
1098− NewtypeD _ _ tvbs con _ -> f name tvbs [con] Nothing
1425+ DataD ctxt _ tvbs cons _ -> f name ctxt tvbs cons Nothing
1426+ NewtypeD ctxt _ tvbs con _ -> f name ctxt tvbs [con] Nothing
10991427#endif
1100− other -> error $ ns ++ "Unsupported type: " ++ show other
1428+ other -> fail $ ns ++ "Unsupported type: " ++ show other
11011429#if MIN_VERSION_template_haskell(2,11,0)
11021430 DataConI _ _ parentName -> do
11031431#else
@@ -1121,24 +1449,24 @@ withType name f = do
11211449 _ -> error $ ns ++ "Must be a data or newtype instance."
11221450 in case instDec of
11231451#if MIN_VERSION_template_haskell(2,11,0)
1124− Just (DataInstD _ _ instTys _ cons _) -> f parentName tvbs cons $ Just instTys
1125− Just (NewtypeInstD _ _ instTys _ con _) -> f parentName tvbs [con] $ Just instTys
1452+ Just (DataInstD ctxt _ instTys _ cons _) -> f parentName ctxt tvbs cons $ Just instTys
1453+ Just (NewtypeInstD ctxt _ instTys _ con _) -> f parentName ctxt tvbs [con] $ Just instTys
11261454#else
1127− Just (DataInstD _ _ instTys cons _) -> f parentName tvbs cons $ Just instTys
1128− Just (NewtypeInstD _ _ instTys con _) -> f parentName tvbs [con] $ Just instTys
1455+ Just (DataInstD ctxt _ instTys cons _) -> f parentName ctxt tvbs cons $ Just instTys
1456+ Just (NewtypeInstD ctxt _ instTys con _) -> f parentName ctxt tvbs [con] $ Just instTys
11291457#endif
1130− _ -> error $ ns ++
1458+ _ -> fail $ ns ++
11311459 "Could not find data or newtype instance constructor."
1132− _ -> error $ ns ++ "Data constructor " ++ show name ++
1460+ _ -> fail $ ns ++ "Data constructor " ++ show name ++
11331461 " is not from a data family instance constructor."
11341462#if MIN_VERSION_template_haskell(2,11,0)
11351463 FamilyI DataFamilyD{} _ ->
11361464#else
11371465 FamilyI (FamilyD DataFam _ _ _) _ ->
11381466#endif
1139− error $ ns ++
1467+ fail $ ns ++
11401468 "Cannot use a data family name. Use a data family instance constructor instead."
1141− _ -> error $ ns ++ "I need the name of a plain data type constructor, "
1469+ _ -> fail $ ns ++ "I need the name of a plain data type constructor, "
11421470 ++ "or a data family instance constructor."
11431471 where
11441472 ns :: String
@@ -1147,8 +1475,10 @@ withType name f = do
11471475-- | Infer the context and instance head needed for a FromJSON or ToJSON instance.
11481476buildTypeInstance :: Name
11491477 -- ^ The type constructor or data family name
1150− -> Name
1151− -- ^ The typeclass name ('ToJSON' or 'FromJSON')
1478+ -> JSONClass
1479+ -- ^ The typeclass to derive
1480+ -> Cxt
1481+ -- ^ The datatype context
11521482 -> [TyVarBndr]
11531483 -- ^ The type variables from the data type/data family declaration
11541484 -> Maybe [Type]
@@ -1157,15 +1487,15 @@ buildTypeInstance :: Name
11571487 -> Q (Cxt, Type)
11581488 -- ^ The resulting 'Cxt' and 'Type' to use in a class instance
11591489-- Plain data type/newtype case
1160−buildTypeInstance tyConName constraint tvbs Nothing =
1490+buildTypeInstance tyConName jc dataCxt tvbs Nothing =
11611491 let varTys :: [Type]
11621492 varTys = map tvbToType tvbs
1163− in buildTypeInstanceFromTys tyConName constraint varTys False
1493+ in buildTypeInstanceFromTys tyConName jc dataCxt varTys False
11641494-- Data family instance case
11651495--
11661496-- The CPP is present to work around a couple of annoying old GHC bugs.
11671497-- See Note [Polykinded data families in Template Haskell]
1168−buildTypeInstance dataFamName constraint tvbs (Just instTysAndKinds) = do
1498+buildTypeInstance dataFamName jc dataCxt tvbs (Just instTysAndKinds) = do
11691499#if !(MIN_VERSION_template_haskell(2,8,0)) || MIN_VERSION_template_haskell(2,10,0)
11701500 let instTys :: [Type]
11711501 instTys = zipWith stealKindForType tvbs instTysAndKinds
@@ -1173,16 +1503,6 @@ buildTypeInstance dataFamName constraint tvbs (Just instTysAndKinds) = do
11731503 let kindVarNames :: [Name]
11741504 kindVarNames = nub $ concatMap (tyVarNamesOfType . tvbKind) tvbs
11751505
1176− -- Gets all of the type/kind variable names mentioned somewhere in a Type.
1177− tyVarNamesOfType :: Type -> [Name]
1178− tyVarNamesOfType = go
1179− where
1180− go :: Type -> [Name]
1181− go (AppT t1 t2) = go t1 ++ go t2
1182− go (SigT t k) = go t ++ go k
1183− go (VarT n) = [n]
1184− go _ = []
1185−
11861506 numKindVars :: Int
11871507 numKindVars = length kindVarNames
11881508
@@ -1208,10 +1528,6 @@ buildTypeInstance dataFamName constraint tvbs (Just instTysAndKinds) = do
12081528 starKindName :: Name
12091529 starKindName = mkNameG_tc "ghc-prim" "GHC.Prim" "*"
12101530
1211− -- Generate a list of fresh names with a common prefix, and numbered suffixes.
1212− newNameList :: String -> Int -> Q [Name]
1213− newNameList prefix n = mapM (newName . (prefix ++) . show) [1..n]
1214−
12151531 -- If we run this code with GHC 7.8, we might have to generate extra type
12161532 -- variables to compensate for any type variables that Template Haskell
12171533 -- eta-reduced away.
@@ -1225,9 +1541,6 @@ buildTypeInstance dataFamName constraint tvbs (Just instTysAndKinds) = do
12251541 -- them as VarT to ensure they will be given an explicit kind annotation
12261542 -- (and so the kind inference machinery has the right information).
12271543
1228− substNameWithKind :: Name -> Kind -> Type -> Type
1229− substNameWithKind n k = substType (M.singleton n k)
1230−
12311544 substNamesWithKinds :: [(Name, Kind)] -> Type -> Type
12321545 substNamesWithKinds nks t = foldr' (uncurry substNameWithKind) t nks
12331546
@@ -1246,50 +1559,147 @@ buildTypeInstance dataFamName constraint tvbs (Just instTysAndKinds) = do
12461559 -- grab the correct kind.
12471560 $ zipWith stealKindForType tvbs (givenTys ++ xTys)
12481561#endif
1249− buildTypeInstanceFromTys dataFamName constraint instTys True
1562+ buildTypeInstanceFromTys dataFamName jc dataCxt instTys True
12501563
12511564-- For the given Types, generate an instance context and head.
12521565buildTypeInstanceFromTys :: Name
12531566 -- ^ The type constructor or data family name
1254− -> Name
1255− -- ^ The typeclass name ('ToJSON' or 'FromJSON')
1567+ -> JSONClass
1568+ -- ^ The typeclass to derive
1569+ -> Cxt
1570+ -- ^ The datatype context
12561571 -> [Type]
12571572 -- ^ The types to instantiate the instance with
12581573 -> Bool
12591574 -- ^ True if it's a data family, False otherwise
12601575 -> Q (Cxt, Type)
1261−buildTypeInstanceFromTys tyConName constraint varTysOrig isDataFamily = do
1262− -- Make sure to expand through type/kind synonyms! Otherwise, we won't
1263− -- be able to infer constraints as accurately.
1576+buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
1577+ -- Make sure to expand through type/kind synonyms! Otherwise, the
1578+ -- eta-reduction check might get tripped up over type variables in a
1579+ -- synonym that are actually dropped.
1580+ -- (See GHC Trac #11416 for a scenario where this actually happened.)
12641581 varTysExp <- mapM expandSyn varTysOrig
12651582
1266− let preds :: [Maybe Pred]
1267− -- Derive instance constraints for type variables of kind *
1268− preds = map (deriveConstraint constraint) varTysExp
1583+ let remainingLength :: Int
1584+ remainingLength = length varTysOrig - arityInt jc
1585+
1586+ droppedTysExp :: [Type]
1587+ droppedTysExp = drop remainingLength varTysExp
1588+
1589+ droppedStarKindStati :: [StarKindStatus]
1590+ droppedStarKindStati = map canRealizeKindStar droppedTysExp
1591+
1592+ -- Check there are enough types to drop and that all of them are either of
1593+ -- kind * or kind k (for some kind variable k). If not, throw an error.
1594+ when (remainingLength < 0 || any (== NotKindStar) droppedStarKindStati) $
1595+ derivingKindError jc tyConName
1596+
1597+ let droppedKindVarNames :: [Name]
1598+ droppedKindVarNames = catKindVarNames droppedStarKindStati
1599+
1600+ -- Substitute kind * for any dropped kind variables
1601+ varTysExpSubst :: [Type]
1602+ varTysExpSubst = map (substNamesWithKindStar droppedKindVarNames) varTysExp
1603+
1604+ remainingTysExpSubst, droppedTysExpSubst :: [Type]
1605+ (remainingTysExpSubst, droppedTysExpSubst) =
1606+ splitAt remainingLength varTysExpSubst
12691607
1270− varTys :: [Type]
1608+ -- All of the type variables mentioned in the dropped types
1609+ -- (post-synonym expansion)
1610+ droppedTyVarNames :: [Name]
1611+ droppedTyVarNames = concatMap tyVarNamesOfType droppedTysExpSubst
1612+
1613+ -- If any of the dropped types were polykinded, ensure that they are of kind *
1614+ -- after substituting * for the dropped kind variables. If not, throw an error.
1615+ unless (all hasKindStar droppedTysExpSubst) $
1616+ derivingKindError jc tyConName
1617+
1618+ let preds :: [Maybe Pred]
1619+ kvNames :: [[Name]]
1620+ kvNames' :: [Name]
1621+ -- Derive instance constraints (and any kind variables which are specialized
1622+ -- to * in those constraints)
1623+ (preds, kvNames) = unzip $ map (deriveConstraint jc) remainingTysExpSubst
1624+ kvNames' = concat kvNames
1625+
1626+ -- Substitute the kind variables specialized in the constraints with *
1627+ remainingTysExpSubst' :: [Type]
1628+ remainingTysExpSubst' =
1629+ map (substNamesWithKindStar kvNames') remainingTysExpSubst
1630+
1631+ -- We now substitute all of the specialized-to-* kind variable names with
1632+ -- *, but in the original types, not the synonym-expanded types. The reason
1633+ -- we do this is a superficial one: we want the derived instance to resemble
1634+ -- the datatype written in source code as closely as possible. For example,
1635+ -- for the following data family instance:
1636+ --
1637+ -- data family Fam a
1638+ -- newtype instance Fam String = Fam String
1639+ --
1640+ -- We'd want to generate the instance:
1641+ --
1642+ -- instance C (Fam String)
1643+ --
1644+ -- Not:
1645+ --
1646+ -- instance C (Fam [Char])
1647+ remainingTysOrigSubst :: [Type]
1648+ remainingTysOrigSubst =
1649+ map (substNamesWithKindStar (union droppedKindVarNames kvNames'))
1650+ $ take remainingLength varTysOrig
1651+
1652+ remainingTysOrigSubst' :: [Type]
12711653 -- See Note [Kind signatures in derived instances] for an explanation
12721654 -- of the isDataFamily check.
1273− varTys =
1655+ remainingTysOrigSubst' =
12741656 if isDataFamily
1275− then varTysOrig
1276− else map unSigT varTysOrig
1657+ then remainingTysOrigSubst
1658+ else map unSigT remainingTysOrigSubst
12771659
12781660 instanceCxt :: Cxt
12791661 instanceCxt = catMaybes preds
12801662
12811663 instanceType :: Type
1282− instanceType = AppT (ConT constraint)
1283− $ applyTyCon tyConName varTys
1284−
1664+ instanceType = AppT (ConT $ jsonClassName jc)
1665+ $ applyTyCon tyConName remainingTysOrigSubst'
1666+
1667+ -- If the datatype context mentions any of the dropped type variables,
1668+ -- we can't derive an instance, so throw an error.
1669+ when (any (`predMentionsName` droppedTyVarNames) dataCxt) $
1670+ datatypeContextError tyConName instanceType
1671+ -- Also ensure the dropped types can be safely eta-reduced. Otherwise,
1672+ -- throw an error.
1673+ unless (canEtaReduce remainingTysExpSubst' droppedTysExpSubst) $
1674+ etaReductionError instanceType
12851675 return (instanceCxt, instanceType)
12861676
1287−-- | Attempt to derive a constraint on a Type. If it's of kind *,
1288−-- we give it Just a ToJSON/FromJSON constraint. Otherwise, return Nothing.
1289−deriveConstraint :: Name -> Type -> Maybe Pred
1290−deriveConstraint constraint t
1291− | isTyVar t && hasKindStar t = Just $ applyCon constraint $ varTToName t
1292− | otherwise = Nothing
1677+-- | Attempt to derive a constraint on a Type. If successful, return
1678+-- Just the constraint and any kind variable names constrained to *.
1679+-- Otherwise, return Nothing and the empty list.
1680+--
1681+-- See Note [Type inference in derived instances] for the heuristics used to
1682+-- come up with constraints.
1683+deriveConstraint :: JSONClass -> Type -> (Maybe Pred, [Name])
1684+deriveConstraint jc t
1685+ | not (isTyVar t) = (Nothing, [])
1686+ | hasKindStar t = (Just (applyCon (jcConstraint Arity0) tName), [])
1687+ | otherwise = case hasKindVarChain 1 t of
1688+ Just ns | jcArity >= Arity1
1689+ -> (Just (applyCon (jcConstraint Arity1) tName), ns)
1690+ _ -> case hasKindVarChain 2 t of
1691+ Just ns | jcArity == Arity2
1692+ -> (Just (applyCon (jcConstraint Arity2) tName), ns)
1693+ _ -> (Nothing, [])
1694+ where
1695+ tName :: Name
1696+ tName = varTToName t
1697+
1698+ jcArity :: Arity
1699+ jcArity = arity jc
1700+
1701+ jcConstraint :: Arity -> Name
1702+ jcConstraint = jsonClassName . JSONClass (direction jc)
12931703
12941704{-
12951705Note [Polykinded data families in Template Haskell]
@@ -1372,8 +1782,135 @@ knowing which instance we are talking about. To avoid this scenario, we always
13721782include explicit kind signatures in data family instances. There is a chance that
13731783the inferred kind signatures will be incorrect, but if so, we can always fall back
13741784on the mk- functions.
1785+
1786+Note [Type inference in derived instances]
1787+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1788+
1789+Type inference is can be tricky to get right, and we want to avoid recreating the
1790+entirety of GHC's type inferencer in Template Haskell. For this reason, we will
1791+probably never come up with derived instance contexts that are as accurate as
1792+GHC's. But that doesn't mean we can't do anything! There are a couple of simple
1793+things we can do to make instance contexts that work for 80% of use cases:
1794+
1795+1. If one of the last type parameters is polykinded, then its kind will be
1796+ specialized to * in the derived instance. We note what kind variable the type
1797+ parameter had and substitute it with * in the other types as well. For example,
1798+ imagine you had
1799+
1800+ data Data (a :: k) (b :: k)
1801+
1802+ Then you'd want to derived instance to be:
1803+
1804+ instance C (Data (a :: *))
1805+
1806+ Not:
1807+
1808+ instance C (Data (a :: k))
1809+
1810+2. We naïvely come up with instance constraints using the following criteria:
1811+
1812+ (i) If there's a type parameter n of kind *, generate a ToJSON n/FromJSON n
1813+ constraint.
1814+ (ii) If there's a type parameter n of kind k1 -> k2 (where k1/k2 are * or kind
1815+ variables), then generate a ToJSON1 n/FromJSON1 n constraint, and if
1816+ k1/k2 are kind variables, then substitute k1/k2 with * elsewhere in the
1817+ types. We must consider the case where they are kind variables because
1818+ you might have a scenario like this:
1819+
1820+ newtype Compose (f :: k2 -> *) (g :: k1 -> k2) (a :: k1)
1821+ = Compose (f (g a))
1822+
1823+ Which would have a derived ToJSON1 instance of:
1824+
1825+ instance (ToJSON1 f, ToJSON1 g) => ToJSON1 (Compose f g) where ...
1826+ (iii) If there's a type parameter n of kind k1 -> k2 -> k3 (where k1/k2/k3 are
1827+ * or kind variables), then generate a ToJSON2 n/FromJSON2 n constraint
1828+ and perform kind substitution as in the other cases.
13751829-}
13761830
1831+-- Determines the types of a constructor's arguments as well as the last type
1832+-- parameters (mapped to their encoding/decoding functions), expanding through
1833+-- any type synonyms.
1834+--
1835+-- The type parameters are determined on a constructor-by-constructor basis since
1836+-- they may be refined to be particular types in a GADT.
1837+reifyConTys :: JSONClass
1838+ -> [(Name, Name)]
1839+ -> Name
1840+ -> Q ([Type], TyVarMap)
1841+reifyConTys jc tpjs conName = do
1842+ info <- reify conName
1843+ (ctxt, uncTy) <- case info of
1844+ DataConI _ ty _
1845+#if !(MIN_VERSION_template_haskell(2,11,0))
1846+ _
1847+#endif
1848+ -> fmap uncurryTy (expandSyn ty)
1849+ _ -> error "Must be a data constructor"
1850+ let (argTys, [resTy]) = NE.splitAt (NE.length uncTy - 1) uncTy
1851+ unapResTy = unapplyTy resTy
1852+ -- If one of the last type variables is refined to a particular type
1853+ -- (i.e., not truly polymorphic), we mark it with Nothing and filter
1854+ -- it out later, since we only apply encoding/decoding functions to
1855+ -- arguments of a type that it (1) one of the last type variables,
1856+ -- and (2) of a truly polymorphic type.
1857+ jArity = arityInt jc
1858+ mbTvNames = map varTToName_maybe $
1859+ NE.drop (NE.length unapResTy - jArity) unapResTy
1860+ -- We use M.fromList to ensure that if there are any duplicate type
1861+ -- variables (as can happen in a GADT), the rightmost type variable gets
1862+ -- associated with the show function.
1863+ --
1864+ -- See Note [Matching functions with GADT type variables]
1865+ tvMap = M.fromList
1866+ . catMaybes -- Drop refined types
1867+ $ zipWith (\mbTvName tpj ->
1868+ fmap (\tvName -> (tvName, tpj)) mbTvName)
1869+ mbTvNames tpjs
1870+ if (any (`predMentionsName` M.keys tvMap) ctxt
1871+ || M.size tvMap < jArity)
1872+ && not (allowExQuant jc)
1873+ then existentialContextError conName
1874+ else return (argTys, tvMap)
1875+
1876+{-
1877+Note [Matching functions with GADT type variables]
1878+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1879+
1880+When deriving ToJSON2, there is a tricky corner case to consider:
1881+
1882+ data Both a b where
1883+ BothCon :: x -> x -> Both x x
1884+
1885+Which encoding functions should be applied to which arguments of BothCon?
1886+We have a choice, since both the function of type (a -> Value) and of type
1887+(b -> Value) can be applied to either argument. In such a scenario, the
1888+second encoding function takes precedence over the first encoding function, so the
1889+derived ToJSON2 instance would be something like:
1890+
1891+ instance ToJSON2 Both where
1892+ liftToJSON2 tj1 tj2 p (BothCon x1 x2) = Array $ create $ do
1893+ mv <- unsafeNew 2
1894+ unsafeWrite mv 0 (tj1 x1)
1895+ unsafeWrite mv 1 (tj2 x2)
1896+ return mv
1897+
1898+This is not an arbitrary choice, as this definition ensures that
1899+liftToJSON2 toJSON = liftToJSON for a derived ToJSON1 instance for
1900+Both.
1901+-}
1902+
1903+-- A mapping of type variable Names to their encoding/decoding function Names.
1904+-- For example, in a ToJSON2 declaration, a TyVarMap might look like
1905+--
1906+-- { a ~> (tj1, tjl1)
1907+-- , b ~> (tj2, tjl2) }
1908+--
1909+-- where a and b are the last two type variables of the datatype, tj1 and tjl1 are
1910+-- the function arguments of types (a -> Value) and ([a] -> Value), and tj2 and tjl2
1911+-- are the function arguments of types (b -> Value) and ([b] -> Value).
1912+type TyVarMap = Map Name (Name, Name)
1913+
13771914-- | If a VarT is missing an explicit kind signature, steal it from a TyVarBndr.
13781915stealKindForType :: TyVarBndr -> Type -> Type
13791916stealKindForType tvb t@VarT{} = SigT t (tvbKind tvb)
@@ -1402,12 +1939,67 @@ hasKindStar (SigT _ StarK) = True
14021939#endif
14031940hasKindStar _ = False
14041941
1942+-- Returns True is a kind is equal to *, or if it is a kind variable.
1943+isStarOrVar :: Kind -> Bool
1944+#if MIN_VERSION_template_haskell(2,8,0)
1945+isStarOrVar StarT = True
1946+isStarOrVar VarT{} = True
1947+#else
1948+isStarOrVar StarK = True
1949+#endif
1950+isStarOrVar _ = False
1951+
1952+-- Generate a list of fresh names with a common prefix, and numbered suffixes.
1953+newNameList :: String -> Int -> Q [Name]
1954+newNameList prefix len = mapM newName [prefix ++ show n | n <- [1..len]]
1955+
1956+-- Gets all of the type/kind variable names mentioned somewhere in a Type.
1957+tyVarNamesOfType :: Type -> [Name]
1958+tyVarNamesOfType = go
1959+ where
1960+ go :: Type -> [Name]
1961+ go (AppT t1 t2) = go t1 ++ go t2
1962+ go (SigT t _k) = go t
1963+#if MIN_VERSION_template_haskell(2,8,0)
1964+ ++ go _k
1965+#endif
1966+ go (VarT n) = [n]
1967+ go _ = []
1968+
1969+-- | Gets all of the type/kind variable names mentioned somewhere in a Kind.
1970+tyVarNamesOfKind :: Kind -> [Name]
1971+#if MIN_VERSION_template_haskell(2,8,0)
1972+tyVarNamesOfKind = tyVarNamesOfType
1973+#else
1974+tyVarNamesOfKind _ = [] -- There are no kind variables
1975+#endif
1976+
1977+-- | @hasKindVarChain n kind@ Checks if @kind@ is of the form
1978+-- k_0 -> k_1 -> ... -> k_(n-1), where k0, k1, ..., and k_(n-1) can be * or
1979+-- kind variables.
1980+hasKindVarChain :: Int -> Type -> Maybe [Name]
1981+hasKindVarChain kindArrows t =
1982+ let uk = uncurryKind (tyKind t)
1983+ in if (NE.length uk - 1 == kindArrows) && F.all isStarOrVar uk
1984+ then Just (concatMap tyVarNamesOfKind uk)
1985+ else Nothing
1986+
1987+-- | If a Type is a SigT, returns its kind signature. Otherwise, return *.
1988+tyKind :: Type -> Kind
1989+tyKind (SigT _ k) = k
1990+tyKind _ = starK
1991+
1992+-- | Extract Just the Name from a type variable. If the argument Type is not a
1993+-- type variable, return Nothing.
1994+varTToName_maybe :: Type -> Maybe Name
1995+varTToName_maybe (VarT n) = Just n
1996+varTToName_maybe (SigT t _) = varTToName_maybe t
1997+varTToName_maybe _ = Nothing
1998+
14051999-- | Extract the Name from a type variable. If the argument Type is not a
14062000-- type variable, throw an error.
14072001varTToName :: Type -> Name
1408−varTToName (VarT n) = n
1409−varTToName (SigT t _) = varTToName t
1410−varTToName _ = error "Not a type variable!"
2002+varTToName = fromMaybe (error "Not a type variable!") . varTToName_maybe
14112003
14122004-- | Extracts the name from a constructor.
14132005getConName :: Con -> Name
@@ -1420,6 +2012,10 @@ getConName (GadtC names _ _) = head names
14202012getConName (RecGadtC names _ _) = head names
14212013#endif
14222014
2015+interleave :: [a] -> [a] -> [a]
2016+interleave (a1:a1s) (a2:a2s) = a1:a2:interleave a1s a2s
2017+interleave _ _ = []
2018+
14232019-- | Fully applies a type constructor to its type variables.
14242020applyTyCon :: Name -> [Type] -> Type
14252021applyTyCon = foldl' AppT . ConT
@@ -1430,11 +2026,122 @@ isTyVar (VarT _) = True
14302026isTyVar (SigT t _) = isTyVar t
14312027isTyVar _ = False
14322028
2029+-- | Is the given type a type family constructor (and not a data family constructor)?
2030+isTyFamily :: Type -> Q Bool
2031+isTyFamily (ConT n) = do
2032+ info <- reify n
2033+ return $ case info of
2034+#if MIN_VERSION_template_haskell(2,11,0)
2035+ FamilyI OpenTypeFamilyD{} _ -> True
2036+#else
2037+ FamilyI (FamilyD TypeFam _ _ _) _ -> True
2038+#endif
2039+#if MIN_VERSION_template_haskell(2,9,0)
2040+ FamilyI ClosedTypeFamilyD{} _ -> True
2041+#endif
2042+ _ -> False
2043+isTyFamily _ = return False
2044+
14332045-- | Peel off a kind signature from a Type (if it has one).
14342046unSigT :: Type -> Type
14352047unSigT (SigT t _) = t
14362048unSigT t = t
14372049
2050+-- | Are all of the items in a list (which have an ordering) distinct?
2051+--
2052+-- This uses Set (as opposed to nub) for better asymptotic time complexity.
2053+allDistinct :: Ord a => [a] -> Bool
2054+allDistinct = allDistinct' Set.empty
2055+ where
2056+ allDistinct' :: Ord a => Set a -> [a] -> Bool
2057+ allDistinct' uniqs (x:xs)
2058+ | x `Set.member` uniqs = False
2059+ | otherwise = allDistinct' (Set.insert x uniqs) xs
2060+ allDistinct' _ _ = True
2061+
2062+-- | Does the given type mention any of the Names in the list?
2063+mentionsName :: Type -> [Name] -> Bool
2064+mentionsName = go
2065+ where
2066+ go :: Type -> [Name] -> Bool
2067+ go (AppT t1 t2) names = go t1 names || go t2 names
2068+ go (SigT t _k) names = go t names
2069+#if MIN_VERSION_template_haskell(2,8,0)
2070+ || go _k names
2071+#endif
2072+ go (VarT n) names = n `elem` names
2073+ go _ _ = False
2074+
2075+-- | Does an instance predicate mention any of the Names in the list?
2076+predMentionsName :: Pred -> [Name] -> Bool
2077+#if MIN_VERSION_template_haskell(2,10,0)
2078+predMentionsName = mentionsName
2079+#else
2080+predMentionsName (ClassP n tys) names = n `elem` names || any (`mentionsName` names) tys
2081+predMentionsName (EqualP t1 t2) names = mentionsName t1 names || mentionsName t2 names
2082+#endif
2083+
2084+-- | Split an applied type into its individual components. For example, this:
2085+--
2086+-- @
2087+-- Either Int Char
2088+-- @
2089+--
2090+-- would split to this:
2091+--
2092+-- @
2093+-- [Either, Int, Char]
2094+-- @
2095+unapplyTy :: Type -> NonEmpty Type
2096+unapplyTy = NE.reverse . go
2097+ where
2098+ go :: Type -> NonEmpty Type
2099+ go (AppT t1 t2) = t2 <| go t1
2100+ go (SigT t _) = go t
2101+ go (ForallT _ _ t) = go t
2102+ go t = t :| []
2103+
2104+-- | Split a type signature by the arrows on its spine. For example, this:
2105+--
2106+-- @
2107+-- forall a b. (a ~ b) => (a -> b) -> Char -> ()
2108+-- @
2109+--
2110+-- would split to this:
2111+--
2112+-- @
2113+-- (a ~ b, [a -> b, Char, ()])
2114+-- @
2115+uncurryTy :: Type -> (Cxt, NonEmpty Type)
2116+uncurryTy (AppT (AppT ArrowT t1) t2) =
2117+ let (ctxt, tys) = uncurryTy t2
2118+ in (ctxt, t1 <| tys)
2119+uncurryTy (SigT t _) = uncurryTy t
2120+uncurryTy (ForallT _ ctxt t) =
2121+ let (ctxt', tys) = uncurryTy t
2122+ in (ctxt ++ ctxt', tys)
2123+uncurryTy t = ([], t :| [])
2124+
2125+-- | Like uncurryType, except on a kind level.
2126+uncurryKind :: Kind -> NonEmpty Kind
2127+#if MIN_VERSION_template_haskell(2,8,0)
2128+uncurryKind = snd . uncurryTy
2129+#else
2130+uncurryKind (ArrowK k1 k2) = k1 <| uncurryKind k2
2131+uncurryKind k = k :| []
2132+#endif
2133+
2134+createKindChain :: Int -> Kind
2135+createKindChain = go starK
2136+ where
2137+ go :: Kind -> Int -> Kind
2138+ go k !0 = k
2139+#if MIN_VERSION_template_haskell(2,8,0)
2140+ go k !n = go (AppT (AppT ArrowT StarT) k) (n - 1)
2141+#else
2142+ go k !n = go (ArrowK StarK k) (n - 1)
2143+#endif
2144+
14382145-- | Makes a string literal expression from a constructor's name.
14392146conNameExp :: Options -> Con -> Q Exp
14402147conNameExp opts = litE
@@ -1466,6 +2173,22 @@ applyCon con t =
14662173 ClassP con [VarT t]
14672174#endif
14682175
2176+-- | Checks to see if the last types in a data family instance can be safely eta-
2177+-- reduced (i.e., dropped), given the other types. This checks for three conditions:
2178+--
2179+-- (1) All of the dropped types are type variables
2180+-- (2) All of the dropped types are distinct
2181+-- (3) None of the remaining types mention any of the dropped types
2182+canEtaReduce :: [Type] -> [Type] -> Bool
2183+canEtaReduce remaining dropped =
2184+ all isTyVar dropped
2185+ && allDistinct droppedNames -- Make sure not to pass something of type [Type], since Type
2186+ -- didn't have an Ord instance until template-haskell-2.10.0.0
2187+ && not (any (`mentionsName` droppedNames) remaining)
2188+ where
2189+ droppedNames :: [Name]
2190+ droppedNames = map varTToName dropped
2191+
14692192-------------------------------------------------------------------------------
14702193-- Expanding type synonyms
14712194-------------------------------------------------------------------------------
@@ -1507,6 +2230,7 @@ expandSynApp t ts = do
15072230 return $ foldl' AppT t' ts
15082231
15092232type TypeSubst = Map Name Type
2233+type KindSubst = Map Name Kind
15102234
15112235mkSubst :: [TyVarBndr] -> [Type] -> TypeSubst
15122236mkSubst vs ts =
@@ -1526,3 +2250,182 @@ substType subs (SigT t k) = SigT (substType subs t)
15262250 k
15272251#endif
15282252substType _ t = t
2253+
2254+substKind :: KindSubst -> Type -> Type
2255+#if MIN_VERSION_template_haskell(2,8,0)
2256+substKind = substType
2257+#else
2258+substKind _ t = t -- There are no kind variables!
2259+#endif
2260+
2261+substNameWithKind :: Name -> Kind -> Type -> Type
2262+substNameWithKind n k = substKind (M.singleton n k)
2263+
2264+substNamesWithKindStar :: [Name] -> Type -> Type
2265+substNamesWithKindStar ns t = foldr' (flip substNameWithKind starK) t ns
2266+
2267+-------------------------------------------------------------------------------
2268+-- Error messages
2269+-------------------------------------------------------------------------------
2270+
2271+-- | Either the given data type doesn't have enough type variables, or one of
2272+-- the type variables to be eta-reduced cannot realize kind *.
2273+derivingKindError :: JSONClass -> Name -> Q a
2274+derivingKindError jc tyConName = fail
2275+ . showString "Cannot derive well-kinded instance of form ‘"
2276+ . showString className
2277+ . showChar ' '
2278+ . showParen True
2279+ ( showString (nameBase tyConName)
2280+ . showString " ..."
2281+ )
2282+ . showString "‘\n\tClass "
2283+ . showString className
2284+ . showString " expects an argument of kind "
2285+ . showString (pprint . createKindChain $ arityInt jc)
2286+ $ ""
2287+ where
2288+ className :: String
2289+ className = nameBase $ jsonClassName jc
2290+
2291+-- | One of the last type variables cannot be eta-reduced (see the canEtaReduce
2292+-- function for the criteria it would have to meet).
2293+etaReductionError :: Type -> Q a
2294+etaReductionError instanceType = fail $
2295+ "Cannot eta-reduce to an instance of form \n\tinstance (...) => "
2296+ ++ pprint instanceType
2297+
2298+-- | The data type has a DatatypeContext which mentions one of the eta-reduced
2299+-- type variables.
2300+datatypeContextError :: Name -> Type -> Q a
2301+datatypeContextError dataName instanceType = fail
2302+ . showString "Can't make a derived instance of ‘"
2303+ . showString (pprint instanceType)
2304+ . showString "‘:\n\tData type ‘"
2305+ . showString (nameBase dataName)
2306+ . showString "‘ must not have a class context involving the last type argument(s)"
2307+ $ ""
2308+
2309+-- | The data type mentions one of the n eta-reduced type variables in a place other
2310+-- than the last nth positions of a data type in a constructor's field.
2311+outOfPlaceTyVarError :: JSONClass -> Name -> a
2312+outOfPlaceTyVarError jc conName = error
2313+ . showString "Constructor ‘"
2314+ . showString (nameBase conName)
2315+ . showString "‘ must only use its last "
2316+ . shows n
2317+ . showString " type variable(s) within the last "
2318+ . shows n
2319+ . showString " argument(s) of a data type"
2320+ $ ""
2321+ where
2322+ n :: Int
2323+ n = arityInt jc
2324+
2325+-- | The data type has an existential constraint which mentions one of the
2326+-- eta-reduced type variables.
2327+existentialContextError :: Name -> a
2328+existentialContextError conName = error
2329+ . showString "Constructor ‘"
2330+ . showString (nameBase conName)
2331+ . showString "‘ must be truly polymorphic in the last argument(s) of the data type"
2332+ $ ""
2333+
2334+-------------------------------------------------------------------------------
2335+-- Class-specific constants
2336+-------------------------------------------------------------------------------
2337+
2338+-- | A representation of the arity of the ToJSON/FromJSON typeclass being derived.
2339+data Arity = Arity0 | Arity1 | Arity2
2340+ deriving (Enum, Eq, Ord)
2341+
2342+-- | Whether ToJSON(1)(2) or FromJSON(1)(2) is being derived.
2343+data Direction = To | From
2344+
2345+-- | A representation of which typeclass method is being spliced in.
2346+data JSONFun = ToJSON | ToEncoding | ParseJSON
2347+
2348+-- | A representation of which typeclass is being derived.
2349+data JSONClass = JSONClass { direction :: Direction, arity :: Arity }
2350+
2351+toJSONClass, toJSON1Class, toJSON2Class,
2352+ fromJSONClass, fromJSON1Class, fromJSON2Class :: JSONClass
2353+toJSONClass = JSONClass To Arity0
2354+toJSON1Class = JSONClass To Arity1
2355+toJSON2Class = JSONClass To Arity2
2356+fromJSONClass = JSONClass From Arity0
2357+fromJSON1Class = JSONClass From Arity1
2358+fromJSON2Class = JSONClass From Arity2
2359+
2360+jsonClassName :: JSONClass -> Name
2361+jsonClassName (JSONClass To Arity0) = ''ToJSON
2362+jsonClassName (JSONClass To Arity1) = ''ToJSON1
2363+jsonClassName (JSONClass To Arity2) = ''ToJSON2
2364+jsonClassName (JSONClass From Arity0) = ''FromJSON
2365+jsonClassName (JSONClass From Arity1) = ''FromJSON1
2366+jsonClassName (JSONClass From Arity2) = ''FromJSON2
2367+
2368+jsonFunValName :: JSONFun -> Arity -> Name
2369+jsonFunValName ToJSON Arity0 = 'toJSON
2370+jsonFunValName ToJSON Arity1 = 'liftToJSON
2371+jsonFunValName ToJSON Arity2 = 'liftToJSON2
2372+jsonFunValName ToEncoding Arity0 = 'toEncoding
2373+jsonFunValName ToEncoding Arity1 = 'liftToEncoding
2374+jsonFunValName ToEncoding Arity2 = 'liftToEncoding2
2375+jsonFunValName ParseJSON Arity0 = 'parseJSON
2376+jsonFunValName ParseJSON Arity1 = 'liftParseJSON
2377+jsonFunValName ParseJSON Arity2 = 'liftParseJSON2
2378+
2379+jsonFunListName :: JSONFun -> Arity -> Name
2380+jsonFunListName ToJSON Arity0 = 'toJSONList
2381+jsonFunListName ToJSON Arity1 = 'liftToJSONList
2382+jsonFunListName ToJSON Arity2 = 'liftToJSONList2
2383+jsonFunListName ToEncoding Arity0 = 'toEncodingList
2384+jsonFunListName ToEncoding Arity1 = 'liftToEncodingList
2385+jsonFunListName ToEncoding Arity2 = 'liftToEncodingList2
2386+jsonFunListName ParseJSON Arity0 = 'parseJSONList
2387+jsonFunListName ParseJSON Arity1 = 'liftParseJSONList
2388+jsonFunListName ParseJSON Arity2 = 'liftParseJSONList2
2389+
2390+jsonFunValOrListName :: Bool -- e.g., toJSONList if True, toJSON if False
2391+ -> JSONFun -> Arity -> Name
2392+jsonFunValOrListName False = jsonFunValName
2393+jsonFunValOrListName True = jsonFunListName
2394+
2395+arityInt :: JSONClass -> Int
2396+arityInt = fromEnum . arity
2397+
2398+allowExQuant :: JSONClass -> Bool
2399+allowExQuant (JSONClass To _) = True
2400+allowExQuant _ = False
2401+
2402+-------------------------------------------------------------------------------
2403+-- StarKindStatus
2404+-------------------------------------------------------------------------------
2405+
2406+-- | Whether a type is not of kind *, is of kind *, or is a kind variable.
2407+data StarKindStatus = NotKindStar
2408+ | KindStar
2409+ | IsKindVar Name
2410+ deriving Eq
2411+
2412+-- | Does a Type have kind * or k (for some kind variable k)?
2413+canRealizeKindStar :: Type -> StarKindStatus
2414+canRealizeKindStar t
2415+ | hasKindStar t = KindStar
2416+ | otherwise = case t of
2417+#if MIN_VERSION_template_haskell(2,8,0)
2418+ SigT _ (VarT k) -> IsKindVar k
2419+#endif
2420+ _ -> NotKindStar
2421+
2422+-- | Returns 'Just' the kind variable 'Name' of a 'StarKindStatus' if it exists.
2423+-- Otherwise, returns 'Nothing'.
2424+starKindStatusToName :: StarKindStatus -> Maybe Name
2425+starKindStatusToName (IsKindVar n) = Just n
2426+starKindStatusToName _ = Nothing
2427+
2428+-- | Concat together all of the StarKindStatuses that are IsKindVar and extract
2429+-- the kind variables' Names out.
2430+catKindVarNames :: [StarKindStatus] -> [Name]
2431+catKindVarNames = mapMaybe starKindStatusToName
Data/Aeson/Types.hs+5
@@ -61,9 +61,14 @@ module Data.Aeson.Types
6161 , GFromJSON(..)
6262 , GToJSON(..)
6363 , GToEncoding(..)
64+ , Zero
65+ , One
6466 , genericToJSON
67+ , genericLiftToJSON
6568 , genericToEncoding
69+ , genericLiftToEncoding
6670 , genericParseJSON
71+ , genericLiftParseJSON
6772
6873 -- * Inspecting @'Value's@
6974 , withObject
Data/Aeson/Types/Class.hs+16−2
@@ -1,5 +1,13 @@
1−{-# LANGUAGE CPP, GADTs, DefaultSignatures, FlexibleInstances, FlexibleContexts, DeriveFunctor,
2− ScopedTypeVariables, TypeSynonymInstances #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DefaultSignatures #-}
3+{-# LANGUAGE DeriveFunctor #-}
4+{-# LANGUAGE EmptyDataDecls #-}
5+{-# LANGUAGE FlexibleContexts #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE GADTs #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TypeSynonymInstances #-}
311
412-- |
513-- Module: Data.Aeson.Types.Class
@@ -32,9 +40,14 @@ module Data.Aeson.Types.Class
3240 , GFromJSON(..)
3341 , GToJSON(..)
3442 , GToEncoding(..)
43+ , Zero
44+ , One
3545 , genericToJSON
46+ , genericLiftToJSON
3647 , genericToEncoding
48+ , genericLiftToEncoding
3749 , genericParseJSON
50+ , genericLiftParseJSON
3851 -- * Classes and types for map keys
3952 , ToJSONKey(..)
4053 , ToJSONKeyFunction(..)
@@ -72,3 +85,4 @@ module Data.Aeson.Types.Class
7285
7386import Data.Aeson.Types.FromJSON
7487import Data.Aeson.Types.ToJSON
88+import Data.Aeson.Types.Generic (One, Zero)
Data/Aeson/Types/FromJSON.hs+249−122
@@ -34,6 +34,7 @@ module Data.Aeson.Types.FromJSON (
3434 -- * Generic JSON classes
3535 , GFromJSON(..)
3636 , genericParseJSON
37+ , genericLiftParseJSON
3738 -- * Classes and types for map keys
3839 , FromJSONKey(..)
3940 , FromJSONKeyFunction(..)
@@ -60,6 +61,9 @@ module Data.Aeson.Types.FromJSON (
6061 , (.:!)
6162 , (.!=)
6263 , typeMismatch
64+
65+ -- * Internal
66+ , parseOptionalFieldWith
6367 ) where
6468
6569import Prelude ()
@@ -172,21 +176,41 @@ parseIntegral :: Integral a => String -> Value -> Parser a
172176parseIntegral expected = withScientific expected $ pure . truncate
173177{-# INLINE parseIntegral #-}
174178
179+parseOptionalFieldWith :: (Value -> Parser (Maybe a))
180+ -> Object -> Text -> Parser (Maybe a)
181+parseOptionalFieldWith pj obj key =
182+ case H.lookup key obj of
183+ Nothing -> pure Nothing
184+ Just v -> pj v <?> Key key
185+{-# INLINE parseOptionalFieldWith #-}
186+
175187-------------------------------------------------------------------------------
176188-- Generics
177189-------------------------------------------------------------------------------
178190
179−-- | Class of generic representation types ('Rep') that can be converted from JSON.
180−class GFromJSON f where
191+-- | Class of generic representation types that can be converted from JSON.
192+class GFromJSON arity f where
181193 -- | This method (applied to 'defaultOptions') is used as the
182− -- default generic implementation of 'parseJSON'.
183− gParseJSON :: Options -> Value -> Parser (f a)
194+ -- default generic implementation of 'parseJSON' (if the @arity@ is 'Zero')
195+ -- or 'liftParseJSON' (if the @arity@ is 'One').
196+ gParseJSON :: Options -> Proxy arity
197+ -> (Value -> Parser a) -> (Value -> Parser [a])
198+ -> Value -> Parser (f a)
184199
185200-- | A configurable generic JSON decoder. This function applied to
186201-- 'defaultOptions' is used as the default for 'parseJSON' when the
187202-- type is an instance of 'Generic'.
188−genericParseJSON :: (Generic a, GFromJSON (Rep a)) => Options -> Value -> Parser a
189−genericParseJSON opts = fmap to . gParseJSON opts
203+genericParseJSON :: (Generic a, GFromJSON Zero (Rep a))
204+ => Options -> Value -> Parser a
205+genericParseJSON opts = fmap to . gParseJSON opts proxyZero undefined undefined
206+
207+-- | A configurable generic JSON decoder. This function applied to
208+-- 'defaultOptions' is used as the default for 'liftParseJSON' when the
209+-- type is an instance of 'Generic1'.
210+genericLiftParseJSON :: (Generic1 f, GFromJSON One (Rep1 f))
211+ => Options -> (Value -> Parser a) -> (Value -> Parser [a])
212+ -> Value -> Parser (f a)
213+genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts proxyOne pj pjl
190214
191215-------------------------------------------------------------------------------
192216-- Class
@@ -269,7 +293,7 @@ genericParseJSON opts = fmap to . gParseJSON opts
269293class FromJSON a where
270294 parseJSON :: Value -> Parser a
271295
272− default parseJSON :: (Generic a, GFromJSON (Rep a)) => Value -> Parser a
296+ default parseJSON :: (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
273297 parseJSON = genericParseJSON defaultOptions
274298
275299 parseJSONList :: Value -> Parser [a]
@@ -281,7 +305,6 @@ class FromJSON a where
281305
282306 parseJSONList v = typeMismatch "[a]" v
283307
284−
285308-------------------------------------------------------------------------------
286309-- Classes and types for map keys
287310-------------------------------------------------------------------------------
@@ -385,8 +408,48 @@ typeMismatch expected actual =
385408-------------------------------------------------------------------------------
386409
387410-- | Lifting of the 'FromJSON' class to unary type constructors.
411+--
412+-- Instead of manually writing your 'FromJSON1' instance, there are two options
413+-- to do it automatically:
414+--
415+-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
416+-- instance at compile time. The generated instance is optimized for your type
417+-- so will probably be more efficient than the following two options:
418+--
419+-- * The compiler can provide a default generic implementation for
420+-- 'liftParseJSON'.
421+--
422+-- To use the second, simply add a @deriving 'Generic1'@ clause to your
423+-- datatype and declare a 'FromJSON1' instance for your datatype without giving
424+-- a definition for 'liftParseJSON'.
425+--
426+-- For example:
427+--
428+-- @
429+-- {-\# LANGUAGE DeriveGeneric \#-}
430+--
431+-- import "GHC.Generics"
432+--
433+-- data Pair a b = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
434+--
435+-- instance FromJSON a => FromJSON1 (Pair a)
436+-- @
437+--
438+-- If @DefaultSignatures@ doesn't give exactly the results you want,
439+-- you can customize the generic decoding with only a tiny amount of
440+-- effort, using 'genericLiftParseJSON' with your preferred 'Options':
441+--
442+-- @
443+-- instance FromJSON a => FromJSON1 (Pair a) where
444+-- liftParseJSON = 'genericLiftParseJSON' 'defaultOptions'
445+-- @
388446class FromJSON1 f where
389447 liftParseJSON :: (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
448+
449+ default liftParseJSON :: (Generic1 f, GFromJSON One (Rep1 f))
450+ => (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
451+ liftParseJSON = genericLiftParseJSON defaultOptions
452+
390453 liftParseJSONList :: (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser [f a]
391454 liftParseJSONList f g v = listParser (liftParseJSON f g) v
392455
@@ -395,8 +458,13 @@ parseJSON1 :: (FromJSON1 f, FromJSON a) => Value -> Parser (f a)
395458parseJSON1 = liftParseJSON parseJSON parseJSONList
396459{-# INLINE parseJSON1 #-}
397460
398−
399461-- | Lifting of the 'FromJSON' class to binary type constructors.
462+--
463+-- Instead of manually writing your 'FromJSON2' instance, "Data.Aeson.TH"
464+-- provides Template Haskell functions which will derive an instance at compile time.
465+
466+-- The compiler cannot provide a default generic implementation for 'liftParseJSON2',
467+-- unlike 'parseJSON' and 'liftParseJSON'.
400468class FromJSON2 f where
401469 liftParseJSON2
402470 :: (Value -> Parser a)
@@ -551,65 +619,90 @@ pmval .!= val = fromMaybe val <$> pmval
551619-- Generic parseJSON
552620-------------------------------------------------------------------------------
553621
554−instance OVERLAPPABLE_ (GFromJSON a) => GFromJSON (M1 i c a) where
622+instance OVERLAPPABLE_ (GFromJSON arity a) => GFromJSON arity (M1 i c a) where
555623 -- Meta-information, which is not handled elsewhere, is just added to the
556624 -- parsed value:
557− gParseJSON opts = fmap M1 . gParseJSON opts
625+ gParseJSON opts pa pj pjl = fmap M1 . gParseJSON opts pa pj pjl
558626
559−instance (FromJSON a) => GFromJSON (K1 i a) where
627+instance (FromJSON a) => GFromJSON arity (K1 i a) where
560628 -- Constant values are decoded using their FromJSON instance:
561− gParseJSON _opts = fmap K1 . parseJSON
629+ gParseJSON _opts _ _ _ = fmap K1 . parseJSON
630+
631+instance GFromJSON One Par1 where
632+ -- Direct occurrences of the last type parameter are decoded with the
633+ -- function passed in as an argument:
634+ gParseJSON _opts _ pj _ = fmap Par1 . pj
635+
636+instance (FromJSON1 f) => GFromJSON One (Rec1 f) where
637+ -- Recursive occurrences of the last type parameter are decoded using their
638+ -- FromJSON1 instance:
639+ gParseJSON _opts _ pj pjl = fmap Rec1 . liftParseJSON pj pjl
562640
563−instance GFromJSON U1 where
641+instance GFromJSON arity U1 where
564642 -- Empty constructors are expected to be encoded as an empty array:
565− gParseJSON _opts v
643+ gParseJSON _opts _ _ _ v
566644 | isEmptyArray v = pure U1
567645 | otherwise = typeMismatch "unit constructor (U1)" v
568646
569−instance (ConsFromJSON a) => GFromJSON (C1 c a) where
647+instance (ConsFromJSON arity a) => GFromJSON arity (C1 c a) where
570648 -- Constructors need to be decoded differently depending on whether they're
571649 -- a record or not. This distinction is made by consParseJSON:
572− gParseJSON opts = fmap M1 . consParseJSON opts
650+ gParseJSON opts pa pj pjl = fmap M1 . consParseJSON opts pa pj pjl
573651
574−instance ( FromProduct a, FromProduct b
575− , ProductSize a, ProductSize b ) => GFromJSON (a :*: b) where
652+instance ( FromProduct arity a, FromProduct arity b
653+ , ProductSize a, ProductSize b
654+ ) => GFromJSON arity (a :*: b) where
576655 -- Products are expected to be encoded to an array. Here we check whether we
577656 -- got an array of the same size as the product, then parse each of the
578657 -- product's elements using parseProduct:
579− gParseJSON opts = withArray "product (:*:)" $ \arr ->
658+ gParseJSON opts pa pj pjl = withArray "product (:*:)" $ \arr ->
580659 let lenArray = V.length arr
581660 lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
582661 productSize in
583662 if lenArray == lenProduct
584− then parseProduct opts arr 0 lenProduct
663+ then parseProduct opts pa arr 0 lenProduct pj pjl
585664 else fail $ "When expecting a product of " ++ show lenProduct ++
586665 " values, encountered an Array of " ++ show lenArray ++
587666 " elements instead"
588667
589−instance ( AllNullary (a :+: b) allNullary
590− , ParseSum (a :+: b) allNullary ) => GFromJSON (a :+: b) where
668+instance ( AllNullary (a :+: b) allNullary
669+ , ParseSum arity (a :+: b) allNullary
670+ ) => GFromJSON arity (a :+: b) where
591671 -- If all constructors of a sum datatype are nullary and the
592672 -- 'allNullaryToStringTag' option is set they are expected to be
593673 -- encoded as strings. This distinction is made by 'parseSum':
594− gParseJSON opts = (unTagged :: Tagged allNullary (Parser ((a :+: b) d)) ->
595− (Parser ((a :+: b) d)))
596− . parseSum opts
674+ gParseJSON opts pa pj pjl =
675+ (unTagged :: Tagged allNullary (Parser ((a :+: b) d)) ->
676+ (Parser ((a :+: b) d)))
677+ . parseSum opts pa pj pjl
678+
679+instance (FromJSON1 f, GFromJSON One g) => GFromJSON One (f :.: g) where
680+ -- If an occurrence of the last type parameter is nested inside two
681+ -- composed types, it is decoded by using the outermost type's FromJSON1
682+ -- instance to generically decode the innermost type:
683+ gParseJSON opts pa pj pjl =
684+ let gpj = gParseJSON opts pa pj pjl in
685+ fmap Comp1 . liftParseJSON gpj (listParser gpj)
597686
598687--------------------------------------------------------------------------------
599688
600−class ParseSum f allNullary where
601− parseSum :: Options -> Value -> Tagged allNullary (Parser (f a))
689+class ParseSum arity f allNullary where
690+ parseSum :: Options -> Proxy arity
691+ -> (Value -> Parser a) -> (Value -> Parser [a])
692+ -> Value -> Tagged allNullary (Parser (f a))
602693
603−instance ( SumFromString (a :+: b)
604− , FromPair (a :+: b)
605− , FromTaggedObject (a :+: b) ) => ParseSum (a :+: b) True where
606− parseSum opts
694+instance ( SumFromString (a :+: b)
695+ , FromPair arity (a :+: b)
696+ , FromTaggedObject arity (a :+: b)
697+ ) => ParseSum arity (a :+: b) True where
698+ parseSum opts pa pj pjl
607699 | allNullaryToStringTag opts = Tagged . parseAllNullarySum opts
608− | otherwise = Tagged . parseNonAllNullarySum opts
700+ | otherwise = Tagged . parseNonAllNullarySum opts pa pj pjl
609701
610−instance ( FromPair (a :+: b)
611− , FromTaggedObject (a :+: b) ) => ParseSum (a :+: b) False where
612− parseSum opts = Tagged . parseNonAllNullarySum opts
702+instance ( FromPair arity (a :+: b)
703+ , FromTaggedObject arity (a :+: b)
704+ ) => ParseSum arity (a :+: b) False where
705+ parseSum opts pa pj pjl = Tagged . parseNonAllNullarySum opts pa pj pjl
613706
614707--------------------------------------------------------------------------------
615708
@@ -634,22 +727,24 @@ instance (Constructor c) => SumFromString (C1 c U1) where
634727
635728--------------------------------------------------------------------------------
636729
637−parseNonAllNullarySum :: ( FromPair (a :+: b)
638− , FromTaggedObject (a :+: b)
639− ) => Options -> Value -> Parser ((a :+: b) c)
640−parseNonAllNullarySum opts =
730+parseNonAllNullarySum :: ( FromPair arity (a :+: b)
731+ , FromTaggedObject arity (a :+: b)
732+ ) => Options -> Proxy arity
733+ -> (Value -> Parser c) -> (Value -> Parser [c])
734+ -> Value -> Parser ((a :+: b) c)
735+parseNonAllNullarySum opts pa pj pjl =
641736 case sumEncoding opts of
642737 TaggedObject{..} ->
643738 withObject "Object" $ \obj -> do
644739 tag <- obj .: pack tagFieldName
645740 fromMaybe (notFound tag) $
646− parseFromTaggedObject opts contentsFieldName obj tag
741+ parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag
647742
648743 ObjectWithSingleField ->
649744 withObject "Object" $ \obj ->
650745 case H.toList obj of
651746 [pair@(tag, _)] -> fromMaybe (notFound tag) $
652− parsePair opts pair
747+ parsePair opts pa pj pjl pair
653748 _ -> fail "Object doesn't have a single field"
654749
655750 TwoElemArray ->
@@ -657,27 +752,30 @@ parseNonAllNullarySum opts =
657752 if V.length arr == 2
658753 then case V.unsafeIndex arr 0 of
659754 String tag -> fromMaybe (notFound tag) $
660− parsePair opts (tag, V.unsafeIndex arr 1)
755+ parsePair opts pa pj pjl (tag, V.unsafeIndex arr 1)
661756 _ -> fail "First element is not a String"
662757 else fail "Array doesn't have 2 elements"
663758
664759--------------------------------------------------------------------------------
665760
666−class FromTaggedObject f where
667− parseFromTaggedObject :: Options -> String -> Object -> Text
668− -> Maybe (Parser (f a))
669−
670−instance (FromTaggedObject a, FromTaggedObject b) =>
671− FromTaggedObject (a :+: b) where
672− parseFromTaggedObject opts contentsFieldName obj tag =
673− (fmap L1 <$> parseFromTaggedObject opts contentsFieldName obj tag) <|>
674− (fmap R1 <$> parseFromTaggedObject opts contentsFieldName obj tag)
675−
676−instance ( FromTaggedObject' f
677− , Constructor c ) => FromTaggedObject (C1 c f) where
678− parseFromTaggedObject opts contentsFieldName obj tag
761+class FromTaggedObject arity f where
762+ parseFromTaggedObject :: Options -> Proxy arity
763+ -> String -> Object
764+ -> (Value -> Parser a) -> (Value -> Parser [a])
765+ -> Text -> Maybe (Parser (f a))
766+
767+instance ( FromTaggedObject arity a, FromTaggedObject arity b) =>
768+ FromTaggedObject arity (a :+: b) where
769+ parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag =
770+ (fmap L1 <$> parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag) <|>
771+ (fmap R1 <$> parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag)
772+
773+instance ( FromTaggedObject' arity f
774+ , Constructor c
775+ ) => FromTaggedObject arity (C1 c f) where
776+ parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag
679777 | tag == name = Just $ M1 <$> parseFromTaggedObject'
680− opts contentsFieldName obj
778+ opts pa contentsFieldName pj pjl obj
681779 | otherwise = Nothing
682780 where
683781 name = pack $ constructorTagModifier opts $
@@ -685,114 +783,143 @@ instance ( FromTaggedObject' f
685783
686784--------------------------------------------------------------------------------
687785
688−class FromTaggedObject' f where
689− parseFromTaggedObject' :: Options -> String -> Object -> Parser (f a)
786+class FromTaggedObject' arity f where
787+ parseFromTaggedObject' :: Options -> Proxy arity -> String
788+ -> (Value -> Parser a) -> (Value -> Parser [a])
789+ -> Object -> Parser (f a)
690790
691−class FromTaggedObject'' f isRecord where
692− parseFromTaggedObject'' :: Options -> String -> Object
693− -> Tagged isRecord (Parser (f a))
791+class FromTaggedObject'' arity f isRecord where
792+ parseFromTaggedObject'' :: Options -> Proxy arity -> String
793+ -> (Value -> Parser a) -> (Value -> Parser [a])
794+ -> Object -> Tagged isRecord (Parser (f a))
694795
695−instance ( IsRecord f isRecord
696− , FromTaggedObject'' f isRecord
697− ) => FromTaggedObject' f where
698− parseFromTaggedObject' opts contentsFieldName =
796+instance ( IsRecord f isRecord
797+ , FromTaggedObject'' arity f isRecord
798+ ) => FromTaggedObject' arity f where
799+ parseFromTaggedObject' opts pa contentsFieldName pj pjl =
699800 (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a)) .
700− parseFromTaggedObject'' opts contentsFieldName
801+ parseFromTaggedObject'' opts pa contentsFieldName pj pjl
701802
702−instance (FromRecord f) => FromTaggedObject'' f True where
703− parseFromTaggedObject'' opts _ = Tagged . parseRecord opts Nothing
803+instance (FromRecord arity f) => FromTaggedObject'' arity f True where
804+ parseFromTaggedObject'' opts pa _ pj pjl =
805+ Tagged . parseRecord opts pa Nothing pj pjl
704806
705−instance (GFromJSON f) => FromTaggedObject'' f False where
706− parseFromTaggedObject'' opts contentsFieldName = Tagged .
707− (gParseJSON opts <=< (.: pack contentsFieldName))
807+instance (GFromJSON arity f) => FromTaggedObject'' arity f False where
808+ parseFromTaggedObject'' opts pa contentsFieldName pj pjl = Tagged .
809+ (gParseJSON opts pa pj pjl <=< (.: pack contentsFieldName))
708810
709−instance OVERLAPPING_ FromTaggedObject'' U1 False where
710− parseFromTaggedObject'' _ _ _ = Tagged (pure U1)
811+instance OVERLAPPING_ FromTaggedObject'' arity U1 False where
812+ parseFromTaggedObject'' _ _ _ _ _ _ = Tagged (pure U1)
711813
712814--------------------------------------------------------------------------------
713815
714−class ConsFromJSON f where
715− consParseJSON :: Options -> Value -> Parser (f a)
816+class ConsFromJSON arity f where
817+ consParseJSON :: Options -> Proxy arity
818+ -> (Value -> Parser a) -> (Value -> Parser [a])
819+ -> Value -> Parser (f a)
716820
717−class ConsFromJSON' f isRecord where
718− consParseJSON' :: Options -> (Maybe Text) -- ^ A dummy label
719− -- (Nothing to use proper label)
821+class ConsFromJSON' arity f isRecord where
822+ consParseJSON' :: Options -> Proxy arity
823+ -> (Maybe Text) -- ^ A dummy label
824+ -- (Nothing to use proper label)
825+ -> (Value -> Parser a) -> (Value -> Parser [a])
720826 -> Value -> Tagged isRecord (Parser (f a))
721827
722−instance ( IsRecord f isRecord
723− , ConsFromJSON' f isRecord
724− ) => ConsFromJSON f where
725− consParseJSON opts v = let
828+instance ( IsRecord f isRecord
829+ , ConsFromJSON' arity f isRecord
830+ ) => ConsFromJSON arity f where
831+ consParseJSON opts pa pj pjl v = let
726832 (v2,lab) = case (unwrapUnaryRecords opts,isUnary (undefined :: f a)) of
727833 -- use a dummy object with a dummy label
728834 (True,True) -> ((object [(pack "dummy",v)]),Just $ pack "dummy")
729835 _ ->(v,Nothing)
730836 in (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))
731− $ consParseJSON' opts lab v2
837+ $ consParseJSON' opts pa lab pj pjl v2
732838
733839
734−instance (FromRecord f) => ConsFromJSON' f True where
735− consParseJSON' opts mlab = Tagged . (withObject "record (:*:)"
736− $ parseRecord opts mlab)
840+instance (FromRecord arity f) => ConsFromJSON' arity f True where
841+ consParseJSON' opts pa mlab pj pjl = Tagged . (withObject "record (:*:)"
842+ $ parseRecord opts pa mlab pj pjl)
737843
738−instance (GFromJSON f) => ConsFromJSON' f False where
739− consParseJSON' opts _ = Tagged . gParseJSON opts
844+instance (GFromJSON arity f) => ConsFromJSON' arity f False where
845+ consParseJSON' opts pa _ pj pjl = Tagged . gParseJSON opts pa pj pjl
740846
741847--------------------------------------------------------------------------------
742848
743−class FromRecord f where
744− parseRecord :: Options -> (Maybe Text) -- ^ A dummy label
745− -- (Nothing to use proper label)
746− -> Object -> Parser (f a)
747−
748−instance (FromRecord a, FromRecord b) => FromRecord (a :*: b) where
749− parseRecord opts _ obj = (:*:) <$> parseRecord opts Nothing obj
750− <*> parseRecord opts Nothing obj
751−
752−instance (Selector s, GFromJSON a) => FromRecord (S1 s a) where
753− parseRecord opts lab = (<?> Key label) . gParseJSON opts <=< (.: label)
849+class FromRecord arity f where
850+ parseRecord :: Options -> Proxy arity
851+ -> (Maybe Text) -- ^ A dummy label
852+ -- (Nothing to use proper label)
853+ -> (Value -> Parser a) -> (Value -> Parser [a])
854+ -> Object -> Parser (f a)
855+
856+instance ( FromRecord arity a
857+ , FromRecord arity b
858+ ) => FromRecord arity (a :*: b) where
859+ parseRecord opts pa _ pj pjl obj =
860+ (:*:) <$> parseRecord opts pa Nothing pj pjl obj
861+ <*> parseRecord opts pa Nothing pj pjl obj
862+
863+instance ( Selector s
864+ , GFromJSON arity a
865+ ) => FromRecord arity (S1 s a) where
866+ parseRecord opts pa lab pj pjl =
867+ (<?> Key label) . gParseJSON opts pa pj pjl <=< (.: label)
754868 where
755869 label = fromMaybe defLabel lab
756870 defLabel = pack . fieldLabelModifier opts $
757871 selName (undefined :: t s a p)
758872
759873instance OVERLAPPING_ (Selector s, FromJSON a) =>
760− FromRecord (S1 s (K1 i (Maybe a))) where
761− parseRecord _ (Just lab) obj = (M1 . K1) <$> obj .:? lab
762− parseRecord opts Nothing obj = (M1 . K1) <$> obj .:? pack label
874+ FromRecord arity (S1 s (K1 i (Maybe a))) where
875+ parseRecord _ _ (Just lab) _ _ obj = (M1 . K1) <$> obj .:? lab
876+ parseRecord opts _ Nothing _ _ obj = (M1 . K1) <$> obj .:? pack label
763877 where
764878 label = fieldLabelModifier opts $
765879 selName (undefined :: t s (K1 i (Maybe a)) p)
766880
767881--------------------------------------------------------------------------------
768882
769−class FromProduct f where
770− parseProduct :: Options -> Array -> Int -> Int -> Parser (f a)
771−
772−instance (FromProduct a, FromProduct b) => FromProduct (a :*: b) where
773− parseProduct opts arr ix len =
774− (:*:) <$> parseProduct opts arr ix lenL
775− <*> parseProduct opts arr ixR lenR
883+class FromProduct arity f where
884+ parseProduct :: Options -> Proxy arity
885+ -> Array -> Int -> Int
886+ -> (Value -> Parser a) -> (Value -> Parser [a])
887+ -> Parser (f a)
888+
889+instance ( FromProduct arity a
890+ , FromProduct arity b
891+ ) => FromProduct arity (a :*: b) where
892+ parseProduct opts pa arr ix len pj pjl =
893+ (:*:) <$> parseProduct opts pa arr ix lenL pj pjl
894+ <*> parseProduct opts pa arr ixR lenR pj pjl
776895 where
777896 lenL = len `unsafeShiftR` 1
778897 ixR = ix + lenL
779898 lenR = len - lenL
780899
781−instance (GFromJSON a) => FromProduct (S1 s a) where
782− parseProduct opts arr ix _ = gParseJSON opts $ V.unsafeIndex arr ix
900+instance (GFromJSON arity a) => FromProduct arity (S1 s a) where
901+ parseProduct opts pa arr ix _ pj pjl =
902+ gParseJSON opts pa pj pjl $ V.unsafeIndex arr ix
783903
784904--------------------------------------------------------------------------------
785905
786−class FromPair f where
787− parsePair :: Options -> Pair -> Maybe (Parser (f a))
788−
789−instance (FromPair a, FromPair b) => FromPair (a :+: b) where
790− parsePair opts pair = (fmap L1 <$> parsePair opts pair) <|>
791− (fmap R1 <$> parsePair opts pair)
792−
793−instance (Constructor c, GFromJSON a, ConsFromJSON a) => FromPair (C1 c a) where
794− parsePair opts (tag, value)
795− | tag == tag' = Just $ gParseJSON opts value
906+class FromPair arity f where
907+ parsePair :: Options -> Proxy arity
908+ -> (Value -> Parser a) -> (Value -> Parser [a])
909+ -> Pair -> Maybe (Parser (f a))
910+
911+instance ( FromPair arity a
912+ , FromPair arity b
913+ ) => FromPair arity (a :+: b) where
914+ parsePair opts pa pj pjl pair = (fmap L1 <$> parsePair opts pa pj pjl pair) <|>
915+ (fmap R1 <$> parsePair opts pa pj pjl pair)
916+
917+instance ( Constructor c
918+ , GFromJSON arity a
919+ , ConsFromJSON arity a
920+ ) => FromPair arity (C1 c a) where
921+ parsePair opts pa pj pjl (tag, value)
922+ | tag == tag' = Just $ gParseJSON opts pa pj pjl value
796923 | otherwise = Nothing
797924 where
798925 tag' = pack $ constructorTagModifier opts $
Data/Aeson/Types/Generic.hs+21
@@ -26,6 +26,7 @@
2626module Data.Aeson.Types.Generic where
2727
2828import GHC.Generics
29+import Data.Proxy (Proxy (..))
2930
3031--------------------------------------------------------------------------------
3132
@@ -43,22 +44,28 @@ instance OVERLAPPING_ IsRecord (M1 S NoSelector f) False
4344#endif
4445instance (IsRecord f isRecord) => IsRecord (M1 S c f) isRecord
4546instance IsRecord (K1 i c) True
47+instance IsRecord Par1 True
48+instance IsRecord (f :.: g) True
4649instance IsRecord U1 False
4750 where isUnary = const False
4851
4952--------------------------------------------------------------------------------
5053
5154class AllNullary (f :: * -> *) allNullary | f -> allNullary
55+
5256instance ( AllNullary a allNullaryL
5357 , AllNullary b allNullaryR
5458 , And allNullaryL allNullaryR allNullary
5559 ) => AllNullary (a :+: b) allNullary
5660instance AllNullary a allNullary => AllNullary (M1 i c a) allNullary
5761instance AllNullary (a :*: b) False
62+instance AllNullary (a :.: b) False
5863instance AllNullary (K1 i c) False
64+instance AllNullary Par1 False
5965instance AllNullary U1 True
6066
6167newtype Tagged2 (s :: * -> *) b = Tagged2 {unTagged2 :: b}
68+
6269--------------------------------------------------------------------------------
6370
6471data True
@@ -73,6 +80,20 @@ instance And True False False
7380
7481--------------------------------------------------------------------------------
7582
83+-- | A type-level indicator that 'ToJSON' or 'FromJSON' is being derived generically.
84+data Zero
85+
86+-- | A type-level indicator that 'ToJSON1' or 'FromJSON1' is being derived generically.
87+data One
88+
89+proxyZero :: Proxy Zero
90+proxyZero = Proxy
91+
92+proxyOne :: Proxy One
93+proxyOne = Proxy
94+
95+--------------------------------------------------------------------------------
96+
7697class ProductSize f where
7798 productSize :: Tagged2 f Int
7899
Data/Aeson/Types/ToJSON.hs+469−264
@@ -38,6 +38,8 @@ module Data.Aeson.Types.ToJSON (
3838 , GToEncoding(..)
3939 , genericToJSON
4040 , genericToEncoding
41+ , genericLiftToJSON
42+ , genericLiftToEncoding
4143 -- * Classes and types for map keys
4244 , ToJSONKey(..)
4345 , ToJSONKeyFunction(..)
@@ -137,36 +139,58 @@ realFloatToEncoding d
137139 | isNaN d || isInfinite d = Encoding EB.null_
138140 | otherwise = toEncoding (Scientific.fromFloatDigits d)
139141{-# INLINE realFloatToEncoding #-}
142+
140143-------------------------------------------------------------------------------
141144-- Generics
142145-------------------------------------------------------------------------------
143146
144−-- | Class of generic representation types ('Rep') that can be converted to
147+-- | Class of generic representation types that can be converted to
145148-- JSON.
146−class GToJSON f where
149+class GToJSON arity f where
147150 -- | This method (applied to 'defaultOptions') is used as the
148− -- default generic implementation of 'toJSON'.
149− gToJSON :: Options -> f a -> Value
151+ -- default generic implementation of 'toJSON' (if the @arity@ is 'Zero')
152+ -- or 'liftToJSON' (if the @arity@ is 'One').
153+ gToJSON :: Options -> Proxy arity
154+ -> (a -> Value) -> ([a] -> Value) -> f a -> Value
150155
151−-- | Class of generic representation types ('Rep') that can be converted to
156+-- | Class of generic representation types that can be converted to
152157-- a JSON 'Encoding'.
153−class GToEncoding f where
158+class GToEncoding arity f where
154159 -- | This method (applied to 'defaultOptions') can be used as the
155− -- default generic implementation of 'toEncoding'.
156− gToEncoding :: Options -> f a -> Encoding
157−
160+ -- default generic implementation of 'toEncoding' (if the @arity@ is 'Zero')
161+ -- or 'liftToEncoding' (if the @arity@ is 'One').
162+ gToEncoding :: Options -> Proxy arity
163+ -> (a -> Encoding) -> ([a] -> Encoding) -> f a -> Encoding
158164
159165-- | A configurable generic JSON creator. This function applied to
160166-- 'defaultOptions' is used as the default for 'toJSON' when the type
161167-- is an instance of 'Generic'.
162−genericToJSON :: (Generic a, GToJSON (Rep a)) => Options -> a -> Value
163−genericToJSON opts = gToJSON opts . from
168+genericToJSON :: (Generic a, GToJSON Zero (Rep a))
169+ => Options -> a -> Value
170+genericToJSON opts = gToJSON opts proxyZero undefined undefined . from
171+
172+-- | A configurable generic JSON creator. This function applied to
173+-- 'defaultOptions' is used as the default for 'liftToJSON' when the type
174+-- is an instance of 'Generic1'.
175+genericLiftToJSON :: (Generic1 f, GToJSON One (Rep1 f))
176+ => Options -> (a -> Value) -> ([a] -> Value)
177+ -> f a -> Value
178+genericLiftToJSON opts tj tjl = gToJSON opts proxyOne tj tjl . from1
164179
165180-- | A configurable generic JSON encoder. This function applied to
166181-- 'defaultOptions' is used as the default for 'toEncoding' when the type
167182-- is an instance of 'Generic'.
168−genericToEncoding :: (Generic a, GToEncoding (Rep a)) => Options -> a -> Encoding
169−genericToEncoding opts = gToEncoding opts . from
183+genericToEncoding :: (Generic a, GToEncoding Zero (Rep a))
184+ => Options -> a -> Encoding
185+genericToEncoding opts = gToEncoding opts proxyZero undefined undefined . from
186+
187+-- | A configurable generic JSON encoder. This function applied to
188+-- 'defaultOptions' is used as the default for 'liftToEncoding' when the type
189+-- is an instance of 'Generic1'.
190+genericLiftToEncoding :: (Generic1 f, GToEncoding One (Rep1 f))
191+ => Options -> (a -> Encoding) -> ([a] -> Encoding)
192+ -> f a -> Encoding
193+genericLiftToEncoding opts te tel = gToEncoding opts proxyOne te tel . from1
170194
171195-------------------------------------------------------------------------------
172196-- Class
@@ -240,7 +264,7 @@ class ToJSON a where
240264 -- | Convert a Haskell value to a JSON-friendly intermediate type.
241265 toJSON :: a -> Value
242266
243− default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value
267+ default toJSON :: (Generic a, GToJSON Zero (Rep a)) => a -> Value
244268 toJSON = genericToJSON defaultOptions
245269
246270 -- | Encode a Haskell value as JSON.
@@ -315,14 +339,62 @@ contramapToJSONKeyFunction h x = case x of
315339-- Lifings of FromJSON and ToJSON to unary and binary type constructors
316340-------------------------------------------------------------------------------
317341
342+
318343-- | Lifting of the 'ToJSON' class to unary type constructors.
344+--
345+-- Instead of manually writing your 'ToJSON1' instance, there are two options
346+-- to do it automatically:
347+--
348+-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
349+-- instance at compile time. The generated instance is optimized for your type
350+-- so will probably be more efficient than the following two options:
351+--
352+-- * The compiler can provide a default generic implementation for
353+-- 'toJSON1'.
354+--
355+-- To use the second, simply add a @deriving 'Generic1'@ clause to your
356+-- datatype and declare a 'ToJSON1' instance for your datatype without giving
357+-- definitions for 'liftToJSON' or 'liftToEncoding'.
358+--
359+-- For example:
360+--
361+-- @
362+-- {-\# LANGUAGE DeriveGeneric \#-}
363+--
364+-- import "GHC.Generics"
365+--
366+-- data Pair = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
367+--
368+-- instance ToJSON a => ToJSON1 (Pair a)
369+-- @
370+--
371+-- If @DefaultSignatures@ doesn't give exactly the results you want,
372+-- you can customize the generic encoding with only a tiny amount of
373+-- effort, using 'genericLiftToJSON' and 'genericLiftToEncoding' with
374+-- your preferred 'Options':
375+--
376+-- @
377+-- instance ToJSON a => ToJSON1 (Pair a) where
378+-- liftToJSON = 'genericLiftToJSON' 'defaultOptions'
379+-- liftToEncoding = 'genericLiftToEncoding' 'defaultOptions'
380+-- @
319381class ToJSON1 f where
320382 liftToJSON :: (a -> Value) -> ([a] -> Value) -> f a -> Value
383+
384+ default liftToJSON :: (Generic1 f, GToJSON One (Rep1 f))
385+ => (a -> Value) -> ([a] -> Value) -> f a -> Value
386+ liftToJSON = genericLiftToJSON defaultOptions
387+
321388 liftToJSONList :: (a -> Value) -> ([a] -> Value) -> [f a] -> Value
322389 liftToJSONList f g = listValue (liftToJSON f g)
323390
324− -- | Unfortunately there cannot be a default implementation of 'liftToEncoding'.
325391 liftToEncoding :: (a -> Encoding) -> ([a] -> Encoding) -> f a -> Encoding
392+
393+ default liftToEncoding :: (Generic1 f, GToEncoding One (Rep1 f))
394+ => (a -> Encoding) -> ([a] -> Encoding)
395+ -> f a -> Encoding
396+ liftToEncoding = genericLiftToEncoding defaultOptions
397+
326398 liftToEncodingList :: (a -> Encoding) -> ([a] -> Encoding) -> [f a] -> Encoding
327399 liftToEncodingList f g = listEncoding (liftToEncoding f g)
328400
@@ -336,8 +408,13 @@ toEncoding1 :: (ToJSON1 f, ToJSON a) => f a -> Encoding
336408toEncoding1 = liftToEncoding toEncoding toEncodingList
337409{-# INLINE toEncoding1 #-}
338410
339−
340411-- | Lifting of the 'ToJSON' class to binary type constructors.
412+--
413+-- Instead of manually writing your 'ToJSON2' instance, "Data.Aeson.TH"
414+-- provides Template Haskell functions which will derive an instance at compile time.
415+--
416+-- The compiler cannot provide a default generic implementation for 'liftToJSON2',
417+-- unlike 'toJSON' and 'liftToJSON'.
341418class ToJSON2 f where
342419 liftToJSON2 :: (a -> Value) -> ([a] -> Value) -> (b -> Value) -> ([b] -> Value) -> f a b -> Value
343420 liftToJSONList2 :: (a -> Value) -> ([a] -> Value) -> (b -> Value) -> ([b] -> Value) -> [f a b] -> Value
@@ -395,211 +472,280 @@ instance (ToJSON a) => ToJSON [a] where
395472--------------------------------------------------------------------------------
396473-- Generic toJSON
397474
398−instance OVERLAPPABLE_ (GToJSON a) => GToJSON (M1 i c a) where
475+instance OVERLAPPABLE_ (GToJSON arity a) => GToJSON arity (M1 i c a) where
399476 -- Meta-information, which is not handled elsewhere, is ignored:
400− gToJSON opts = gToJSON opts . unM1
477+ gToJSON opts pa tj tjl = gToJSON opts pa tj tjl . unM1
401478
402−instance (ToJSON a) => GToJSON (K1 i a) where
479+instance (ToJSON a) => GToJSON arity (K1 i a) where
403480 -- Constant values are encoded using their ToJSON instance:
404− gToJSON _opts = toJSON . unK1
481+ gToJSON _opts _ _ _ = toJSON . unK1
482+
483+instance GToJSON One Par1 where
484+ -- Direct occurrences of the last type parameter are encoded with the
485+ -- function passed in as an argument:
486+ gToJSON _opts _ tj _ = tj . unPar1
487+
488+instance (ToJSON1 f) => GToJSON One (Rec1 f) where
489+ -- Recursive occurrences of the last type parameter are encoded using their
490+ -- ToJSON1 instance:
491+ gToJSON _opts _ tj tjl = liftToJSON tj tjl . unRec1
405492
406−instance GToJSON U1 where
493+instance GToJSON arity U1 where
407494 -- Empty constructors are encoded to an empty array:
408− gToJSON _opts _ = emptyArray
495+ gToJSON _opts _ _ _ _ = emptyArray
409496
410−instance (ConsToJSON a) => GToJSON (C1 c a) where
497+instance (ConsToJSON arity a) => GToJSON arity (C1 c a) where
411498 -- Constructors need to be encoded differently depending on whether they're
412499 -- a record or not. This distinction is made by 'consToJSON':
413− gToJSON opts = consToJSON opts . unM1
500+ gToJSON opts pa tj tjl = consToJSON opts pa tj tjl . unM1
414501
415−instance ( WriteProduct a, WriteProduct b
416− , ProductSize a, ProductSize b ) => GToJSON (a :*: b) where
502+instance ( WriteProduct arity a, WriteProduct arity b
503+ , ProductSize a, ProductSize b
504+ ) => GToJSON arity (a :*: b) where
417505 -- Products are encoded to an array. Here we allocate a mutable vector of
418506 -- the same size as the product and write the product's elements to it using
419507 -- 'writeProduct':
420− gToJSON opts p =
508+ gToJSON opts pa tj tjl p =
421509 Array $ V.create $ do
422510 mv <- VM.unsafeNew lenProduct
423− writeProduct opts mv 0 lenProduct p
511+ writeProduct opts pa mv 0 lenProduct tj tjl p
424512 return mv
425513 where
426514 lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
427515 productSize
428516
429−instance ( AllNullary (a :+: b) allNullary
430− , SumToJSON (a :+: b) allNullary ) => GToJSON (a :+: b) where
517+instance ( AllNullary (a :+: b) allNullary
518+ , SumToJSON arity (a :+: b) allNullary
519+ ) => GToJSON arity (a :+: b) where
431520 -- If all constructors of a sum datatype are nullary and the
432521 -- 'allNullaryToStringTag' option is set they are encoded to
433522 -- strings. This distinction is made by 'sumToJSON':
434− gToJSON opts = (unTagged :: Tagged allNullary Value -> Value)
435− . sumToJSON opts
523+ gToJSON opts pa tj tjl = (unTagged :: Tagged allNullary Value -> Value)
524+ . sumToJSON opts pa tj tjl
525+
526+instance (ToJSON1 f, GToJSON One g) => GToJSON One (f :.: g) where
527+ -- If an occurrence of the last type parameter is nested inside two
528+ -- composed types, it is encoded by using the outermost type's ToJSON1
529+ -- instance to generically encode the innermost type:
530+ gToJSON opts pa tj tjl =
531+ let gtj = gToJSON opts pa tj tjl in
532+ liftToJSON gtj (listValue gtj) . unComp1
436533
437534--------------------------------------------------------------------------------
438535-- Generic toEncoding
439536
440−instance OVERLAPPABLE_ (GToEncoding a) => GToEncoding (M1 i c a) where
537+instance OVERLAPPABLE_ (GToEncoding arity a) => GToEncoding arity (M1 i c a) where
441538 -- Meta-information, which is not handled elsewhere, is ignored:
442− gToEncoding opts = gToEncoding opts . unM1
539+ gToEncoding opts pa te tel = gToEncoding opts pa te tel . unM1
443540
444−instance (ToJSON a) => GToEncoding (K1 i a) where
541+instance (ToJSON a) => GToEncoding arity (K1 i a) where
445542 -- Constant values are encoded using their ToJSON instance:
446− gToEncoding _opts = toEncoding . unK1
543+ gToEncoding _opts _ _ _ = toEncoding . unK1
544+
545+instance GToEncoding One Par1 where
546+ -- Direct occurrences of the last type parameter are encoded with the
547+ -- function passed in as an argument:
548+ gToEncoding _opts _ te _ = te . unPar1
447549
448−instance GToEncoding U1 where
550+instance (ToJSON1 f) => GToEncoding One (Rec1 f) where
551+ -- Recursive occurrences of the last type parameter are encoded using their
552+ -- ToEncoding1 instance:
553+ gToEncoding _opts _ te tel = liftToEncoding te tel . unRec1
554+
555+instance GToEncoding arity U1 where
449556 -- Empty constructors are encoded to an empty array:
450− gToEncoding _opts _ = E.emptyArray_
557+ gToEncoding _opts _ _ _ _ = E.emptyArray_
451558
452−instance (ConsToEncoding a) => GToEncoding (C1 c a) where
559+instance (ConsToEncoding arity a) => GToEncoding arity (C1 c a) where
453560 -- Constructors need to be encoded differently depending on whether they're
454561 -- a record or not. This distinction is made by 'consToEncoding':
455− gToEncoding opts = consToEncoding opts . unM1
562+ gToEncoding opts pa te tel = consToEncoding opts pa te tel . unM1
456563
457−instance ( EncodeProduct a, EncodeProduct b ) => GToEncoding (a :*: b) where
564+instance ( EncodeProduct arity a
565+ , EncodeProduct arity b
566+ ) => GToEncoding arity (a :*: b) where
458567 -- Products are encoded to an array. Here we allocate a mutable vector of
459568 -- the same size as the product and write the product's elements to it using
460569 -- 'encodeProduct':
461− gToEncoding opts p = E.tuple $ encodeProduct opts p
570+ gToEncoding opts pa te tel p = E.tuple $ encodeProduct opts pa te tel p
462571
463−instance ( AllNullary (a :+: b) allNullary
464− , SumToEncoding (a :+: b) allNullary ) => GToEncoding (a :+: b) where
572+instance ( AllNullary (a :+: b) allNullary
573+ , SumToEncoding arity (a :+: b) allNullary
574+ ) => GToEncoding arity (a :+: b) where
465575 -- If all constructors of a sum datatype are nullary and the
466576 -- 'allNullaryToStringTag' option is set they are encoded to
467577 -- strings. This distinction is made by 'sumToEncoding':
468− gToEncoding opts
578+ gToEncoding opts pa te tel
469579 = (unTagged :: Tagged allNullary Encoding -> Encoding)
470− . sumToEncoding opts
580+ . sumToEncoding opts pa te tel
471581
472−--------------------------------------------------------------------------------
582+instance (ToJSON1 f, GToEncoding One g) => GToEncoding One (f :.: g) where
583+ -- If an occurrence of the last type parameter is nested inside two
584+ -- composed types, it is encoded by using the outermost type's ToJSON1
585+ -- instance to generically encode the innermost type:
586+ gToEncoding opts pa te tel =
587+ let gte = gToEncoding opts pa te tel in
588+ liftToEncoding gte (listEncoding gte) . unComp1
473589
474−class SumToJSON f allNullary where
475− sumToJSON :: Options -> f a -> Tagged allNullary Value
590+--------------------------------------------------------------------------------
476591
477−instance ( GetConName f
478− , TaggedObjectPairs f
479− , ObjectWithSingleFieldObj f
480− , TwoElemArrayObj f ) => SumToJSON f True where
481− sumToJSON opts
592+class SumToJSON arity f allNullary where
593+ sumToJSON :: Options -> Proxy arity
594+ -> (a -> Value) -> ([a] -> Value)
595+ -> f a -> Tagged allNullary Value
596+
597+instance ( GetConName f
598+ , TaggedObjectPairs arity f
599+ , ObjectWithSingleFieldObj arity f
600+ , TwoElemArrayObj arity f
601+ ) => SumToJSON arity f True where
602+ sumToJSON opts pa tj tjl
482603 | allNullaryToStringTag opts = Tagged . String . pack
483604 . constructorTagModifier opts . getConName
484− | otherwise = Tagged . nonAllNullarySumToJSON opts
485−
486−instance ( TwoElemArrayObj f
487− , TaggedObjectPairs f
488− , ObjectWithSingleFieldObj f ) => SumToJSON f False where
489− sumToJSON opts = Tagged . nonAllNullarySumToJSON opts
490−
491−nonAllNullarySumToJSON :: ( TwoElemArrayObj f
492− , TaggedObjectPairs f
493− , ObjectWithSingleFieldObj f
494− ) => Options -> f a -> Value
495−nonAllNullarySumToJSON opts =
605+ | otherwise = Tagged . nonAllNullarySumToJSON opts pa tj tjl
606+
607+instance ( TwoElemArrayObj arity f
608+ , TaggedObjectPairs arity f
609+ , ObjectWithSingleFieldObj arity f
610+ ) => SumToJSON arity f False where
611+ sumToJSON opts pa tj tjl = Tagged . nonAllNullarySumToJSON opts pa tj tjl
612+
613+nonAllNullarySumToJSON :: ( TwoElemArrayObj arity f
614+ , TaggedObjectPairs arity f
615+ , ObjectWithSingleFieldObj arity f
616+ ) => Options -> Proxy arity
617+ -> (a -> Value) -> ([a] -> Value)
618+ -> f a -> Value
619+nonAllNullarySumToJSON opts pa tj tjl =
496620 case sumEncoding opts of
497621 TaggedObject{..} ->
498− object . taggedObjectPairs opts tagFieldName contentsFieldName
499− ObjectWithSingleField -> Object . objectWithSingleFieldObj opts
500− TwoElemArray -> Array . twoElemArrayObj opts
622+ object . taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl
623+ ObjectWithSingleField -> Object . objectWithSingleFieldObj opts pa tj tjl
624+ TwoElemArray -> Array . twoElemArrayObj opts pa tj tjl
501625
502626--------------------------------------------------------------------------------
503627
504−class SumToEncoding f allNullary where
505− sumToEncoding :: Options -> f a -> Tagged allNullary Encoding
506−
507−instance ( GetConName f
508− , TaggedObjectEnc f
509− , ObjectWithSingleFieldEnc f
510− , TwoElemArrayEnc f ) => SumToEncoding f True where
511− sumToEncoding opts
628+class SumToEncoding arity f allNullary where
629+ sumToEncoding :: Options -> Proxy arity
630+ -> (a -> Encoding) -> ([a] -> Encoding)
631+ -> f a -> Tagged allNullary Encoding
632+
633+instance ( GetConName f
634+ , TaggedObjectEnc arity f
635+ , ObjectWithSingleFieldEnc arity f
636+ , TwoElemArrayEnc arity f
637+ ) => SumToEncoding arity f True where
638+ sumToEncoding opts pa te tel
512639 | allNullaryToStringTag opts = Tagged . toEncoding .
513640 constructorTagModifier opts . getConName
514− | otherwise = Tagged . nonAllNullarySumToEncoding opts
515−
516−instance ( TwoElemArrayEnc f
517− , TaggedObjectEnc f
518− , ObjectWithSingleFieldEnc f ) => SumToEncoding f False where
519− sumToEncoding opts = Tagged . nonAllNullarySumToEncoding opts
520−
521−nonAllNullarySumToEncoding :: ( TwoElemArrayEnc f
522− , TaggedObjectEnc f
523− , ObjectWithSingleFieldEnc f
524− ) => Options -> f a -> Encoding
525−nonAllNullarySumToEncoding opts =
641+ | otherwise = Tagged . nonAllNullarySumToEncoding opts pa te tel
642+
643+instance ( TwoElemArrayEnc arity f
644+ , TaggedObjectEnc arity f
645+ , ObjectWithSingleFieldEnc arity f
646+ ) => SumToEncoding arity f False where
647+ sumToEncoding opts pa te tel = Tagged . nonAllNullarySumToEncoding opts pa te tel
648+
649+nonAllNullarySumToEncoding :: ( TwoElemArrayEnc arity f
650+ , TaggedObjectEnc arity f
651+ , ObjectWithSingleFieldEnc arity f
652+ ) => Options -> Proxy arity
653+ -> (a -> Encoding) -> ([a] -> Encoding)
654+ -> f a -> Encoding
655+nonAllNullarySumToEncoding opts pa te tel =
526656 case sumEncoding opts of
527657 TaggedObject{..} ->
528− taggedObjectEnc opts tagFieldName contentsFieldName
529− ObjectWithSingleField -> objectWithSingleFieldEnc opts
530− TwoElemArray -> twoElemArrayEnc opts
658+ taggedObjectEnc opts pa tagFieldName contentsFieldName te tel
659+ ObjectWithSingleField -> objectWithSingleFieldEnc opts pa te tel
660+ TwoElemArray -> twoElemArrayEnc opts pa te tel
531661
532662--------------------------------------------------------------------------------
533663
534−class TaggedObjectPairs f where
535− taggedObjectPairs :: Options -> String -> String -> f a -> [Pair]
536−
537−instance ( TaggedObjectPairs a
538− , TaggedObjectPairs b ) => TaggedObjectPairs (a :+: b) where
539− taggedObjectPairs opts tagFieldName contentsFieldName (L1 x) =
540− taggedObjectPairs opts tagFieldName contentsFieldName x
541− taggedObjectPairs opts tagFieldName contentsFieldName (R1 x) =
542− taggedObjectPairs opts tagFieldName contentsFieldName x
543−
544−instance ( IsRecord a isRecord
545− , TaggedObjectPairs' a isRecord
546− , Constructor c ) => TaggedObjectPairs (C1 c a) where
547− taggedObjectPairs opts tagFieldName contentsFieldName =
664+class TaggedObjectPairs arity f where
665+ taggedObjectPairs :: Options -> Proxy arity
666+ -> String -> String
667+ -> (a -> Value) -> ([a] -> Value)
668+ -> f a -> [Pair]
669+
670+instance ( TaggedObjectPairs arity a
671+ , TaggedObjectPairs arity b
672+ ) => TaggedObjectPairs arity (a :+: b) where
673+ taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl (L1 x) =
674+ taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl x
675+ taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl (R1 x) =
676+ taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl x
677+
678+instance ( IsRecord a isRecord
679+ , TaggedObjectPairs' arity a isRecord
680+ , Constructor c
681+ ) => TaggedObjectPairs arity (C1 c a) where
682+ taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl =
548683 (pack tagFieldName .= constructorTagModifier opts
549684 (conName (undefined :: t c a p)) :) .
550685 (unTagged :: Tagged isRecord [Pair] -> [Pair]) .
551− taggedObjectPairs' opts contentsFieldName . unM1
686+ taggedObjectPairs' opts pa contentsFieldName tj tjl . unM1
552687
553−class TaggedObjectPairs' f isRecord where
554− taggedObjectPairs' :: Options -> String -> f a -> Tagged isRecord [Pair]
688+class TaggedObjectPairs' arity f isRecord where
689+ taggedObjectPairs' :: Options -> Proxy arity
690+ -> String -> (a -> Value) -> ([a] -> Value)
691+ -> f a -> Tagged isRecord [Pair]
555692
556−instance OVERLAPPING_ TaggedObjectPairs' U1 False where
557− taggedObjectPairs' _ _ _ = Tagged []
693+instance OVERLAPPING_ TaggedObjectPairs' arity U1 False where
694+ taggedObjectPairs' _ _ _ _ _ _ = Tagged []
558695
559−instance (RecordToPairs f) => TaggedObjectPairs' f True where
560− taggedObjectPairs' opts _ = Tagged . toList . recordToPairs opts
696+instance (RecordToPairs arity f) => TaggedObjectPairs' arity f True where
697+ taggedObjectPairs' opts pa _ tj tjl =
698+ Tagged . toList . recordToPairs opts pa tj tjl
561699
562−instance (GToJSON f) => TaggedObjectPairs' f False where
563− taggedObjectPairs' opts contentsFieldName =
564− Tagged . (:[]) . (pack contentsFieldName .=) . gToJSON opts
700+instance (GToJSON arity f) => TaggedObjectPairs' arity f False where
701+ taggedObjectPairs' opts pa contentsFieldName tj tjl =
702+ Tagged . (:[]) . (pack contentsFieldName .=) . gToJSON opts pa tj tjl
565703
566704--------------------------------------------------------------------------------
567705
568−class TaggedObjectEnc f where
569− taggedObjectEnc :: Options -> String -> String -> f a -> Encoding
570−
571−instance ( TaggedObjectEnc a
572− , TaggedObjectEnc b ) => TaggedObjectEnc (a :+: b) where
573− taggedObjectEnc opts tagFieldName contentsFieldName (L1 x) =
574− taggedObjectEnc opts tagFieldName contentsFieldName x
575− taggedObjectEnc opts tagFieldName contentsFieldName (R1 x) =
576− taggedObjectEnc opts tagFieldName contentsFieldName x
577−
578−instance ( IsRecord a isRecord
579− , TaggedObjectEnc' a isRecord
580− , Constructor c ) => TaggedObjectEnc (C1 c a) where
581− taggedObjectEnc opts tagFieldName contentsFieldName v =
706+class TaggedObjectEnc arity f where
707+ taggedObjectEnc :: Options -> Proxy arity
708+ -> String -> String
709+ -> (a -> Encoding) -> ([a] -> Encoding)
710+ -> f a -> Encoding
711+
712+instance ( TaggedObjectEnc arity a
713+ , TaggedObjectEnc arity b
714+ ) => TaggedObjectEnc arity (a :+: b) where
715+ taggedObjectEnc opts pa tagFieldName contentsFieldName te tel (L1 x) =
716+ taggedObjectEnc opts pa tagFieldName contentsFieldName te tel x
717+ taggedObjectEnc opts pa tagFieldName contentsFieldName te tel (R1 x) =
718+ taggedObjectEnc opts pa tagFieldName contentsFieldName te tel x
719+
720+instance ( IsRecord a isRecord
721+ , TaggedObjectEnc' arity a isRecord
722+ , Constructor c
723+ ) => TaggedObjectEnc arity (C1 c a) where
724+ taggedObjectEnc opts pa tagFieldName contentsFieldName te tel v =
582725 E.openCurly <>
583726 (toEncoding tagFieldName <>
584727 E.colon <>
585728 toEncoding (constructorTagModifier opts (conName (undefined :: t c a p)))) <>
586729 ((unTagged :: Tagged isRecord Encoding -> Encoding) .
587− taggedObjectEnc' opts contentsFieldName . unM1 $ v) <>
730+ taggedObjectEnc' opts pa contentsFieldName te tel . unM1 $ v) <>
588731 E.closeCurly
589732
590−class TaggedObjectEnc' f isRecord where
591− taggedObjectEnc' :: Options -> String -> f a -> Tagged isRecord Encoding
733+class TaggedObjectEnc' arity f isRecord where
734+ taggedObjectEnc' :: Options -> Proxy arity
735+ -> String -> (a -> Encoding) -> ([a] -> Encoding)
736+ -> f a -> Tagged isRecord Encoding
592737
593−instance OVERLAPPING_ TaggedObjectEnc' U1 False where
594− taggedObjectEnc' _ _ _ = Tagged mempty
738+instance OVERLAPPING_ TaggedObjectEnc' arity U1 False where
739+ taggedObjectEnc' _ _ _ _ _ _ = Tagged mempty
595740
596−instance (RecordToEncoding f) => TaggedObjectEnc' f True where
597− taggedObjectEnc' opts _ = Tagged . (E.comma <>) . fst . recordToEncoding opts
741+instance (RecordToEncoding arity f) => TaggedObjectEnc' arity f True where
742+ taggedObjectEnc' opts pa _ te tel = Tagged . (E.comma <>) . fst
743+ . recordToEncoding opts pa te tel
598744
599−instance (GToEncoding f) => TaggedObjectEnc' f False where
600− taggedObjectEnc' opts contentsFieldName =
745+instance (GToEncoding arity f) => TaggedObjectEnc' arity f False where
746+ taggedObjectEnc' opts pa contentsFieldName te tel =
601747 Tagged . (\z -> E.comma <> toEncoding contentsFieldName <> E.colon <> z) .
602− gToEncoding opts
748+ gToEncoding opts pa te tel
603749
604750--------------------------------------------------------------------------------
605751
@@ -616,227 +762,286 @@ instance (Constructor c) => GetConName (C1 c a) where
616762
617763--------------------------------------------------------------------------------
618764
619−class TwoElemArrayObj f where
620− twoElemArrayObj :: Options -> f a -> V.Vector Value
621−
622−instance (TwoElemArrayObj a, TwoElemArrayObj b) => TwoElemArrayObj (a :+: b) where
623− twoElemArrayObj opts (L1 x) = twoElemArrayObj opts x
624− twoElemArrayObj opts (R1 x) = twoElemArrayObj opts x
625−
626−instance ( GToJSON a, ConsToJSON a
627− , Constructor c ) => TwoElemArrayObj (C1 c a) where
628− twoElemArrayObj opts x = V.create $ do
765+class TwoElemArrayObj arity f where
766+ twoElemArrayObj :: Options -> Proxy arity
767+ -> (a -> Value) -> ([a] -> Value)
768+ -> f a -> V.Vector Value
769+
770+instance ( TwoElemArrayObj arity a
771+ , TwoElemArrayObj arity b
772+ ) => TwoElemArrayObj arity (a :+: b) where
773+ twoElemArrayObj opts pa tj tjl (L1 x) = twoElemArrayObj opts pa tj tjl x
774+ twoElemArrayObj opts pa tj tjl (R1 x) = twoElemArrayObj opts pa tj tjl x
775+
776+instance ( GToJSON arity a
777+ , ConsToJSON arity a
778+ , Constructor c
779+ ) => TwoElemArrayObj arity (C1 c a) where
780+ twoElemArrayObj opts pa tj tjl x = V.create $ do
629781 mv <- VM.unsafeNew 2
630782 VM.unsafeWrite mv 0 $ String $ pack $ constructorTagModifier opts
631783 $ conName (undefined :: t c a p)
632− VM.unsafeWrite mv 1 $ gToJSON opts x
784+ VM.unsafeWrite mv 1 $ gToJSON opts pa tj tjl x
633785 return mv
634786
635787--------------------------------------------------------------------------------
636788
637−class TwoElemArrayEnc f where
638− twoElemArrayEnc :: Options -> f a -> Encoding
639−
640−instance (TwoElemArrayEnc a, TwoElemArrayEnc b) => TwoElemArrayEnc (a :+: b) where
641− twoElemArrayEnc opts (L1 x) = twoElemArrayEnc opts x
642− twoElemArrayEnc opts (R1 x) = twoElemArrayEnc opts x
643−
644−instance ( GToEncoding a, ConsToEncoding a
645− , Constructor c ) => TwoElemArrayEnc (C1 c a) where
646− twoElemArrayEnc opts x = E.tuple $
789+class TwoElemArrayEnc arity f where
790+ twoElemArrayEnc :: Options -> Proxy arity
791+ -> (a -> Encoding) -> ([a] -> Encoding)
792+ -> f a -> Encoding
793+
794+instance ( TwoElemArrayEnc arity a
795+ , TwoElemArrayEnc arity b
796+ ) => TwoElemArrayEnc arity (a :+: b) where
797+ twoElemArrayEnc opts pa te tel (L1 x) = twoElemArrayEnc opts pa te tel x
798+ twoElemArrayEnc opts pa te tel (R1 x) = twoElemArrayEnc opts pa te tel x
799+
800+instance ( GToEncoding arity a
801+ , ConsToEncoding arity a
802+ , Constructor c
803+ ) => TwoElemArrayEnc arity (C1 c a) where
804+ twoElemArrayEnc opts pa te tel x = E.tuple $
647805 toEncoding (constructorTagModifier opts (conName (undefined :: t c a p))) >*<
648− gToEncoding opts x
806+ gToEncoding opts pa te tel x
649807
650808--------------------------------------------------------------------------------
651809
652−class ConsToJSON f where
653− consToJSON :: Options -> f a -> Value
810+class ConsToJSON arity f where
811+ consToJSON :: Options -> Proxy arity
812+ -> (a -> Value) -> ([a] -> Value)
813+ -> f a -> Value
654814
655−class ConsToJSON' f isRecord where
656− consToJSON' :: Options -> Bool -- ^ Are we a record with one field?
815+class ConsToJSON' arity f isRecord where
816+ consToJSON' :: Options -> Proxy arity
817+ -> Bool -- ^ Are we a record with one field?
818+ -> (a -> Value) -> ([a] -> Value)
657819 -> f a -> Tagged isRecord Value
658820
659−instance ( IsRecord f isRecord
660− , ConsToJSON' f isRecord ) => ConsToJSON f where
661− consToJSON opts = (unTagged :: Tagged isRecord Value -> Value)
662− . consToJSON' opts (isUnary (undefined :: f a))
821+instance ( IsRecord f isRecord
822+ , ConsToJSON' arity f isRecord
823+ ) => ConsToJSON arity f where
824+ consToJSON opts pa tj tjl =
825+ (unTagged :: Tagged isRecord Value -> Value)
826+ . consToJSON' opts pa (isUnary (undefined :: f a)) tj tjl
663827
664−instance (RecordToPairs f) => ConsToJSON' f True where
665− consToJSON' opts isUn f = let
666− vals = toList $ recordToPairs opts f
828+instance (RecordToPairs arity f) => ConsToJSON' arity f True where
829+ consToJSON' opts pa isUn tj tjl f = let
830+ vals = toList $ recordToPairs opts pa tj tjl f
667831 in case (unwrapUnaryRecords opts,isUn,vals) of
668832 (True,True,[(_,val)]) -> Tagged val
669833 _ -> Tagged $ object vals
670834
671−instance GToJSON f => ConsToJSON' f False where
672− consToJSON' opts _ = Tagged . gToJSON opts
835+instance GToJSON arity f => ConsToJSON' arity f False where
836+ consToJSON' opts pa _ tj tjl = Tagged . gToJSON opts pa tj tjl
673837
674838--------------------------------------------------------------------------------
675839
676−class ConsToEncoding f where
677− consToEncoding :: Options -> f a -> Encoding
840+class ConsToEncoding arity f where
841+ consToEncoding :: Options -> Proxy arity
842+ -> (a -> Encoding) -> ([a] -> Encoding)
843+ -> f a -> Encoding
678844
679−class ConsToEncoding' f isRecord where
680− consToEncoding' :: Options -> Bool -- ^ Are we a record with one field?
845+class ConsToEncoding' arity f isRecord where
846+ consToEncoding' :: Options -> Proxy arity
847+ -> Bool -- ^ Are we a record with one field?
848+ -> (a -> Encoding) -> ([a] -> Encoding)
681849 -> f a -> Tagged isRecord Encoding
682850
683−instance ( IsRecord f isRecord
684− , ConsToEncoding' f isRecord ) => ConsToEncoding f where
685− consToEncoding opts = (unTagged :: Tagged isRecord Encoding -> Encoding)
686− . consToEncoding' opts (isUnary (undefined :: f a))
851+instance ( IsRecord f isRecord
852+ , ConsToEncoding' arity f isRecord
853+ ) => ConsToEncoding arity f where
854+ consToEncoding opts pa te tel =
855+ (unTagged :: Tagged isRecord Encoding -> Encoding)
856+ . consToEncoding' opts pa (isUnary (undefined :: f a)) te tel
687857
688−instance (RecordToEncoding f) => ConsToEncoding' f True where
689− consToEncoding' opts isUn x =
690− let (enc, mbVal) = recordToEncoding opts x
858+instance (RecordToEncoding arity f) => ConsToEncoding' arity f True where
859+ consToEncoding' opts pa isUn te tel x =
860+ let (enc, mbVal) = recordToEncoding opts pa te tel x
691861 in case (unwrapUnaryRecords opts, isUn, mbVal) of
692862 (True, True, Just val) -> Tagged val
693863 _ -> Tagged $ E.wrapObject enc
694864
695−instance GToEncoding f => ConsToEncoding' f False where
696− consToEncoding' opts _ = Tagged . gToEncoding opts
865+instance GToEncoding arity f => ConsToEncoding' arity f False where
866+ consToEncoding' opts pa _ te tel = Tagged . gToEncoding opts pa te tel
697867
698868--------------------------------------------------------------------------------
699869
700−class RecordToPairs f where
701− recordToPairs :: Options -> f a -> DList Pair
870+class RecordToPairs arity f where
871+ recordToPairs :: Options -> Proxy arity
872+ -> (a -> Value) -> ([a] -> Value)
873+ -> f a -> DList Pair
702874
703−instance (RecordToPairs a, RecordToPairs b) => RecordToPairs (a :*: b) where
704− recordToPairs opts (a :*: b) = recordToPairs opts a <>
705− recordToPairs opts b
875+instance ( RecordToPairs arity a
876+ , RecordToPairs arity b
877+ ) => RecordToPairs arity (a :*: b) where
878+ recordToPairs opts pa tj tjl (a :*: b) = recordToPairs opts pa tj tjl a <>
879+ recordToPairs opts pa tj tjl b
706880
707−instance (Selector s, GToJSON a) => RecordToPairs (S1 s a) where
881+instance (Selector s, GToJSON arity a) => RecordToPairs arity (S1 s a) where
708882 recordToPairs = fieldToPair
709883
710884instance OVERLAPPING_ (Selector s, ToJSON a) =>
711− RecordToPairs (S1 s (K1 i (Maybe a))) where
712− recordToPairs opts (M1 k1) | omitNothingFields opts
713− , K1 Nothing <- k1 = DList.empty
714− recordToPairs opts m1 = fieldToPair opts m1
715−
716−fieldToPair :: (Selector s, GToJSON a) => Options -> S1 s a p -> DList Pair
717−fieldToPair opts m1 = pure ( pack $ fieldLabelModifier opts $ selName m1
718− , gToJSON opts (unM1 m1)
719− )
885+ RecordToPairs arity (S1 s (K1 i (Maybe a))) where
886+ recordToPairs opts _ _ _ (M1 k1) | omitNothingFields opts
887+ , K1 Nothing <- k1 = DList.empty
888+ recordToPairs opts pa tj tjl m1 = fieldToPair opts pa tj tjl m1
889+
890+fieldToPair :: (Selector s, GToJSON arity a)
891+ => Options -> Proxy arity
892+ -> (p -> Value) -> ([p] -> Value)
893+ -> S1 s a p -> DList Pair
894+fieldToPair opts pa tj tjl m1 = pure ( pack $ fieldLabelModifier opts $ selName m1
895+ , gToJSON opts pa tj tjl (unM1 m1)
896+ )
720897
721898--------------------------------------------------------------------------------
722899
723−class RecordToEncoding f where
900+class RecordToEncoding arity f where
724901 -- 1st element: whole thing
725902 -- 2nd element: in case the record has only 1 field, just the value
726903 -- of the field (without the key); 'Nothing' otherwise
727− recordToEncoding :: Options -> f a -> (Encoding, Maybe Encoding)
728−
729−instance (RecordToEncoding a, RecordToEncoding b) => RecordToEncoding (a :*: b) where
730− recordToEncoding opts (a :*: b) | omitNothingFields opts =
904+ recordToEncoding :: Options -> Proxy arity
905+ -> (a -> Encoding) -> ([a] -> Encoding)
906+ -> f a -> (Encoding, Maybe Encoding)
907+
908+instance ( RecordToEncoding arity a
909+ , RecordToEncoding arity b
910+ ) => RecordToEncoding arity (a :*: b) where
911+ recordToEncoding opts pa te tel (a :*: b) | omitNothingFields opts =
731912 (mconcat $ intersperse E.comma $
732913 filter (not . E.nullEncoding)
733− [fst (recordToEncoding opts a), fst (recordToEncoding opts b)]
914+ [ fst (recordToEncoding opts pa te tel a)
915+ , fst (recordToEncoding opts pa te tel b) ]
734916 , Nothing)
735− recordToEncoding opts (a :*: b) =
736− (fst (recordToEncoding opts a) <> E.comma <>
737− fst (recordToEncoding opts b),
917+ recordToEncoding opts pa te tel (a :*: b) =
918+ (fst (recordToEncoding opts pa te tel a) <> E.comma <>
919+ fst (recordToEncoding opts pa te tel b),
738920 Nothing)
739921
740−instance (Selector s, GToEncoding a) => RecordToEncoding (S1 s a) where
922+instance (Selector s, GToEncoding arity a) => RecordToEncoding arity (S1 s a) where
741923 recordToEncoding = fieldToEncoding
742924
743925instance OVERLAPPING_ (Selector s, ToJSON a) =>
744− RecordToEncoding (S1 s (K1 i (Maybe a))) where
745− recordToEncoding opts (M1 k1) | omitNothingFields opts
746− , K1 Nothing <- k1 = (mempty, Nothing)
747− recordToEncoding opts m1 = fieldToEncoding opts m1
748−
749−fieldToEncoding :: (Selector s, GToEncoding a) => Options -> S1 s a p -> (Encoding, Maybe Encoding)
750−fieldToEncoding opts m1 =
926+ RecordToEncoding arity (S1 s (K1 i (Maybe a))) where
927+ recordToEncoding opts _ _ _ (M1 k1) | omitNothingFields opts
928+ , K1 Nothing <- k1 = (mempty, Nothing)
929+ recordToEncoding opts pa te tel m1 = fieldToEncoding opts pa te tel m1
930+
931+fieldToEncoding :: (Selector s, GToEncoding arity a)
932+ => Options -> Proxy arity
933+ -> (p -> Encoding) -> ([p] -> Encoding)
934+ -> S1 s a p -> (Encoding, Maybe Encoding)
935+fieldToEncoding opts pa te tel m1 =
751936 let keyBuilder = toEncoding (fieldLabelModifier opts $ selName m1)
752− valueBuilder = gToEncoding opts (unM1 m1)
937+ valueBuilder = gToEncoding opts pa te tel (unM1 m1)
753938 in (keyBuilder <> E.colon <> valueBuilder, Just valueBuilder)
754939
755940--------------------------------------------------------------------------------
756941
757−class WriteProduct f where
942+class WriteProduct arity f where
758943 writeProduct :: Options
944+ -> Proxy arity
759945 -> VM.MVector s Value
760946 -> Int -- ^ index
761947 -> Int -- ^ length
948+ -> (a -> Value)
949+ -> ([a] -> Value)
762950 -> f a
763951 -> ST s ()
764952
765−instance ( WriteProduct a
766− , WriteProduct b ) => WriteProduct (a :*: b) where
767− writeProduct opts mv ix len (a :*: b) = do
768− writeProduct opts mv ix lenL a
769− writeProduct opts mv ixR lenR b
953+instance ( WriteProduct arity a
954+ , WriteProduct arity b
955+ ) => WriteProduct arity (a :*: b) where
956+ writeProduct opts pa mv ix len tj tjl (a :*: b) = do
957+ writeProduct opts pa mv ix lenL tj tjl a
958+ writeProduct opts pa mv ixR lenR tj tjl b
770959 where
771960 lenL = len `unsafeShiftR` 1
772961 lenR = len - lenL
773962 ixR = ix + lenL
774963
775−instance OVERLAPPABLE_ (GToJSON a) => WriteProduct a where
776− writeProduct opts mv ix _ = VM.unsafeWrite mv ix . gToJSON opts
964+instance OVERLAPPABLE_ (GToJSON arity a) => WriteProduct arity a where
965+ writeProduct opts pa mv ix _ tj tjl =
966+ VM.unsafeWrite mv ix . gToJSON opts pa tj tjl
777967
778968--------------------------------------------------------------------------------
779969
780−class EncodeProduct f where
781− encodeProduct :: Options -> f a -> Encoding
970+class EncodeProduct arity f where
971+ encodeProduct :: Options -> Proxy arity
972+ -> (a -> Encoding) -> ([a] -> Encoding)
973+ -> f a -> Encoding
782974
783−instance ( EncodeProduct a
784− , EncodeProduct b ) => EncodeProduct (a :*: b) where
785− encodeProduct opts (a :*: b) | omitNothingFields opts =
975+instance ( EncodeProduct arity a
976+ , EncodeProduct arity b
977+ ) => EncodeProduct arity (a :*: b) where
978+ encodeProduct opts pa te tel (a :*: b) | omitNothingFields opts =
786979 mconcat $ intersperse E.comma $
787980 filter (not . E.nullEncoding)
788− [encodeProduct opts a, encodeProduct opts b]
789− encodeProduct opts (a :*: b) = encodeProduct opts a <>
790− E.comma <>
791− encodeProduct opts b
981+ [encodeProduct opts pa te tel a, encodeProduct opts pa te tel b]
982+ encodeProduct opts pa te tel (a :*: b) = encodeProduct opts pa te tel a <>
983+ E.comma <>
984+ encodeProduct opts pa te tel b
792985
793−instance OVERLAPPABLE_ (GToEncoding a) => EncodeProduct a where
986+instance OVERLAPPABLE_ (GToEncoding arity a) => EncodeProduct arity a where
794987 encodeProduct opts = gToEncoding opts
795988
796989--------------------------------------------------------------------------------
797990
798−class ObjectWithSingleFieldObj f where
799− objectWithSingleFieldObj :: Options -> f a -> Object
800−
801−instance ( ObjectWithSingleFieldObj a
802− , ObjectWithSingleFieldObj b ) => ObjectWithSingleFieldObj (a :+: b) where
803− objectWithSingleFieldObj opts (L1 x) = objectWithSingleFieldObj opts x
804− objectWithSingleFieldObj opts (R1 x) = objectWithSingleFieldObj opts x
805−
806−instance ( GToJSON a, ConsToJSON a
807− , Constructor c ) => ObjectWithSingleFieldObj (C1 c a) where
808− objectWithSingleFieldObj opts = H.singleton typ . gToJSON opts
991+class ObjectWithSingleFieldObj arity f where
992+ objectWithSingleFieldObj :: Options -> Proxy arity
993+ -> (a -> Value) -> ([a] -> Value)
994+ -> f a -> Object
995+
996+instance ( ObjectWithSingleFieldObj arity a
997+ , ObjectWithSingleFieldObj arity b
998+ ) => ObjectWithSingleFieldObj arity (a :+: b) where
999+ objectWithSingleFieldObj opts pa tj tjl (L1 x) =
1000+ objectWithSingleFieldObj opts pa tj tjl x
1001+ objectWithSingleFieldObj opts pa tj tjl (R1 x) =
1002+ objectWithSingleFieldObj opts pa tj tjl x
1003+
1004+instance ( GToJSON arity a
1005+ , ConsToJSON arity a
1006+ , Constructor c
1007+ ) => ObjectWithSingleFieldObj arity (C1 c a) where
1008+ objectWithSingleFieldObj opts pa tj tjl = H.singleton typ . gToJSON opts pa tj tjl
8091009 where
8101010 typ = pack $ constructorTagModifier opts $
8111011 conName (undefined :: t c a p)
8121012
8131013--------------------------------------------------------------------------------
8141014
815−class ObjectWithSingleFieldEnc f where
816− objectWithSingleFieldEnc :: Options -> f a -> Encoding
817−
818−instance ( ObjectWithSingleFieldEnc a
819− , ObjectWithSingleFieldEnc b ) => ObjectWithSingleFieldEnc (a :+: b) where
820− objectWithSingleFieldEnc opts (L1 x) = objectWithSingleFieldEnc opts x
821− objectWithSingleFieldEnc opts (R1 x) = objectWithSingleFieldEnc opts x
822−
823−instance ( GToEncoding a, ConsToEncoding a
824− , Constructor c ) => ObjectWithSingleFieldEnc (C1 c a) where
825− objectWithSingleFieldEnc opts v =
1015+class ObjectWithSingleFieldEnc arity f where
1016+ objectWithSingleFieldEnc :: Options -> Proxy arity
1017+ -> (a -> Encoding) -> ([a] -> Encoding)
1018+ -> f a -> Encoding
1019+
1020+instance ( ObjectWithSingleFieldEnc arity a
1021+ , ObjectWithSingleFieldEnc arity b
1022+ ) => ObjectWithSingleFieldEnc arity (a :+: b) where
1023+ objectWithSingleFieldEnc opts pa te tel (L1 x) =
1024+ objectWithSingleFieldEnc opts pa te tel x
1025+ objectWithSingleFieldEnc opts pa te tel (R1 x) =
1026+ objectWithSingleFieldEnc opts pa te tel x
1027+
1028+instance ( GToEncoding arity a
1029+ , ConsToEncoding arity a
1030+ , Constructor c
1031+ ) => ObjectWithSingleFieldEnc arity (C1 c a) where
1032+ objectWithSingleFieldEnc opts pa te tel v =
8261033 E.openCurly <>
8271034 toEncoding
8281035 (constructorTagModifier opts
8291036 (conName (undefined :: t c a p))) <>
8301037 E.colon <>
831− gToEncoding opts v <>
1038+ gToEncoding opts pa te tel v <>
8321039 E.closeCurly
8331040
8341041-------------------------------------------------------------------------------
8351042-- Instances
8361043-------------------------------------------------------------------------------
8371044
838−
839−
8401045-------------------------------------------------------------------------------
8411046-- base
8421047-------------------------------------------------------------------------------