{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
import Control.DeepSeq (NFData)
import Criterion (Benchmark, nf)
import Data.Aeson.Combinators.Decode (Decoder)
import Data.Aeson.Types (FromJSON, ToJSON, withObject,
(.:))
import Data.ByteString.Lazy (ByteString)
import GHC.Generics (Generic)
import qualified Criterion.Main as Criterion
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Combinators.Decode as Decode
bench :: NFData b => String -> (a -> b) -> (Int -> a) -> [Benchmark]
bench name f gen = fmap (\i -> let !n = 10 ^ i
!generated = gen n
in Criterion.bench (name <> " " <> show n) $ (nf f) generated
) ([1..4] :: [Int])
{-# INLINE bench #-}
main :: IO ()
main =
Criterion.defaultMain
[ Criterion.bgroup "Combinators decoder nested" $
bench "nested" (Decode.decode deeplyNestedDecoder) deeplyNestedValue
, Criterion.bgroup "Derived (generic) decoder nested" $
bench "nested" (Aeson.decode @DeeplyNested) deeplyNestedValue
, Criterion.bgroup "Implemented instance decoder nested" $
bench "nested" (Aeson.decode @DeeplyNested') deeplyNestedValue
, Criterion.bgroup "Combinators decoder narrow" $
bench "narrow" (Decode.decode narrowDecoder) narrowValue
, Criterion.bgroup "Derived (generic) decoder narrow" $
bench "narrow" (Aeson.decode @Narrow) narrowValue
, Criterion.bgroup "Implemented instance decoder narrow" $
bench "narrow" (Aeson.decode @Narrow') narrowValue
]
data DeeplyNested = DeeplyNested
{ nested :: ![DeeplyNested]
} deriving stock (Show, Generic)
deriving anyclass (FromJSON, NFData, ToJSON)
deeplyNestedDecoder :: Decoder DeeplyNested
deeplyNestedDecoder = DeeplyNested
<$> Decode.key "nested" (Decode.list deeplyNestedDecoder)
deeplyNestedValue :: Int -> ByteString
deeplyNestedValue depth = Aeson.encode $ go depth (DeeplyNested [])
where
go :: Int -> DeeplyNested -> DeeplyNested
go n dn
| n <= 0 = dn
| otherwise = go (n - 1) $ DeeplyNested [dn]
data DeeplyNested' = DeeplyNested'
{ nested' :: ![DeeplyNested']
} deriving stock (Show, Generic)
deriving anyclass (NFData)
instance FromJSON DeeplyNested' where
parseJSON = withObject "DeeplyNested'" $ \v ->
DeeplyNested' <$> v .: "nested"
data Narrow = Narrow
{ narrow :: ![Int]
} deriving stock (Show, Generic)
deriving anyclass (FromJSON, NFData, ToJSON)
narrowDecoder :: Decoder Narrow
narrowDecoder = Narrow
<$> Decode.key "narrow" (Decode.list Decode.int)
narrowValue :: Int -> ByteString
narrowValue width = Aeson.encode $ Narrow [1..width]
data Narrow' = Narrow'
{ narrow' :: ![Int]
} deriving stock (Show, Generic)
deriving anyclass (NFData)
instance FromJSON Narrow' where
parseJSON = withObject "narrow'" $ \v ->
Narrow' <$> v .: "narrow"