aeson 0.4.0.1 → 0.5.0.0
raw patch · 4 files changed
+61/−47 lines, 4 filesdep −blaze-textualPVP ok
version bump matches the API change (PVP)
Dependencies removed: blaze-textual
API changes (from Hackage documentation)
Files
- Data/Aeson/Encode.hs +46/−42
- aeson.cabal +1/−2
- benchmarks/aeson-benchmarks.cabal +3/−3
- release-notes.markdown +11/−0
Data/Aeson/Encode.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns, OverloadedStrings #-} -- | -- Module: Data.Aeson.Encode@@ -8,8 +8,13 @@ -- Stability: experimental -- Portability: portable ----- Efficiently serialize a JSON value as a lazy 'L.ByteString',--- encoded as UTF-8.+-- Efficiently serialize a JSON value.+--+-- Most frequently, you'll probably want to encode straight to UTF-8+-- (the standard JSON encoding) using 'encode'.+--+-- You can convert a 'Builder' (as returned by 'fromValue') to a+-- string using e.g. 'toLazyText'. module Data.Aeson.Encode (@@ -17,74 +22,73 @@ , encode ) where -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 Data.Text.Lazy.Builder+import Data.Text.Lazy.Builder.Int (decimal)+import Data.Text.Lazy.Builder.RealFloat (realFloat)+import Data.Text.Lazy.Encoding (encodeUtf8) import Numeric (showHex)-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.ByteString.Lazy as L import qualified Data.HashMap.Strict as H import qualified Data.Text as T import qualified Data.Vector as V --- | Encode a JSON value to a 'Builder'.+-- | Encode a JSON value to a 'Builder'. You can convert this to a+-- string using e.g. 'toLazyText', or encode straight to UTF-8 (the+-- standard JSON encoding) using 'encode'. fromValue :: Value -> Builder-fromValue Null = {-# SCC "fromValue/Null" #-} fromByteString "null"+fromValue Null = {-# SCC "fromValue/Null" #-} "null" fromValue (Bool b) = {-# SCC "fromValue/Bool" #-}- if b then fromByteString "true"- else fromByteString "false"+ if b then "true" else "false" fromValue (Number n) = {-# SCC "fromValue/Number" #-} fromNumber n fromValue (String s) = {-# SCC "fromValue/String" #-} string s fromValue (Array v)- | V.null v = {-# SCC "fromValue/Array" #-} fromByteString "[]"+ | V.null v = {-# SCC "fromValue/Array" #-} "[]" | otherwise = {-# SCC "fromValue/Array" #-}- Char8.fromChar '[' `mappend`- fromValue (V.unsafeHead v) `mappend`- V.foldr f (Char8.fromChar ']') (V.unsafeTail v)- where f a z = Char8.fromChar ',' `mappend` fromValue a `mappend` z+ singleton '[' <>+ fromValue (V.unsafeHead v) <>+ V.foldr f (singleton ']') (V.unsafeTail v)+ where f a z = singleton ',' <> fromValue a <> z fromValue (Object m) = {-# SCC "fromValue/Object" #-} case H.toList m of- (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+ (x:xs) -> singleton '{' <> one x <> foldr f (singleton '}') xs+ _ -> "{}"+ where f a z = singleton ',' <> one a <> z+ one (k,v) = string k <> singleton ':' <> fromValue v string :: T.Text -> Builder-string s = Char8.fromChar '"' `mappend` (quote s) `mappend` Char8.fromChar '"'+string s = {-# SCC "string" #-} singleton '"' <> quote s <> singleton '"' where quote q = case T.uncons t of- Just (c,t') -> fromText h `mappend` escape c `mappend` quote t' Nothing -> fromText h- where (h,t) = T.break isEscape q+ Just (!c,t') -> fromText h <> escape c <> quote t'+ where (h,t) = {-# SCC "break" #-} T.break isEscape q isEscape c = c == '\"' || c == '\\' || c < '\x20'- escape '\"' = fromByteString "\\\""- escape '\\' = fromByteString "\\\\"- escape '\n' = fromByteString "\\n"- escape '\r' = fromByteString "\\r"- escape '\t' = fromByteString "\\t"+ escape '\"' = "\\\""+ escape '\\' = "\\\\"+ escape '\n' = "\\n"+ escape '\r' = "\\r"+ escape '\t' = "\\t" escape c- | c < '\x20' = Char8.fromString $- "\\u" ++ replicate (4 - length h) '0' ++ h- | otherwise = Utf8.fromChar c+ | c < '\x20' = fromString $ "\\u" ++ replicate (4 - length h) '0' ++ h+ | otherwise = singleton 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 (I i) = decimal i fromNumber (D d)- | isNaN d || isInfinite d = fromByteString "null"- | otherwise = double d+ | isNaN d || isInfinite d = "null"+ | otherwise = realFloat d -- | Efficiently serialize a JSON value as a lazy 'L.ByteString'. encode :: ToJSON a => a -> L.ByteString-encode = {-# SCC "encode" #-} toLazyByteString . fromValue .+encode = {-# SCC "encode" #-} encodeUtf8 . toLazyText . fromValue . {-# SCC "toJSON" #-} toJSON {-# INLINE encode #-}++(<>) :: Builder -> Builder -> Builder+(<>) = mappend+{-# INLINE (<>) #-}+infixr 6 <>
aeson.cabal view
@@ -1,5 +1,5 @@ name: aeson-version: 0.4.0.1+version: 0.5.0.0 license: BSD3 license-file: LICENSE category: Text, Web, JSON@@ -122,7 +122,6 @@ attoparsec >= 0.8.6.1, base == 4.*, blaze-builder >= 0.2.1.4,- blaze-textual >= 0.2.0.2, bytestring, containers, deepseq,
benchmarks/aeson-benchmarks.cabal view
@@ -8,7 +8,7 @@ main-is: CompareWithJSON.hs ghc-options: -Wall -O2 build-depends:- aeson == 0.4.0.0,+ aeson, base, blaze-builder, bytestring,@@ -19,14 +19,14 @@ main-is: AesonEncode.hs ghc-options: -Wall -O2 build-depends:- aeson == 0.4.0.0,+ aeson, base executable aeson-benchmark-aeson-parse main-is: AesonParse.hs ghc-options: -Wall -O2 build-depends:- aeson == 0.4.0.0,+ aeson, attoparsec, base
release-notes.markdown view
@@ -1,3 +1,14 @@+# 0.4 to 0.5++When used with the UTF-8 encoding performance improvements introduced+in version 0.11.1.12 of the text package, this release improves+aeson's JSON encoding performance by 33% relative to aeson 0.4.++As part of achieving this improvement, an API change was necessary.+The `fromValue` function in the `Data.Aeson.Encode` module now uses+the text package's `Builder` type instead of the blaze-builder+package's `Builder` type.+ # 0.3 to 0.4 ## Ease of use