on master help sign in
Start working on release notes and expanded examples.
commiteb3e4d3cf8cd715a8023db25282ae361f3efb46f authorBryan O'Sullivan <bos@serpentine.com> dateWed 30 Nov 2011, 19:58 (15 years ago) parented97238
6 files changed+153−33
Data/Aeson/Generic.hs+27−4 aeson.cabal+12−7 examples/Generic.hs+38 examples/GenericSYB.hs+30 examples/Simplest.hs+19−22 release-notes.markdown+27
Data/Aeson/Generic.hs+27−4
@@ -16,14 +16,18 @@
1616
1717module Data.Aeson.Generic
1818 (
19− fromJSON
19+ -- * Decoding and encoding
20+ decode
21+ , encode
22+ -- * Lower-level conversion functions
23+ , fromJSON
2024 , toJSON
2125 ) where
2226
2327import Control.Applicative ((<$>))
2428import Control.Arrow (first)
2529import Control.Monad.State.Strict
26−import Data.Aeson.Functions
30+import Data.Aeson.Functions hiding (decode)
2731import Data.Aeson.Types hiding (FromJSON(..), ToJSON(..), fromJSON)
2832import Data.Attoparsec.Number (Number)
2933import Data.Generics
@@ -35,7 +39,11 @@ import Data.Text (Text, pack, unpack)
3539import Data.Text.Encoding (encodeUtf8)
3640import Data.Time.Clock (UTCTime)
3741import Data.Word (Word, Word8, Word16, Word32, Word64)
42+import Data.Aeson.Parser (json)
43+import qualified Data.Aeson.Encode as E
44+import qualified Data.Aeson.Functions as F
3845import qualified Data.Aeson.Types as T
46+import qualified Data.Attoparsec.Lazy as L
3947import qualified Data.ByteString as B
4048import qualified Data.ByteString.Lazy as L
4149import qualified Data.HashMap.Strict as H
@@ -46,6 +54,21 @@ import qualified Data.Text.Lazy as LT
4654import qualified Data.Traversable as T
4755import qualified Data.Vector as V
4856
57+-- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.
58+encode :: (Data a) => a -> L.ByteString
59+encode = E.encode . toJSON
60+{-# INLINE encode #-}
61+
62+-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
63+-- If this fails due to incomplete or invalid input, 'Nothing' is
64+-- returned.
65+decode :: (Data a) => L.ByteString -> Maybe a
66+decode s = case L.parse json s of
67+ L.Done _ v -> case fromJSON v of
68+ Success a -> Just a
69+ _ -> Nothing
70+ _ -> Nothing
71+
4972type T a = a -> Value
5073
5174toJSON :: (Data a) => a -> Value
@@ -93,7 +116,7 @@ toJSON = toJSON_generic
93116 | tyrep == typeOf DT.empty = remap id
94117 | tyrep == typeOf LT.empty = remap LT.toStrict
95118 | tyrep == typeOf "" = remap pack
96− | tyrep == typeOf B.empty = remap decode
119+ | tyrep == typeOf B.empty = remap F.decode
97120 | tyrep == typeOf L.empty = remap strict
98121 | otherwise = modError "toJSON" $
99122 "cannot convert map keyed by type " ++ show tyrep
@@ -104,7 +127,7 @@ toJSON = toJSON_generic
104127 | tyrep == typeOf DT.empty = remap id
105128 | tyrep == typeOf LT.empty = remap LT.toStrict
106129 | tyrep == typeOf "" = remap pack
107− | tyrep == typeOf B.empty = remap decode
130+ | tyrep == typeOf B.empty = remap F.decode
108131 | tyrep == typeOf L.empty = remap strict
109132 | otherwise = modError "toJSON" $
110133 "cannot convert map keyed by type " ++ show tyrep
aeson.cabal+12−7
@@ -3,15 +3,16 @@ version: 0.4.0.0
33license: BSD3
44license-file: LICENSE
55category: Text, Web, JSON
6−copyright: Copyright 2011 MailRank, Inc.
6+copyright: (c) 2011 Bryan O'Sullivan
7+ (c) 2011 MailRank, Inc.
78author: Bryan O'Sullivan <bos@serpentine.com>
89maintainer: Bryan O'Sullivan <bos@serpentine.com>
910stability: experimental
10−tested-with: GHC == 6.12.3
11+tested-with: GHC == 6.12.3, GHC == 7.0.4, GHC == 7.2.2
1112synopsis: Fast JSON parsing and encoding
1213cabal-version: >= 1.8
13−homepage: http://github.com/bos/aeson
14−bug-reports: http://github.com/bos/aeson/issues
14+homepage: https://github.com/bos/aeson
15+bug-reports: https://github.com/bos/aeson/issues
1516build-type: Simple
1617description:
1718 A JSON parsing and encoding library optimized for ease of use
@@ -20,6 +21,9 @@ description:
2021 To get started, see the documentation for the @Data.Aeson@ module
2122 below.
2223 .
24+ For release notes, see
25+ <https://github.com/bos/aeson/blob/master/release-notes.markdown>
26+ .
2327 /Note/: if you use GHCi or Template Haskell, please see the
2428 @README@ file for important details about building this package,
2529 and other packages that depend on it:
@@ -80,6 +84,7 @@ description:
8084
8185extra-source-files:
8286 README.markdown
87+ release-notes.markdown
8388 benchmarks/AesonEncode.hs
8489 benchmarks/AesonParse.hs
8590 benchmarks/JsonParse.hs
@@ -98,7 +103,7 @@ extra-source-files:
98103 benchmarks/json-data/twitter50.json
99104 benchmarks/json-data/twitter100.json
100105 tests/Properties.hs
101− examples/Demo.hs
106+ examples/*.hs
102107
103108flag developer
104109 description: operate in developer mode
@@ -170,8 +175,8 @@ test-suite tests
170175
171176source-repository head
172177 type: git
173− location: http://github.com/bos/aeson
178+ location: git://github.com/bos/aeson.git
174179
175180source-repository head
176181 type: mercurial
177− location: http://bitbucket.org/bos/aeson
182+ location: https://bitbucket.org/bos/aeson
examples/Generic.hsnew file+38
@@ -0,0 +1,38 @@
1+-- This example is basically the same as in Simplest.hs, only it uses
2+-- GHC's builtin generics instead of explicit instances of ToJSON and
3+-- FromJSON.
4+
5+-- This example only works with GHC 7.2 or newer, as it uses the
6+-- datatype-generic programming machinery introduced in 7.2.
7+
8+-- We enable the DeriveGeneric language extension so that GHC can
9+-- automatically derive the Generic class for us.
10+
11+{-# LANGUAGE DeriveGeneric #-}
12+
13+{-# LANGUAGE OverloadedStrings #-}
14+
15+import Data.Aeson (FromJSON, ToJSON, decode, encode)
16+import qualified Data.ByteString.Lazy.Char8 as BL
17+
18+-- To decode or encode a value using the generic machinery, we must
19+-- make the type an instance of the Generic class.
20+
21+import GHC.Generics (Generic)
22+
23+data Coord = Coord { x :: Double, y :: Double }
24+ deriving (Show, Generic)
25+
26+-- While we still have to declare our type as instances of FromJSON
27+-- and ToJSON, we do *not* need to provide bodies for the instances.
28+-- Default versions will be supplied for us.
29+
30+instance FromJSON Coord
31+instance ToJSON Coord
32+
33+main ::IO ()
34+main = do
35+ let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
36+ print req
37+ let reply = Coord 123.4 20
38+ BL.putStrLn (encode reply)
examples/GenericSYB.hsnew file+30
@@ -0,0 +1,30 @@
1+-- This example is basically the same as in Simplest.hs, only it uses
2+-- SYB generics instead of explicit instances of ToJSON and FromJSON.
3+
4+-- This mechanism is much slower than the newer generics mechanism
5+-- demonstrated in Generic.hs, but it works on versions of GHC older
6+-- than 7.2.
7+
8+-- We enable the DeriveDataTypeable language extension so that GHC can
9+-- automatically derive the Typeable and Data classes for us.
10+
11+{-# LANGUAGE DeriveDataTypeable #-}
12+
13+{-# LANGUAGE OverloadedStrings #-}
14+
15+import Data.Data (Typeable, Data)
16+import Data.Aeson.Generic (decode, encode)
17+import qualified Data.ByteString.Lazy.Char8 as BL
18+
19+-- To decode or encode a value using the generic machinery, we must
20+-- make the type an instance of the Typeable and Data classes.
21+
22+data Coord = Coord { x :: Double, y :: Double }
23+ deriving (Show, Typeable, Data)
24+
25+main ::IO ()
26+main = do
27+ let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
28+ print req
29+ let reply = Coord 123.4 20
30+ BL.putStrLn (encode reply)
examples/Simplest.hs+19−22
@@ -1,33 +1,30 @@
11{-# LANGUAGE OverloadedStrings #-}
22
3−import Control.Applicative ((<$>), (<*>))
4−import Control.Monad (mzero)
3+import Control.Applicative ((<$>), (<*>), empty)
54import Data.Aeson
6−import qualified Data.Aeson.Types as T
7−import Data.Attoparsec (parse, Result(..))
8−import qualified Data.ByteString.Char8 as BS
9−import qualified Data.ByteString.Lazy.Char8 as BSL
5+import qualified Data.ByteString.Lazy.Char8 as BL
106
11−main ::IO ()
12−main = do
13− print $ parseFromString "{\"x\":3.0,\"y\":-1.0}"
14− let reply = Coord 123.4 20
15− putStrLn $ BSL.unpack (encode reply)
7+data Coord = Coord { x :: Double, y :: Double }
8+ deriving (Show)
169
17−data Coord = Coord { x :: Double, y :: Double } deriving (Show)
10+-- A ToJSON instance allows us to encode a value as JSON.
1811
1912instance ToJSON Coord where
20− toJSON (Coord xV yV) = object ["x" .= xV, "y" .= yV]
13+ toJSON (Coord xV yV) = object [ "x" .= xV,
14+ "y" .= yV ]
15+
16+-- A FromJSON instance allows us to decode a value from JSON. This
17+-- should match the format used by the ToJSON instance.
2118
2219instance FromJSON Coord where
2320 parseJSON (Object v) = Coord <$>
24− v .: "x" <*>
25− v .: "y"
26− parseJSON _ = mzero
21+ v .: "x" <*>
22+ v .: "y"
23+ parseJSON _ = empty
2724
28−parseFromString :: String -> Maybe Coord
29−parseFromString s =
30− let bs = BS.pack s
31− in case parse json bs of
32− Done _rest res -> T.parseMaybe parseJSON res
33− _ -> Nothing
25+main ::IO ()
26+main = do
27+ let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
28+ print req
29+ let reply = Coord 123.4 20
30+ BL.putStrLn (encode reply)
release-notes.markdownnew file+27
@@ -0,0 +1,27 @@
1+# 0.3 to 0.4
2+
3+## Generics support
4+
5+Aeson's support for data-type generic programming makes it possible to
6+use JSON encodings of most data types without writing any boilerplate
7+instances.
8+
9+Thanks to Bas Van Dijk, aeson now supports the two major schemes for
10+doing datatype-generic programming:
11+
12+* the newer mechanism, [built into GHC
13+ itself](http://www.haskell.org/ghc/docs/latest/html/users_guide/generic-programming.html)
14+
15+* the older mechanism, based on SYB (for "scrap your boilerplate")
16+
17+The GHC-based generics are fast and terse: in fact, they're generally
18+comparable in performance to hand-written `ToJSON` and `FromJSON`
19+instances. To see how to use GHC generics, see
20+[`examples/Generic.hs`](https://github.com/bos/aeson/blob/master/examples/Generic.hs).
21+
22+The SYB-based generics support lives in
23+[Data.Aeson.Generic](http://hackage.haskell.org/packages/archive/aeson/0.4.0.0/doc/html/Data-Aeson-Generic.html),
24+and is provided mainly for users of GHC older than 7.2. It's far
25+slower (by about 10x) than the more modern generic mechanism. To see
26+how to use SYB generics, see
27+[`examples/GenericSYB.hs`](https://github.com/bos/aeson/blob/master/examples/GenericSYB.hs).