on master help sign in
Solved conflicts and improved documentation of FromJSON and ToJSON
commit53c92343868677f969b0ad7b8a5163eb1e77765e authorBas van Dijk <v.dijk.bas@gmail.com> dateSat 29 Oct 2011, 18:52 (15 years ago) parentbb691cdb72b7a2
4 files changed+325−138
Data/Aeson.hs+20−5 Data/Aeson/TH.hs+242−109 Data/Aeson/Types/Internal.hs+48−22 aeson.cabal+15−2
Data/Aeson.hs+20−5
@@ -12,8 +12,11 @@
1212
1313module Data.Aeson
1414 (
15+ -- * Encoding and decoding
16+ decode
17+ , encode
1518 -- * Core JSON types
16− Value(..)
19+ , Value(..)
1720 , Array
1821 , Object
1922 -- * Convenience types
@@ -28,11 +31,23 @@ module Data.Aeson
2831 , (.:)
2932 , (.:?)
3033 , object
31− -- * Encoding and parsing
32− , encode
34+ -- * Parsing
3335 , json
3436 ) where
3537
36−import Data.Aeson.Encode
37−import Data.Aeson.Parser
38+import Data.Aeson.Encode (encode)
39+import Data.Aeson.Parser (json)
3840import Data.Aeson.Types
41+import qualified Data.ByteString.Lazy as L
42+import qualified Data.Attoparsec.Lazy as L
43+
44+-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
45+-- If this fails due to incomplete or invalid input, 'Nothing' is
46+-- returned.
47+decode :: (FromJSON a) => L.ByteString -> Maybe a
48+decode s = case L.parse json s of
49+ L.Done _ v -> case fromJSON v of
50+ Success a -> Just a
51+ _ -> Nothing
52+ _ -> Nothing
53+{-# INLINE decode #-}
Data/Aeson/TH.hs+242−109
@@ -47,21 +47,21 @@ instance 'ToJSON' a => 'ToJSON' (D a) where
4747 \value ->
4848 case value of
4949 Nullary ->
50− 'object' ['T.pack' \"Nullary\" .= 'toJSON' ([] :: [()])]
50+ 'object' [T.pack \"Nullary\" .= 'toJSON' ([] :: [()])]
5151 Unary arg1 ->
52− 'object' ['T.pack' \"Unary\" .= 'toJSON' arg1]
52+ 'object' [T.pack \"Unary\" .= 'toJSON' arg1]
5353 Product arg1 arg2 arg3 ->
54− 'object' [ 'T.pack' \"Product\"
54+ 'object' [ T.pack \"Product\"
5555 .= 'toJSON' [ 'toJSON' arg1
5656 , 'toJSON' arg2
5757 , 'toJSON' arg3
5858 ]
5959 ]
6060 Record arg1 arg2 arg3 ->
61− 'object' [ 'T.pack' \"Record\"
62− .= 'object' [ 'T.pack' \"One\" '.=' arg1
63− , 'T.pack' \"Two\" '.=' arg2
64− , 'T.pack' \"Three\" '.=' arg3
61+ 'object' [ T.pack \"Record\"
62+ .= 'object' [ T.pack \"One\" '.=' arg1
63+ , T.pack \"Two\" '.=' arg2
64+ , T.pack \"Three\" '.=' arg3
6565 ]
6666 ]
6767@
@@ -72,35 +72,45 @@ instance 'FromJSON' a => 'FromJSON' (D a) where
7272 \value ->
7373 case value of
7474 'Object' obj ->
75− case 'M.toList' obj of
75+ case M.toList obj of
7676 [(conKey, conVal)] ->
77− case conKey of
78− _ | (conKey '==' 'T.pack' \"Nullary\") ->
79− case conVal of
80− 'Array' arr | 'V.null' arr -> 'pure' Nullary
81− _ -> 'mzero'
82− | (conKey '==' 'T.pack' \"Unary\") ->
83− case conVal of
84− arg -> Unary '<$>' 'parseJSON' arg
85− | (conKey '==' 'T.pack' \"Product\") ->
86− case conVal of
87− 'Array' arr | 'V.length' arr '==' 3 ->
88− 'Product' '<$>' 'parseJSON' (arr 'V.!' 0)
89− '<*>' 'parseJSON' (arr 'V.!' 1)
90− '<*>' 'parseJSON' (arr 'V.!' 2)
91− _ -> 'mzero'
92− | (conKey '==' 'T.pack' \"Record\") ->
93− case conVal of
94− 'Object' obj ->
95− Record '<$>' (obj '.:' 'T.pack' \"One\")
96− '<*>' (obj '.:' 'T.pack' \"Two\")
97− '<*>' (obj '.:' 'T.pack' \"Three\")
98− _ -> 'mzero'
99− | 'otherwise' -> 'mzero'
100− _ -> 'mzero'
101− _ -> 'mzero'
77+ case conKey of
78+ _ | conKey == T.pack \"Nullary\" ->
79+ case conVal of
80+ 'Array' arr ->
81+ if V.null arr
82+ then pure Nullary
83+ else fail \"\<error message\>\"
84+ _ -> fail \"\<error message\>\"
85+ | conKey == T.pack \"Unary\" ->
86+ case conVal of
87+ arg -> Unary \<$\> parseJSON arg
88+ | conKey == T.pack \"Product\" ->
89+ case conVal of
90+ 'Array' arr ->
91+ if V.length arr == 3
92+ then Product \<$\> 'parseJSON' (arr V.! 0)
93+ \<*\> 'parseJSON' (arr V.! 1)
94+ \<*\> 'parseJSON' (arr V.! 2)
95+ else fail \"\<error message\>\"
96+ _ -> fail \"\<error message\>\"
97+ | conKey == T.pack \"Record\" ->
98+ case conVal of
99+ 'Object' recObj ->
100+ if M.size recObj == 3
101+ then Record \<$\> recObj '.:' T.pack \"One\"
102+ \<*\> recObj '.:' T.pack \"Two\"
103+ \<*\> recObj '.:' T.pack \"Three\"
104+ else fail \"\<error message\>\"
105+ _ -> fail \"\<error message\>\"
106+ | otherwise -> fail \"\<error message\>\"
107+ _ -> fail \"\<error message\>\"
108+ _ -> fail \"\<error message\>\"
102109@
103110
111+Note that every \"\<error message\>\" is in fact a descriptive message which
112+provides as much information as is reasonable about the failed parse.
113+
104114Now we can use the newly created instances.
105115
106116@
@@ -114,6 +124,13 @@ d = Record { testOne = 3.14159
114124>>> fromJSON (toJSON d) == Success d
115125> True
116126
127+Please note that you can derive instances for tuples using the following syntax:
128+
129+@
130+-- FromJSON and ToJSON instances for 4-tuples.
131+$('deriveJSON' id ''(,,,))
132+@
133+
117134-}
118135
119136module Data.Aeson.TH
@@ -131,31 +148,35 @@ module Data.Aeson.TH
131148--------------------------------------------------------------------------------
132149
133150-- from aeson:
134−import Data.Aeson ( toJSON, object, (.=), (.:)
151+import Data.Aeson ( toJSON, Object, object, (.=)
135152 , ToJSON, toJSON
136153 , FromJSON, parseJSON
137154 )
138−import Data.Aeson.Types ( Value(..) )
155+import Data.Aeson.Types ( Value(..), Parser )
139156-- from base:
140157import Control.Applicative ( pure, (<$>), (<*>) )
141−import Control.Monad ( return, mapM, mzero, liftM2 )
158+import Control.Monad ( return, mapM, liftM2, fail )
142159import Data.Bool ( otherwise )
143160import Data.Eq ( (==) )
144161import Data.Function ( ($), (.), id )
145162import Data.Functor ( fmap )
146−import Data.List ( (++), foldl', map, zip, genericLength )
163+import Data.List ( (++), foldl, foldl', intercalate
164+ , length, map, zip, genericLength
165+ )
166+import Data.Maybe ( Maybe(Nothing, Just) )
147167import Prelude ( String, (-), Integer, error )
168+import Text.Printf ( printf )
148169import Text.Show ( show )
149170#if __GLASGOW_HASKELL__ < 700
150171import Control.Monad ( (>>=), fail )
151172import Prelude ( fromInteger )
152173#endif
153174-- from containers:
154−import qualified Data.Map as M ( toList )
175+import qualified Data.Map as M ( lookup, toList, size )
155176-- from template-haskell:
156177import Language.Haskell.TH
157178-- from text:
158−import qualified Data.Text as T ( pack )
179+import qualified Data.Text as T ( Text, pack, unpack )
159180-- from vector:
160181import qualified Data.Vector as V ( (!), null, length )
161182
@@ -241,12 +262,12 @@ deriveToJSON withField name =
241262-- Example:
242263--
243264-- @
244−-- data Foo = Foo 'Int'
265+-- data Foo = Foo Int
245266-- @
246267--
247268-- @
248269-- encodeFoo :: Foo -> 'Value'
249−-- encodeFoo = $('mkToJSON' 'id' ''Foo)
270+-- encodeFoo = $('mkToJSON' id ''Foo)
250271-- @
251272--
252273-- This will splice in the following code:
@@ -352,8 +373,8 @@ encodeArgs withExp withField (ForallC _ _ con) =
352373-- Example:
353374--
354375-- @
355−-- data Foo = Foo 'Char' 'Int'
356−-- $('deriveFromJSON' 'id' ''Foo)
376+-- data Foo = Foo Char Int
377+-- $('deriveFromJSON' id ''Foo)
357378-- @
358379--
359380-- This will splice in the following code:
@@ -362,10 +383,12 @@ encodeArgs withExp withField (ForallC _ _ con) =
362383-- instance 'FromJSON' Foo where
363384-- 'parseJSON' =
364385-- \value -> case value of
365−-- 'Array' arr | ('V.length' arr '==' 2) ->
366−-- Foo '<$>' 'parseJSON' (arr 'V.!' 0)
367−-- '<*>' 'parseJSON' (arr 'V.!' 1)
368−-- _ -> 'mzero'
386+-- 'Array' arr ->
387+-- if (V.length arr == 2)
388+-- then Foo \<$\> 'parseJSON' (arr V.! 0)
389+-- \<*\> 'parseJSON' (arr V.! 1)
390+-- else fail \"\<error message\>\"
391+-- other -> fail \"\<error message\>\"
369392-- @
370393deriveFromJSON :: (String -> String)
371394 -- ^ Function to change field names.
@@ -382,7 +405,7 @@ deriveFromJSON withField name =
382405 (classType `appT` instanceType)
383406 [ funD 'parseJSON
384407 [ clause []
385− (normalB $ consFromJSON withField cons)
408+ (normalB $ consFromJSON name withField cons)
386409 []
387410 ]
388411 ]
@@ -402,36 +425,38 @@ deriveFromJSON withField name =
402425--
403426-- @
404427-- parseFoo :: 'Value' -> 'Parser' Foo
405−-- parseFoo = $('mkParseJSON' 'id' ''Foo)
428+-- parseFoo = $('mkParseJSON' id ''Foo)
406429-- @
407430--
408431-- This will splice in the following code:
409432--
410433-- @
411−-- \\value -> case value of arg -> Foo '<$>' 'parseJSON' arg
434+-- \\value -> case value of arg -> Foo \<$\> 'parseJSON' arg
412435-- @
413436mkParseJSON :: (String -> String) -- ^ Function to change field names.
414437 -> Name -- ^ Name of the encoded type.
415438 -> Q Exp
416439mkParseJSON withField name =
417− withType name (\_ cons -> consFromJSON withField cons)
440+ withType name (\_ cons -> consFromJSON name withField cons)
418441
419442-- | Helper function used by both 'deriveFromJSON' and 'mkParseJSON'. Generates
420443-- code to parse the JSON encoding of a number of constructors. All constructors
421444-- must be from the same type.
422−consFromJSON :: (String -> String)
445+consFromJSON :: Name
446+ -- ^ Name of the type to which the constructors belong.
447+ -> (String -> String)
423448 -- ^ Function to change field names.
424449 -> [Con]
425450 -- ^ Constructors for which to generate JSON parsing code.
426451 -> Q Exp
427−consFromJSON _ [] = error $ "Data.Aeson.TH.consFromJSON: "
428− ++ "Not a single constructor given!"
429−consFromJSON withField [con] = do
452+consFromJSON _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
453+ ++ "Not a single constructor given!"
454+consFromJSON tName withField [con] = do
430455 value <- newName "value"
431456 lam1E (varP value)
432457 $ caseE (varE value)
433− (parseArgs withField con)
434−consFromJSON withField cons = do
458+ (parseArgs tName withField con)
459+consFromJSON tName withField cons = do
435460 value <- newName "value"
436461 obj <- newName "obj"
437462 conKey <- newName "conKey"
@@ -444,8 +469,15 @@ consFromJSON withField cons = do
444469 [ match (listP [tupP [varP conKey, varP conVal]])
445470 (normalB caseKey)
446471 []
447− , errorMatch
472+ , do other <- newName "other"
473+ match (varP other)
474+ (normalB $ [|wrongPairCountFail|]
475+ `appE` (litE $ stringL $ show tName)
476+ `appE` ([|show . length|] `appE` varE other)
477+ )
478+ []
448479 ]
480+
449481 caseKey = caseE (varE conKey)
450482 [match wildP (guardedB guards) []]
451483 guards = [ do g <- normalG $ infixApp (varE conKey)
@@ -454,44 +486,59 @@ consFromJSON withField cons = do
454486 `appE` conNameExp con
455487 )
456488 e <- caseE (varE conVal)
457− (parseArgs withField con)
489+ (parseArgs tName withField con)
458490 return (g, e)
459491 | con <- cons
460492 ]
461493 ++
462− [liftM2 (,) (normalG [e|otherwise|]) [e|mzero|]]
494+ [ liftM2 (,)
495+ (normalG [e|otherwise|])
496+ ( [|conNotFoundFail|]
497+ `appE` (litE $ stringL $ show tName)
498+ `appE` listE (map (litE . stringL . nameBase . getConName) cons)
499+ `appE` ([|T.unpack|] `appE` varE conKey)
500+ )
501+ ]
463502
464503 lam1E (varP value)
465504 $ caseE (varE value)
466505 [ match (conP 'Object [varP obj])
467506 (normalB caseLst)
468507 []
469− , errorMatch
508+ , do other <- newName "other"
509+ match (varP other)
510+ ( normalB
511+ $ [|noObjectFail|]
512+ `appE` (litE $ stringL $ show tName)
513+ `appE` ([|valueConName|] `appE` varE other)
514+ )
515+ []
470516 ]
471− where
472− -- Makes a string literal expression from a constructor's name.
473− conNameExp :: Con -> Q Exp
474− conNameExp = litE . stringL . nameBase . getConName
475517
476−-- | Generates code to parse the JSON encoding of a single
477−-- constructor.
478−parseArgs :: (String -> String) -- ^ Function to change field names.
518+-- | Generates code to parse the JSON encoding of a single constructor.
519+parseArgs :: Name -- ^ Name of the type to which the constructor belongs.
520+ -> (String -> String) -- ^ Function to change field names.
479521 -> Con -- ^ Constructor for which to generate JSON parsing code.
480522 -> [Q Match]
481523-- Nullary constructors.
482−parseArgs _ (NormalC conName []) =
524+parseArgs tName _ (NormalC conName []) =
483525 [ do arr <- newName "arr"
484− g <- normalG $ [|V.null|] `appE` varE arr
485− e <- [e|pure|] `appE` conE conName
486− -- TODO: Use applicative style: guardedB [(,) <$> g' <*> e']
487− -- But first need to have "instance Applicative Q".
488526 match (conP 'Array [varP arr])
489− (guardedB [return (g, e)])
527+ ( normalB $ condE ([|V.null|] `appE` varE arr)
528+ ([e|pure|] `appE` conE conName)
529+ ( parseTypeMismatch tName conName
530+ (litE $ stringL "an empty Array")
531+ ( infixApp (litE $ stringL $ "Array of length ")
532+ [|(++)|]
533+ ([|show . V.length|] `appE` varE arr)
534+ )
535+ )
536+ )
490537 []
491− , errorMatch
538+ , matchFailed tName conName "Array"
492539 ]
493540-- Unary constructors.
494−parseArgs _ (NormalC conName [_]) =
541+parseArgs _ _ (NormalC conName [_]) =
495542 [ do arg <- newName "arg"
496543 match (varP arg)
497544 ( normalB $ infixApp (conE conName)
@@ -500,46 +547,59 @@ parseArgs _ (NormalC conName [_]) =
500547 )
501548 []
502549 ]
503−
504550-- Polyadic constructors.
505−parseArgs _ (NormalC conName ts) = parseProduct conName $ genericLength ts
551+parseArgs tName _ (NormalC conName ts) = parseProduct tName conName $ genericLength ts
506552-- Records.
507−parseArgs withField (RecC conName ts) =
508− [ do obj <- newName "obj"
509− -- List of: "obj .: "<FIELD>""
510− let x:xs = [ infixApp (varE obj)
511− [|(.:)|]
512− ( [e|T.pack|]
513− `appE`
514− fieldNameExp withField field
515− )
553+parseArgs tName withField (RecC conName ts) =
554+ [ do obj <- newName "recObj"
555+ let x:xs = [ [|lookupField|]
556+ `appE` (litE $ stringL $ show tName)
557+ `appE` (litE $ stringL $ nameBase conName)
558+ `appE` (varE obj)
559+ `appE` ( [e|T.pack|]
560+ `appE`
561+ fieldNameExp withField field
562+ )
516563 | (field, _, _) <- ts
517564 ]
518565 match (conP 'Object [varP obj])
519− ( normalB $ foldl' (\a b -> infixApp a [|(<*>)|] b)
520− (infixApp (conE conName) [|(<$>)|] x)
521− xs
566+ ( normalB $ condE ( infixApp ([|M.size|] `appE` varE obj)
567+ [|(==)|]
568+ (litE $ integerL $ genericLength ts)
569+ )
570+ ( foldl' (\a b -> infixApp a [|(<*>)|] b)
571+ (infixApp (conE conName) [|(<$>)|] x)
572+ xs
573+ )
574+ ( parseTypeMismatch tName conName
575+ ( litE $ stringL $ "Object with "
576+ ++ show (length ts)
577+ ++ " name/value pairs"
578+ )
579+ ( infixApp ([|show . M.size|] `appE` varE obj)
580+ [|(++)|]
581+ (litE $ stringL $ " name/value pairs")
582+ )
583+ )
522584 )
523585 []
524− , errorMatch
586+ , matchFailed tName conName "Object"
525587 ]
526588-- Infix constructors. Apart from syntax these are the same as
527589-- polyadic constructors.
528−parseArgs _ (InfixC _ conName _) = parseProduct conName 2
590+parseArgs tName _ (InfixC _ conName _) = parseProduct tName conName 2
529591-- Existentially quantified constructors. We ignore the quantifiers
530592-- and proceed with the contained constructor.
531−parseArgs withField (ForallC _ _ con) = parseArgs withField con
593+parseArgs tName withField (ForallC _ _ con) = parseArgs tName withField con
532594
533595-- | Generates code to parse the JSON encoding of an n-ary
534596-- constructor.
535−parseProduct :: Name -- ^ 'Con'structor name.
597+parseProduct :: Name -- ^ Name of the type to which the constructor belongs.
598+ -> Name -- ^ 'Con'structor name.
536599 -> Integer -- ^ 'Con'structor arity.
537600 -> [Q Match]
538−parseProduct conName numArgs =
601+parseProduct tName conName numArgs =
539602 [ do arr <- newName "arr"
540− g <- normalG $ infixApp ([|V.length|] `appE` varE arr)
541− [|(==)|]
542− (litE $ integerL numArgs)
543603 -- List of: "parseJSON (arr V.! <IX>)"
544604 let x:xs = [ [|parseJSON|]
545605 `appE`
@@ -548,21 +608,81 @@ parseProduct conName numArgs =
548608 (litE $ integerL ix)
549609 | ix <- [0 .. numArgs - 1]
550610 ]
551− e <- foldl' (\a b -> infixApp a [|(<*>)|] b)
552− (infixApp (conE conName) [|(<$>)|] x)
553− xs
554611 match (conP 'Array [varP arr])
555− (guardedB [return (g, e)])
612+ (normalB $ condE ( infixApp ([|V.length|] `appE` varE arr)
613+ [|(==)|]
614+ (litE $ integerL numArgs)
615+ )
616+ ( foldl' (\a b -> infixApp a [|(<*>)|] b)
617+ (infixApp (conE conName) [|(<$>)|] x)
618+ xs
619+ )
620+ ( parseTypeMismatch tName conName
621+ (litE $ stringL $ "Array of length " ++ show numArgs)
622+ ( infixApp (litE $ stringL $ "Array of length ")
623+ [|(++)|]
624+ ([|show . V.length|] `appE` varE arr)
625+ )
626+ )
627+ )
556628 []
557− , errorMatch
629+ , matchFailed tName conName "Array"
558630 ]
559631
560−-- |
561−-- @
562−-- _ -> 'mzero'
563−-- @
564−errorMatch :: Q Match
565−errorMatch = match wildP (normalB [|mzero|]) []
632+
633+--------------------------------------------------------------------------------
634+-- Parsing errors
635+--------------------------------------------------------------------------------
636+
637+matchFailed :: Name -> Name -> String -> MatchQ
638+matchFailed tName conName expected = do
639+ other <- newName "other"
640+ match (varP other)
641+ ( normalB $ parseTypeMismatch tName conName
642+ (litE $ stringL expected)
643+ ([|valueConName|] `appE` varE other)
644+ )
645+ []
646+
647+parseTypeMismatch :: Name -> Name -> ExpQ -> ExpQ -> ExpQ
648+parseTypeMismatch tName conName expected actual =
649+ foldl appE
650+ [|parseTypeMismatch'|]
651+ [ litE $ stringL $ nameBase conName
652+ , litE $ stringL $ show tName
653+ , expected
654+ , actual
655+ ]
656+
657+lookupField :: (FromJSON a) => String -> String -> Object -> T.Text -> Parser a
658+lookupField tName rec obj key =
659+ case M.lookup key obj of
660+ Nothing -> unknownFieldFail tName rec (T.unpack key)
661+ Just v -> parseJSON v
662+
663+unknownFieldFail :: String -> String -> String -> Parser fail
664+unknownFieldFail tName rec key =
665+ fail $ printf "When parsing the record %s of type %s the key %s was not present."
666+ rec tName key
667+
668+noObjectFail :: String -> String -> Parser fail
669+noObjectFail t o =
670+ fail $ printf "When parsing %s expected Object but got %s." t o
671+
672+wrongPairCountFail :: String -> String -> Parser fail
673+wrongPairCountFail t n =
674+ fail $ printf "When parsing %s expected an Object with a single name/value pair but got %s pairs."
675+ t n
676+
677+conNotFoundFail :: String -> [String] -> String -> Parser fail
678+conNotFoundFail t cs o =
679+ fail $ printf "When parsing %s expected an Object with a name/value pair where the name is one of [%s], but got %s."
680+ t (intercalate ", " cs) o
681+
682+parseTypeMismatch' :: String -> String -> String -> String -> Parser fail
683+parseTypeMismatch' tName conName expected actual =
684+ fail $ printf "When parsing the constructor %s of type %s expected %s but got %s."
685+ conName tName expected actual
566686
567687
568688--------------------------------------------------------------------------------
@@ -604,8 +724,21 @@ tvbName :: TyVarBndr -> Name
604724tvbName (PlainTV name ) = name
605725tvbName (KindedTV name _) = name
606726
727+-- | Makes a string literal expression from a constructor's name.
728+conNameExp :: Con -> Q Exp
729+conNameExp = litE . stringL . nameBase . getConName
730+
607731-- | Creates a string literal expression from a record field name.
608732fieldNameExp :: (String -> String) -- ^ Function to change the field name.
609733 -> Name
610734 -> Q Exp
611735fieldNameExp f = litE . stringL . f . nameBase
736+
737+-- | The name of the outermost 'Value' constructor.
738+valueConName :: Value -> String
739+valueConName (Object _) = "Object"
740+valueConName (Array _) = "Array"
741+valueConName (String _) = "String"
742+valueConName (Number _) = "Number"
743+valueConName (Bool _) = "Boolean"
744+valueConName Null = "Null"
Data/Aeson/Types/Internal.hs+48−22
@@ -313,20 +313,36 @@ object = Object . M.fromList
313313--
314314-- An example type and instance:
315315--
316−-- @data Coord { x :: Double, y :: Double }
316+-- @{-\# LANGUAGE OverloadedStrings #-}
317+--
318+-- data Coord { x :: Double, y :: Double }
317319--
318320-- instance ToJSON Coord where
319321-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
320322-- @
321323--
322−-- This example assumes the OverloadedStrings language option is enabled.
324+-- Note the use of the @OverloadedStrings@ language extension which enables
325+-- 'Text' values to be written as string literals.
323326--
324−-- If your compiler has support for the @DeriveGeneric@ and @DefaultSignatures@
325−-- language extensions, @toJSON@ will have a default generic implementation.
327+-- Instead of manually writing your 'ToJSON' instance, there are three options
328+-- to do it automatically:
326329--
327−-- To use this, simply add a @deriving 'Generic'@ clause to your datatype and
328−-- declare a @ToJSON@ instance for your datatype without giving a definition for
329−-- @toJSON@. For example the previous example can be simplified to just:
330+-- * 'Data.Aeson.TH' provides template-haskell functions which will derive an
331+-- instance at compile-time. The generated instance is optimized for your type
332+-- so will probably be more efficient than the following two options:
333+--
334+-- * 'Data.Aeson.Generic' provides a generic @toJSON@ function that accepts any
335+-- type which is an instance of 'Data'.
336+--
337+-- * If your compiler has support for the @DeriveGeneric@ and
338+-- @DefaultSignatures@ language extensions, @toJSON@ will have a default generic
339+-- implementation.
340+--
341+-- To use the latter option, simply add a @deriving 'Generic'@ clause to your
342+-- datatype and declare a @ToJSON@ instance for your datatype without giving a
343+-- definition for @toJSON@.
344+--
345+-- For example the previous example can be simplified to just:
330346--
331347-- @{-\# LANGUAGE DeriveGeneric \#-}
332348--
@@ -336,9 +352,6 @@ object = Object . M.fromList
336352--
337353-- instance ToJSON Coord
338354-- @
339−--
340−-- (Another way to automatically derive a @ToJSON@ instance is to use the
341−-- template-haskell template 'deriveToJSON' from "Data.Aeson.TH".)
342355class ToJSON a where
343356 toJSON :: a -> Value
344357
@@ -356,25 +369,41 @@ class ToJSON a where
356369--
357370-- An example type and instance:
358371--
359−-- @data Coord { x :: Double, y :: Double }
372+-- @{-\# LANGUAGE OverloadedStrings #-}
360373--
374+-- data Coord { x :: Double, y :: Double }
375+--
361376-- instance FromJSON Coord where
362−-- parseJSON ('Object' v) = Coord '<$>'
363−-- v '.:' \"x\" '<*>'
364−-- v '.:' \"y\"
377+-- parseJSON ('Object' v) = Coord '<$>'
378+-- v '.:' \"x\" '<*>'
379+-- v '.:' \"y\"
365380--
366381-- \-- A non-'Object' value is of the wrong type, so use 'mzero' to fail.
367382-- parseJSON _ = 'mzero'
368383-- @
369384--
370−-- This example assumes the OverloadedStrings language option is enabled.
385+-- Note the use of the @OverloadedStrings@ language extension which enables
386+-- 'Text' values to be written as string literals.
371387--
372−-- If your compiler has support for the @DeriveGeneric@ and @DefaultSignatures@
373−-- language extensions, @parseJSON@ will have a default generic implementation.
388+-- Instead of manually writing your 'FromJSON' instance, there are three options
389+-- to do it automatically:
390+--
391+-- * 'Data.Aeson.TH' provides template-haskell functions which will derive an
392+-- instance at compile-time. The generated instance is optimized for your type
393+-- so will probably be more efficient than the following two options:
394+--
395+-- * 'Data.Aeson.Generic' provides a generic @fromJSON@ function that parses to
396+-- any type which is an instance of 'Data'.
397+--
398+-- * If your compiler has support for the @DeriveGeneric@ and
399+-- @DefaultSignatures@ language extensions, @parseJSON@ will have a default
400+-- generic implementation.
374401--
375402-- To use this, simply add a @deriving 'Generic'@ clause to your datatype and
376−-- declare a @FromJSON@ instance for your datatype without giving a definition for
377−-- @parseJSON@. For example the previous example can be simplified to just:
403+-- declare a @FromJSON@ instance for your datatype without giving a definition
404+-- for @parseJSON@.
405+--
406+-- For example the previous example can be simplified to just:
378407--
379408-- @{-\# LANGUAGE DeriveGeneric \#-}
380409--
@@ -384,9 +413,6 @@ class ToJSON a where
384413--
385414-- instance FromJSON Coord
386415-- @
387−--
388−-- (Another way to automatically derive a @FromJSON@ instance is to use the
389−-- template-haskell template 'deriveFromJSON' from "Data.Aeson.TH".)
390416class FromJSON a where
391417 parseJSON :: Value -> Parser a
392418
aeson.cabal+15−2
@@ -17,6 +17,9 @@ description:
1717 A JSON parsing and encoding library optimized for ease of use
1818 and high performance.
1919 .
20+ To get started, see the documentation for the @Data.Aeson@ module
21+ below.
22+ .
2023 /Note/: if you use GHCi or Template Haskell, please see the
2124 @README@ file for important details about building this package,
2225 and other packages that depend on it:
@@ -102,6 +105,9 @@ flag developer
102105 description: operate in developer mode
103106 default: False
104107
108+flag old-deepseq-containers
109+ default: False
110+
105111library
106112 exposed-modules:
107113 Data.Aeson
@@ -121,8 +127,6 @@ library
121127 blaze-builder >= 0.2.1.4,
122128 blaze-textual >= 0.2.0.2,
123129 bytestring,
124− containers,
125− deepseq < 1.2,
126130 hashable >= 1.1.2.0,
127131 mtl,
128132 old-locale,
@@ -133,6 +137,15 @@ library
133137 unordered-containers >= 0.1.3.0,
134138 vector >= 0.7.1
135139
140+ if flag(old-deepseq-containers)
141+ build-depends:
142+ containers < 0.4.2,
143+ deepseq < 1.2
144+ else
145+ build-depends:
146+ containers >= 0.4.2,
147+ deepseq >= 1.2
148+
136149 if flag(developer)
137150 ghc-options: -Werror
138151 ghc-prof-options: -auto-all