packages feed

buffer-builder-aeson (empty) → 0.1.0.1

raw patch · 6 files changed

+250/−0 lines, 6 filesdep +HUnitdep +QuickCheckdep +aesonsetup-changed

Dependencies added: HUnit, QuickCheck, aeson, attoparsec, base, buffer-builder, buffer-builder-aeson, bytestring, criterion, deepseq, hashable, integer-gmp, scientific, tasty, tasty-hunit, tasty-quickcheck, tasty-th, text, unordered-containers, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, IMVU, Chad Austin, Andy Friesen++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Chad Austin nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bench/Bench.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE OverloadedStrings, RecordWildCards #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE BangPatterns #-}++module Main where++import           Control.DeepSeq (force)+import           Criterion+import           Criterion.Main+import qualified Data.Aeson as Aeson+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL+import qualified Data.BufferBuilder.Json as Json+import qualified Data.BufferBuilder.Aeson ()+import qualified Data.Text as Text+import qualified Data.Vector as Vector+import qualified Data.Vector.Unboxed as UnboxedVector++assumeSuccess :: Either a b -> b+assumeSuccess (Right r) = r+assumeSuccess _ = error "assumeSuccess"++main :: IO ()+main = do+    content <- BS.readFile "test.json"+    let lazyContent = force $ BSL.fromChunks [content]++    let parsedUserList :: [Aeson.Value]+        Just parsedUserList = Aeson.decode lazyContent++    let compareBench name !value =+            bgroup name+                [ bench "bufferbuilder" $ nf Json.encodeJson value+                , bench "aeson"         $ nf Aeson.encode value+                ]++    defaultMain+        [ compareBench "list bool" $ Aeson.Array $ Vector.fromList $ fmap Aeson.Bool $ replicate 65536 False+        , compareBench "list null" $ Aeson.Array $ Vector.replicate 65536 Aeson.Null+        , compareBench "list empty object" $ Aeson.Array $ Vector.replicate 65536 $ Aeson.object []+        , compareBench "list empty array" $ Aeson.Array $ Vector.replicate 65536 $ Aeson.Array Vector.empty+        , compareBench "list string" $ Aeson.Array $ Vector.fromList $ fmap (Aeson.String . Text.pack . show) ([0..65535] :: [Int])+        , compareBench "list int" $ Aeson.Array $ Vector.fromList $ fmap (Aeson.Number . fromIntegral) ([0..65535] :: [Int])+        , compareBench "hash string" $ Aeson.object $ fmap (\e -> (Text.pack $ show e, Aeson.Null)) ([0..65535] :: [Int])++        , compareBench "list record" parsedUserList+        , bench "intvector" $ nf Json.encodeJson (UnboxedVector.fromList $! [0..65535] :: UnboxedVector.Vector Int)+        ]
+ buffer-builder-aeson.cabal view
@@ -0,0 +1,78 @@+-- Initial buffer-builder-aeson.cabal generated by cabal init.  For further+--  documentation, see http://haskell.org/cabal/users-guide/++name:                buffer-builder-aeson+version:             0.1.0.1+synopsis:            Serialize Aeson values with Data.BufferBuilder+-- description:+license:             MIT+license-file:        LICENSE+author:              Andy Friesen+maintainer:          andy.friesen@gmail.com+-- copyright:+category:            Data+build-type:          Simple+-- extra-source-files:+cabal-version:       >=1.10++library+  exposed-modules:     Data.BufferBuilder.Aeson+  hs-source-dirs:      src+  ghc-options: -O2 -Wall+  -- ghc-options: -ddump-ds -ddump-simpl -ddump-stg -ddump-opt-cmm -ddump-asm -ddump-to-file++  -- other-modules:+  -- other-extensions:+  build-depends:       base == 4.*+                     , aeson+                     , integer-gmp+                     , buffer-builder >=0.2.0.0+                     , unordered-containers+                     , vector+                     , scientific+                     , bytestring+  hs-source-dirs:+  default-language:    Haskell2010++test-suite tests+  type: exitcode-stdio-1.0+  main-is: Main.hs+  hs-source-dirs: test+  default-language: Haskell2010+  ghc-options: -O2 -Wall++  build-depends: base ==4.*+               , buffer-builder-aeson+               , buffer-builder+               , text+               , tasty+               , tasty-hunit+               , tasty-quickcheck+               , tasty-th+               , QuickCheck+               , unordered-containers+               , vector+               , scientific+               , bytestring+               , HUnit+               , text+               , hashable+               , attoparsec+               , aeson++benchmark json-bench+  type: exitcode-stdio-1.0+  main-is: Bench.hs+  hs-source-dirs: bench+  default-language: Haskell2010+  ghc-options: -O2 -Wall+  -- ghc-options: -ddump-ds -ddump-simpl -ddump-stg -ddump-opt-cmm -ddump-asm -ddump-to-file+  build-depends: base+               , buffer-builder+               , buffer-builder-aeson+               , aeson+               , bytestring+               , text+               , deepseq+               , criterion+               , vector
+ src/Data/BufferBuilder/Aeson.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE MagicHash #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} ++module Data.BufferBuilder.Aeson () where++import GHC.Base+import GHC.Integer.GMP.Internals+import           Data.Aeson (Value (..))+import           Data.BufferBuilder.Json (ToJson (..), nullValue, unsafeAppendBS, unsafeAppendUtf8Builder)+import qualified Data.BufferBuilder.Json as Json+import qualified Data.BufferBuilder.Utf8 as Utf8Builder+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Lazy.Builder as BB+import qualified Data.ByteString.Builder.Scientific as BB+import qualified Data.Scientific as Scientific++-- TODO: this doesn't need to convert the bytestring to strict before appending it+-- there is an appendBSL+slowNumber :: Scientific.Scientific -> Json.Value+slowNumber n = unsafeAppendBS+                    $ BSL.toStrict+                    $ BB.toLazyByteString+                    $ BB.formatScientificBuilder BB.Fixed Nothing n++instance ToJson Value where+    {-# INLINE toJson #-}+    toJson (Object o) = toJson o+    toJson (Array a) = toJson a+    toJson (String s) = toJson s+    toJson (Number n) = case Scientific.coefficient n of+        (S# smallcoeff) -> case Scientific.base10Exponent n of+            0 -> toJson (I# smallcoeff)+            exp' -> unsafeAppendUtf8Builder $ do+                Utf8Builder.appendDecimalSignedInt (I# smallcoeff)+                Utf8Builder.appendChar7 'e'+                Utf8Builder.appendDecimalSignedInt exp'+        _ -> slowNumber n+    toJson (Bool b) = toJson b+    toJson Null = nullValue
+ test/Main.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE MagicHash, OverloadedStrings, TemplateHaskell #-}++module Main where++import           Test.Tasty+import           Test.Tasty.TH+import           Test.Tasty.HUnit+import           Test.Tasty.QuickCheck+import           Data.String (IsString (..))+import           Data.BufferBuilder.Json+import           Data.BufferBuilder.Aeson ()+import           Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.Attoparsec.ByteString as Atto+import qualified Data.Aeson.Parser as JsonParse+import qualified Data.Aeson as Aeson+import           AesonQuickCheck ()+import           Debug.Trace++ae :: String -> ByteString -> IO ()+ae expected actual = assertEqual expected (fromString expected) actual++decodeJsonFragment :: Aeson.FromJSON j => BS.ByteString -> Maybe j+decodeJsonFragment str = case parsed of+    Right r -> case Aeson.fromJSON r of+        Aeson.Success a -> Just a+        _              -> Nothing+    _ -> Nothing+  where+    parsed = Atto.parseOnly JsonParse.value' str++case_serialize_simple_things :: IO ()+case_serialize_simple_things = do+    ae "false" (encodeJson $ Aeson.Bool False)+    ae "true" (encodeJson $ Aeson.Bool True)+    ae "null" (encodeJson $ Aeson.Null)+    ae "9" (encodeJson $ Aeson.Number 9)+    ae "-9" (encodeJson $ Aeson.Number (-9))++prop_matches_aeson :: Aeson.Value -> Bool+prop_matches_aeson value =+    let encoded = encodeJson value+        decoded = decodeJsonFragment encoded+    in if decoded == Just value+        then True+        else trace (show (value, encoded, decoded)) False++tests :: TestTree+tests = $(testGroupGenerator)++main :: IO ()+main = defaultMain tests