packages feed

aeson-quick-0.2.0: bench/Benchmark.hs

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Applicative
import Control.Monad

import Criterion.Main

import Data.Aeson.Quick
import Data.Aeson.Types (parseMaybe)
import qualified Data.ByteString.Lazy as BL
import Data.Text (Text)

import System.IO.Unsafe

main :: IO ()
main = defaultMain
  -- TODO: Refactor such that "bench" also tests
  [ bench "quickGetSimple"     $ nf quickGetSimple jsonSimple
  , bench "aesonGetSimple"     $ nf aesonGetSimple jsonSimple
  , bench "quickGetComplex"    $ nf quickGetComplex jsonComplex
  , bench "aesonGetComplex"    $ nf aesonGetComplex jsonComplex
  , bench "quickSetSimple"     $ nf quickSetSimple simple
  , bench "aesonSetSimple"     $ nf aesonSetSimple simple
  , bench "quickSetComplex"    $ nf quickSetComplex complex
  , bench "aesonSetComplex"    $ nf aesonSetComplex complex
  , bench "parseSimple"        $ nf parseQuick "{a}"
  , bench "parseComplex"       $ nf parseQuick "{a,b:[{c,d:[{e,f}]}]}"
 ]
  where
    jsonSimple = d "{\"a\":2,\"b\":[1,1]}" :: Value
    jsonComplex = d $ unsafePerformIO $ BL.readFile "bench/complex.json"

    check :: (Value -> Maybe a) -> Value -> a
    check f = maybe (error "Nothing") id . f

    quickGetSimple, aesonGetSimple :: Value -> Integer
    quickGetSimple = check (.? "{a}")
    aesonGetSimple = check $ parseMaybe $ withObject "" (.: "a")
    
    quickGetComplex, aesonGetComplex :: Value -> [(Text,Float,[Text],[Text])]
    quickGetComplex = check (.! "[{id,ppu,batters:{batter:[{id}]},topping:[{id}]}]")
    aesonGetComplex = check $ parseMaybe $ parseJSON >=> mapM (\o ->
      (,,,) <$> o .: "id" <*> o .: "ppu" <*> batters o <*> toppings o)
      where
        batters = (.:"batters") >=> withObject "" (.:"batter")
                                >=> mapM (withObject "" (.:"id"))
        toppings = (.:"topping") >=> mapM (withObject "" (.:"id"))
    
    simple = object ["a" .= Number 1]
    quickSetSimple, aesonSetSimple :: Value -> Bool
    quickSetSimple r = r `must` ("{a}" .% (1::Int))
    aesonSetSimple r = r `must` object ["a" .= (1::Int)]

    Just complex = decode "{\"a\":1,\"b\":[{\"a\":1},{\"a\":2},{\"a\":3}]}"
    quickSetComplex, aesonSetComplex :: Value -> Bool
    quickSetComplex r =
      let vals = ((1,[1,2,3])::(Int,[Int]))
       in r `must` ("{a,b:[{a}]}" .% vals)
    aesonSetComplex r =
      let inner = [object ["a" .= n] | n <- [1,2,3::Int]]
       in r `must` object ["a" .= (1::Int), "b" .= inner]


must :: Eq a => a -> a -> Bool
must a b = if a == b then True else error "False"

d :: BL.ByteString -> Value
d s = case decode s of
           Just v -> v
           Nothing -> error $ "Coult not decode JSON: " ++ show s