aeson 0.4.0.0 → 0.4.0.1
raw patch · 7 files changed
+147/−31 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/Aeson/Encode.hs +33/−23
- aeson.cabal +3/−2
- benchmarks/AesonEncode.hs +0/−2
- benchmarks/AesonParse.hs +0/−2
- benchmarks/CompareWithJSON.hs +70/−0
- benchmarks/JsonParse.hs +1/−2
- benchmarks/aeson-benchmarks.cabal +40/−0
Data/Aeson/Encode.hs view
@@ -17,13 +17,15 @@ , encode ) where -import Blaze.ByteString.Builder-import Blaze.ByteString.Builder.Char.Utf8-import Data.Attoparsec.Number (Number(..))+import Blaze.ByteString.Builder (Builder, fromByteString, toLazyByteString)+import Blaze.Text (double, integral) import Data.Aeson.Types (ToJSON(..), Value(..))+import Data.Attoparsec.Number (Number(..)) import Data.Monoid (mappend)+import Data.Text.Encoding (encodeUtf8) import Numeric (showHex)-import Blaze.Text (double, integral)+import qualified Blaze.ByteString.Builder.Char.Utf8 as Utf8+import qualified Blaze.ByteString.Builder.Char8 as Char8 import qualified Data.ByteString.Lazy.Char8 as L import qualified Data.HashMap.Strict as H import qualified Data.Text as T@@ -31,27 +33,29 @@ -- | Encode a JSON value to a 'Builder'. fromValue :: Value -> Builder-fromValue Null = fromByteString "null"-fromValue (Bool b) = fromByteString $ if b then "true" else "false"-fromValue (Number n) = fromNumber n-fromValue (String s) = string s+fromValue Null = {-# SCC "fromValue/Null" #-} fromByteString "null"+fromValue (Bool b) = {-# SCC "fromValue/Bool" #-}+ if b then fromByteString "true"+ else fromByteString "false"+fromValue (Number n) = {-# SCC "fromValue/Number" #-} fromNumber n+fromValue (String s) = {-# SCC "fromValue/String" #-} string s fromValue (Array v)- | V.null v = fromByteString "[]"- | otherwise = fromChar '[' `mappend`+ | V.null v = {-# SCC "fromValue/Array" #-} fromByteString "[]"+ | otherwise = {-# SCC "fromValue/Array" #-}+ Char8.fromChar '[' `mappend` fromValue (V.unsafeHead v) `mappend`- V.foldr f (fromChar ']') (V.unsafeTail v)- where f a z = fromChar ',' `mappend` fromValue a `mappend` z-fromValue (Object m) =+ V.foldr f (Char8.fromChar ']') (V.unsafeTail v)+ where f a z = Char8.fromChar ',' `mappend` fromValue a `mappend` z+fromValue (Object m) = {-# SCC "fromValue/Object" #-} case H.toList m of- (x:xs) -> fromChar '{' `mappend`- one x `mappend`- foldr f (fromChar '}') xs- _ -> fromByteString "{}"- where f a z = fromChar ',' `mappend` one a `mappend` z- one (k,v) = string k `mappend` fromChar ':' `mappend` fromValue v+ (x:xs) -> Char8.fromChar '{' `mappend`+ one x `mappend` foldr f (Char8.fromChar '}') xs+ _ -> fromByteString "{}"+ where f a z = Char8.fromChar ',' `mappend` one a `mappend` z+ one (k,v) = string k `mappend` Char8.fromChar ':' `mappend` fromValue v string :: T.Text -> Builder-string s = fromChar '"' `mappend` quote s `mappend` fromChar '"'+string s = Char8.fromChar '"' `mappend` (quote s) `mappend` Char8.fromChar '"' where quote q = case T.uncons t of Just (c,t') -> fromText h `mappend` escape c `mappend` quote t'@@ -64,10 +68,15 @@ escape '\r' = fromByteString "\\r" escape '\t' = fromByteString "\\t" escape c- | c < '\x20' = fromString $ "\\u" ++ replicate (4 - length h) '0' ++ h- | otherwise = fromChar c+ | c < '\x20' = Char8.fromString $+ "\\u" ++ replicate (4 - length h) '0' ++ h+ | otherwise = Utf8.fromChar c where h = showHex (fromEnum c) "" +-- The version in blaze-builder is way slower.+fromText :: T.Text -> Builder+fromText t = fromByteString (encodeUtf8 t)+ fromNumber :: Number -> Builder fromNumber (I i) = integral i fromNumber (D d)@@ -76,5 +85,6 @@ -- | Efficiently serialize a JSON value as a lazy 'L.ByteString'. encode :: ToJSON a => a -> L.ByteString-encode = toLazyByteString . fromValue . toJSON+encode = {-# SCC "encode" #-} toLazyByteString . fromValue .+ {-# SCC "toJSON" #-} toJSON {-# INLINE encode #-}
aeson.cabal view
@@ -1,5 +1,5 @@ name: aeson-version: 0.4.0.0+version: 0.4.0.1 license: BSD3 license-file: LICENSE category: Text, Web, JSON@@ -84,6 +84,7 @@ extra-source-files: README.markdown+ benchmarks/*.cabal benchmarks/*.hs benchmarks/*.py benchmarks/Makefile@@ -139,7 +140,7 @@ ghc-options: -Werror ghc-prof-options: -auto-all - ghc-options: -Wall+ ghc-options: -O2 -Wall test-suite tests type: exitcode-stdio-1.0
benchmarks/AesonEncode.hs view
@@ -3,8 +3,6 @@ import Control.Exception import Control.Monad import Data.Aeson-import Data.Aeson.Encode-import Data.Aeson.Parser import Data.Attoparsec import Data.Time.Clock import System.Environment (getArgs)
benchmarks/AesonParse.hs view
@@ -1,10 +1,8 @@ {-# LANGUAGE BangPatterns, OverloadedStrings #-} -import Control.DeepSeq import Control.Exception import Control.Monad import Data.Aeson-import Data.Aeson.Parser import Data.Attoparsec import Data.Time.Clock import System.Environment (getArgs)
+ benchmarks/CompareWithJSON.hs view
@@ -0,0 +1,70 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++import Blaze.ByteString.Builder (toLazyByteString)+import Blaze.ByteString.Builder.Char.Utf8 (fromString)+import Control.DeepSeq (NFData(rnf))+import Criterion.Main+import qualified Data.Aeson as A+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString.Lazy.Internal as BL+import qualified Text.JSON as J++instance (NFData v) => NFData (J.JSObject v) where+ rnf o = rnf (J.fromJSObject o)++instance NFData J.JSValue where+ rnf J.JSNull = ()+ rnf (J.JSBool b) = rnf b+ rnf (J.JSRational a b) = rnf a `seq` rnf b `seq` ()+ rnf (J.JSString s) = rnf (J.fromJSString s)+ rnf (J.JSArray lst) = rnf lst+ rnf (J.JSObject o) = rnf o++instance NFData BL.ByteString where+ rnf (BL.Chunk _ bs) = rnf bs+ rnf BL.Empty = ()++decodeJ :: String -> J.JSValue+decodeJ s =+ case J.decodeStrict s of+ J.Ok v -> v+ J.Error _ -> error "fail to parse via JSON"++decodeA :: BL.ByteString -> A.Value+decodeA s = case A.decode s of+ Just v -> v+ Nothing -> error "fail to parse via Aeson"++encodeJ :: J.JSValue -> BL.ByteString+encodeJ = toLazyByteString . fromString . J.encode++main :: IO ()+main = do+ let enFile = "json-data/twitter100.json"+ jpFile = "json-data/jp100.json"+ enA <- BL.readFile enFile+ enJ <- readFile enFile+ jpA <- BL.readFile jpFile+ jpJ <- readFile jpFile+ defaultMain [+ bgroup "decode" [+ bgroup "en" [+ bench "aeson" $ nf decodeA enA+ , bench "json" $ nf decodeJ enJ+ ]+ , bgroup "jp" [+ bench "aeson" $ nf decodeA jpA+ , bench "json" $ nf decodeJ jpJ+ ]+ ]+ , bgroup "encode" [+ bgroup "en" [+ bench "aeson" $ nf A.encode (decodeA enA)+ , bench "json" $ nf encodeJ (decodeJ enJ)+ ]+ , bgroup "jp" [+ bench "aeson" $ nf A.encode (decodeA jpA)+ , bench "json" $ nf encodeJ (decodeJ jpJ)+ ]+ ]+ ]
benchmarks/JsonParse.hs view
@@ -1,13 +1,12 @@ {-# LANGUAGE BangPatterns, ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} import Control.DeepSeq-import Control.Exception import Control.Monad import Text.JSON import Data.Time.Clock import System.Environment (getArgs) import System.IO-import qualified Data.ByteString as B instance NFData JSValue where rnf JSNull = ()
+ benchmarks/aeson-benchmarks.cabal view
@@ -0,0 +1,40 @@+name: aeson-benchmarks+version: 0+build-type: Simple++cabal-version: >=1.2++executable aeson-benchmark-compare-with-json+ main-is: CompareWithJSON.hs+ ghc-options: -Wall -O2+ build-depends:+ aeson == 0.4.0.0,+ base,+ blaze-builder,+ bytestring,+ criterion,+ json++executable aeson-benchmark-aeson-encode+ main-is: AesonEncode.hs+ ghc-options: -Wall -O2+ build-depends:+ aeson == 0.4.0.0,+ base++executable aeson-benchmark-aeson-parse+ main-is: AesonParse.hs+ ghc-options: -Wall -O2+ build-depends:+ aeson == 0.4.0.0,+ attoparsec,+ base++executable aeson-benchmark-json-parse+ main-is: JsonParse.hs+ ghc-options: -Wall -O2+ build-depends:+ base,+ deepseq,+ json,+ time