Skip to content

Commit

Permalink
Slightly improved performance of generically parsing sums
Browse files Browse the repository at this point in the history
The BigSum/fromJSON/generic benchmarks goes from 13.6 us to 11.3 us.
Thanks to Twan van Laarhoven for the idea of using Maybe
for the parse result instead of using the parser directly
  • Loading branch information
basvandijk committed Nov 3, 2011
1 parent 155e809 commit 72814fa
Showing 1 changed file with 15 additions and 11 deletions.
26 changes: 15 additions & 11 deletions Data/Aeson/Types/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ object = Object . M.fromList
--
-- * 'Data.Aeson.Generic' provides a generic @toJSON@ function that accepts any
-- type which is an instance of 'Data'.
--
--
-- * If your compiler has support for the @DeriveGeneric@ and
-- @DefaultSignatures@ language extensions, @toJSON@ will have a default generic
-- implementation.
Expand Down Expand Up @@ -382,7 +382,7 @@ class ToJSON a where
-- @{-\# LANGUAGE OverloadedStrings #-}
--
-- data Coord { x :: Double, y :: Double }
--
--
-- instance FromJSON Coord where
-- parseJSON ('Object' v) = Coord '<$>'
-- v '.:' \"x\" '<*>'
Expand Down Expand Up @@ -1057,10 +1057,17 @@ instance ( GFromProduct a, GFromProduct b
{-# INLINE gParseJSON #-}

instance (GFromSum a, GFromSum b) => GFromJSON (a :+: b) where
gParseJSON (Object (M.toList -> [keyVal])) = gParseSum keyVal
gParseJSON (Object (M.toList -> [keyVal@(key, _)])) =
case gParseSum keyVal of
Nothing -> notFound $ unpack key
Just p -> p
gParseJSON v = typeMismatch "sum (:+:)" v
{-# INLINE gParseJSON #-}

notFound :: String -> Parser a
notFound key = fail $ "The key \"" ++ key ++ "\" was not found"
{-# INLINE notFound #-}

--------------------------------------------------------------------------------

class ConsFromJSON f where consParseJSON :: Value -> Parser (f a)
Expand Down Expand Up @@ -1131,22 +1138,19 @@ instance (GFromJSON a) => GFromProduct (S1 s a) where
--------------------------------------------------------------------------------

class GFromSum f where
gParseSum :: Pair -> Parser (f a)
gParseSum :: Pair -> Maybe (Parser (f a))

instance (GFromSum a, GFromSum b) => GFromSum (a :+: b) where
gParseSum keyVal = (L1 <$> gParseSum keyVal) <|> (R1 <$> gParseSum keyVal)
gParseSum keyVal = (fmap L1 <$> gParseSum keyVal) <|>
(fmap R1 <$> gParseSum keyVal)
{-# INLINE gParseSum #-}

instance (Constructor c, GFromJSON a, ConsFromJSON a) => GFromSum (C1 c a) where
gParseSum (key, value)
| key == pack (conName (undefined :: t c a p)) = gParseJSON value
| otherwise = notFound $ unpack key
| key == pack (conName (undefined :: t c a p)) = Just $ gParseJSON value
| otherwise = Nothing
{-# INLINE gParseSum #-}

notFound :: String -> Parser a
notFound key = fail $ "The key \"" ++ key ++ "\" was not found"
{-# INLINE notFound #-}

--------------------------------------------------------------------------------

class IsRecord (f :: * -> *) b | f -> b
Expand Down

0 comments on commit 72814fa

Please sign in to comment.