hermes-json 0.4.0.0 → 0.5.0.0
raw patch · 7 files changed
+114/−92 lines, 7 filesdep ~vectorPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: vector
API changes (from Hackage documentation)
- Data.Hermes: withNull :: (Bool -> DecoderM a) -> Decoder a
- Data.Hermes: withTypeM :: (ValueType -> DecoderM a) -> Decoder a
- Data.Hermes.Decoder.Value: withNull :: (Bool -> DecoderM a) -> Decoder a
- Data.Hermes.Decoder.Value: withTypeM :: (ValueType -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: parseScientific :: ByteString -> Decoder Scientific
- Data.Hermes: atKey :: Text -> Decoder a -> Object -> DecoderM a
+ Data.Hermes: atKey :: Text -> Decoder a -> Object -> Decoder a
- Data.Hermes: atKeyOptional :: Text -> Decoder a -> Object -> DecoderM (Maybe a)
+ Data.Hermes: atKeyOptional :: Text -> Decoder a -> Object -> Decoder (Maybe a)
- Data.Hermes: atKeyStrict :: Text -> Decoder a -> Object -> DecoderM a
+ Data.Hermes: atKeyStrict :: Text -> Decoder a -> Object -> Decoder a
- Data.Hermes: objectAsKeyValues :: (Text -> DecoderM k) -> Decoder v -> Decoder [(k, v)]
+ Data.Hermes: objectAsKeyValues :: (Text -> Decoder k) -> Decoder v -> Decoder [(k, v)]
- Data.Hermes: objectAsMap :: Ord k => (Text -> DecoderM k) -> Decoder v -> Decoder (Map k v)
+ Data.Hermes: objectAsMap :: Ord k => (Text -> Decoder k) -> Decoder v -> Decoder (Map k v)
- Data.Hermes: withArray :: (Array -> DecoderM a) -> Decoder a
+ Data.Hermes: withArray :: (Array -> Decoder a) -> Decoder a
- Data.Hermes: withBool :: (Bool -> DecoderM a) -> Decoder a
+ Data.Hermes: withBool :: (Bool -> Decoder a) -> Decoder a
- Data.Hermes: withDouble :: (Double -> DecoderM a) -> Decoder a
+ Data.Hermes: withDouble :: (Double -> Decoder a) -> Decoder a
- Data.Hermes: withInt :: (Int -> DecoderM a) -> Decoder a
+ Data.Hermes: withInt :: (Int -> Decoder a) -> Decoder a
- Data.Hermes: withObject :: (Object -> DecoderM a) -> Decoder a
+ Data.Hermes: withObject :: (Object -> Decoder a) -> Decoder a
- Data.Hermes: withObjectAsMap :: Ord k => (Text -> DecoderM k) -> Decoder v -> (Map k v -> DecoderM a) -> Decoder a
+ Data.Hermes: withObjectAsMap :: Ord k => (Text -> Decoder k) -> Decoder v -> (Map k v -> Decoder a) -> Decoder a
- Data.Hermes: withRawByteString :: (ByteString -> DecoderM a) -> Decoder a
+ Data.Hermes: withRawByteString :: (ByteString -> Decoder a) -> Decoder a
- Data.Hermes: withScientific :: (Scientific -> DecoderM a) -> Decoder a
+ Data.Hermes: withScientific :: (Scientific -> Decoder a) -> Decoder a
- Data.Hermes: withString :: (String -> DecoderM a) -> Decoder a
+ Data.Hermes: withString :: (String -> Decoder a) -> Decoder a
- Data.Hermes: withText :: (Text -> DecoderM a) -> Decoder a
+ Data.Hermes: withText :: (Text -> Decoder a) -> Decoder a
- Data.Hermes: withVector :: Vector v a => Decoder a -> (v a -> DecoderM a) -> Decoder a
+ Data.Hermes: withVector :: Vector v a => Decoder a -> (v a -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: atKey :: Text -> Decoder a -> Object -> DecoderM a
+ Data.Hermes.Decoder.Value: atKey :: Text -> Decoder a -> Object -> Decoder a
- Data.Hermes.Decoder.Value: atKeyOptional :: Text -> Decoder a -> Object -> DecoderM (Maybe a)
+ Data.Hermes.Decoder.Value: atKeyOptional :: Text -> Decoder a -> Object -> Decoder (Maybe a)
- Data.Hermes.Decoder.Value: atKeyStrict :: Text -> Decoder a -> Object -> DecoderM a
+ Data.Hermes.Decoder.Value: atKeyStrict :: Text -> Decoder a -> Object -> Decoder a
- Data.Hermes.Decoder.Value: objectAsKeyValues :: (Text -> DecoderM k) -> Decoder v -> Decoder [(k, v)]
+ Data.Hermes.Decoder.Value: objectAsKeyValues :: (Text -> Decoder k) -> Decoder v -> Decoder [(k, v)]
- Data.Hermes.Decoder.Value: objectAsMap :: Ord k => (Text -> DecoderM k) -> Decoder v -> Decoder (Map k v)
+ Data.Hermes.Decoder.Value: objectAsMap :: Ord k => (Text -> Decoder k) -> Decoder v -> Decoder (Map k v)
- Data.Hermes.Decoder.Value: withArray :: (Array -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withArray :: (Array -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withBool :: (Bool -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withBool :: (Bool -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withDouble :: (Double -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withDouble :: (Double -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withInt :: (Int -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withInt :: (Int -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withObject :: (Object -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withObject :: (Object -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withObjectAsMap :: Ord k => (Text -> DecoderM k) -> Decoder v -> (Map k v -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withObjectAsMap :: Ord k => (Text -> Decoder k) -> Decoder v -> (Map k v -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withRawByteString :: (ByteString -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withRawByteString :: (ByteString -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withScientific :: (Scientific -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withScientific :: (Scientific -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withString :: (String -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withString :: (String -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withText :: (Text -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withText :: (Text -> Decoder a) -> Decoder a
- Data.Hermes.Decoder.Value: withVector :: Vector v a => Decoder a -> (v a -> DecoderM a) -> Decoder a
+ Data.Hermes.Decoder.Value: withVector :: Vector v a => Decoder a -> (v a -> Decoder a) -> Decoder a
Files
- CHANGELOG.md +7/−0
- README.md +12/−12
- hermes-json.cabal +2/−2
- src/Data/Hermes.hs +0/−2
- src/Data/Hermes/Decoder/Internal.hs +30/−0
- src/Data/Hermes/Decoder/Time.hs +2/−2
- src/Data/Hermes/Decoder/Value.hs +61/−74
CHANGELOG.md view
@@ -1,5 +1,12 @@ # Revision history for hermes-json +## 0.5.0.0 -- 2023-03-08++* Convert `DecoderM` callbacks to `Decoder`. This is a breaking change.+* Add useful instances for the `Decoder` monad+* Remove some redundant functions+* Adjust `vector` bounds+ ## 0.4.0.0 -- 2023-03-07 * Update simdjson to 3.1.3
README.md view
@@ -90,17 +90,17 @@ <!-- AUTO-GENERATED-CONTENT:START (BENCHES) --> | Name | Mean (ps) | 2*Stdev (ps) | Allocated | Copied | Peak Memory | | --------------------------------------- | ------------- | ------------ | ---------- | ---------- | ----------- |-| All.Decode.Arrays.Hermes | 267104550000 | 18274712758 | 503599934 | 439150544 | 541065216 |-| All.Decode.Arrays.Aeson | 2205838200000 | 108871466542 | 7094759154 | 2392723275 | 1166016512 |-| All.Decode.Persons.Hermes | 47153700000 | 3880584170 | 144901928 | 57032737 | 1166016512 |-| All.Decode.Persons.Aeson | 134265700000 | 7195219536 | 357269946 | 188529734 | 1166016512 |-| All.Decode.Partial Twitter.Hermes | 246448046 | 20934312 | 348540 | 3088 | 1166016512 |-| All.Decode.Partial Twitter.JsonStream | 2105484765 | 73210262 | 15261108 | 273820 | 1166016512 |-| All.Decode.Partial Twitter.Aeson | 4297434375 | 139205712 | 12547656 | 4625157 | 1166016512 |-| All.Decode.Persons (Aeson Value).Hermes | 108099550000 | 9966602188 | 303649194 | 138051155 | 1166016512 |-| All.Decode.Persons (Aeson Value).Aeson | 119240200000 | 9148201308 | 286148916 | 177027844 | 1166016512 |-| All.Decode.Twitter (Aeson Value).Hermes | 4261312500 | 149205128 | 12555922 | 4151184 | 1166016512 |-| All.Decode.Twitter (Aeson Value).Aeson | 4832229687 | 242990712 | 12539421 | 5527422 | 1166016512 |+| All.Decode.Arrays.Hermes | 267914650000 | 10610366160 | 503599934 | 439150544 | 541065216 |+| All.Decode.Arrays.Aeson | 2214928800000 | 160279563772 | 7094759111 | 2392723388 | 1166016512 |+| All.Decode.Persons.Hermes | 47338175000 | 4290343628 | 144901928 | 57032737 | 1166016512 |+| All.Decode.Persons.Aeson | 132864400000 | 9509102680 | 357269946 | 188529742 | 1166016512 |+| All.Decode.Partial Twitter.Hermes | 241083593 | 13856196 | 348540 | 3088 | 1166016512 |+| All.Decode.Partial Twitter.JsonStream | 2116192187 | 158907568 | 15259526 | 273821 | 1166016512 |+| All.Decode.Partial Twitter.Aeson | 4254060937 | 262619196 | 12538003 | 4634594 | 1166016512 |+| All.Decode.Persons (Aeson Value).Hermes | 106420425000 | 3747538126 | 303886293 | 135388183 | 1166016512 |+| All.Decode.Persons (Aeson Value).Aeson | 119489550000 | 9713032080 | 286148916 | 177027852 | 1166016512 |+| All.Decode.Twitter (Aeson Value).Hermes | 4164246875 | 240020934 | 12368752 | 4149211 | 1166016512 |+| All.Decode.Twitter (Aeson Value).Aeson | 4810817187 | 345165042 | 12539421 | 5527424 | 1166016512 | | | <!-- AUTO-GENERATED-CONTENT:END (BENCHES) --> @@ -111,7 +111,7 @@ * Decode to `Int` or `Double` instead of `Scientific` if you can. * Decode your object fields in order. If encoding with `aeson`, you can leverage `toEncoding` to enforce ordering. -If you need to decode in tight loops or long-running processes (like a server), consider using the `withHermesEnv/mkHermesEnv` and `parseByteString` functions instead of `decodeEither`. This ensures the simdjson instances are not re-created on each decode. Please see the [simdjson performance docs](https://github.com/simdjson/simdjson/blob/master/doc/performance.md#performance-notes) for more info.+If you need to decode in tight loops or long-running processes (like a server), consider using the `withHermesEnv/mkHermesEnv` and `parseByteString` functions instead of `decodeEither`. This ensures the simdjson instances are not re-created on each decode. Please see the [simdjson performance docs](https://github.com/simdjson/simdjson/blob/master/doc/performance.md#performance-notes) for more info. But please ensure that you use one `HermesEnv` per thread, as simdjson is [single-threaded by default](https://github.com/simdjson/simdjson/blob/master/doc/basics.md#thread-safety). ## Limitations
hermes-json.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: hermes-json-version: 0.4.0.0+version: 0.5.0.0 category: Text, Web, JSON, FFI synopsis: Fast JSON decoding via simdjson C++ bindings description:@@ -72,7 +72,7 @@ transformers >= 0.5.6 && < 0.6, time >= 1.9.3 && < 1.13, time-compat >= 1.9.5 && < 1.10,- vector >= 0.13.0 && < 0.14+ vector >= 0.12.3.1 && < 0.14 hs-source-dirs: src default-language: Haskell2010
src/Data/Hermes.hs view
@@ -69,14 +69,12 @@ , withBool , withDouble , withInt- , withNull , withObject , withObjectAsMap , withScientific , withString , withText , withType- , withTypeM , withVector -- * Raw ByteString access , withRawByteString
src/Data/Hermes/Decoder/Internal.hs view
@@ -105,6 +105,34 @@ newtype Decoder a = Decoder { runDecoder :: Value -> DecoderM a } +instance Functor Decoder where+ {-# INLINE fmap #-}+ fmap f d = Decoder $ \val -> f <$> runDecoder d val++instance Applicative Decoder where+ {-# INLINE pure #-}+ pure a = Decoder $ \_ -> pure a+ {-# INLINE (<*>) #-}+ (Decoder f) <*> (Decoder e) = Decoder $ \val -> f val <*> e val++instance Monad Decoder where+ {-# INLINE return #-}+ return = pure+ {-# INLINE (>>=) #-}+ (Decoder d) >>= f = Decoder $ \val -> do+ x <- d val+ runDecoder (f x) val++instance Alternative Decoder where+ {-# INLINE (<|>) #-}+ (Decoder a) <|> (Decoder b) = Decoder $ \val -> a val <|> b val+ {-# INLINE empty #-}+ empty = Decoder $ const empty++instance MonadFail Decoder where+ {-# INLINE fail #-}+ fail e = Decoder $ \_ -> fail e+ -- | Decode a strict `ByteString` using the simdjson::ondemand bindings. -- Creates simdjson instances on each decode. decodeEither :: Decoder a -> BS.ByteString -> Either HermesException a@@ -139,6 +167,8 @@ -- It is preferable to use `withHermesEnv` to keep foreign references in scope. -- Be careful using this, the foreign references can be finalized if the -- `HermesEnv` goes out of scope.+--+-- Do _not_ share a `HermesEnv` across multiple threads. Each thread should get its own. mkHermesEnv :: Maybe Int -> IO HermesEnv mkHermesEnv mCapacity = do parser <- mkSIMDParser mCapacity
src/Data/Hermes/Decoder/Time.hs view
@@ -19,11 +19,11 @@ import qualified Data.Time.Calendar.Quarter.Compat as Time import qualified Data.Time.LocalTime as Local -import Data.Hermes.Decoder.Internal (DecoderM, Decoder(..))+import Data.Hermes.Decoder.Internal (Decoder(..)) import Data.Hermes.Decoder.Value (withText) -- | Run an attoparsec text parser as a hermes decoder.-runAttoDate :: AT.Parser a -> Text -> DecoderM a+runAttoDate :: AT.Parser a -> Text -> Decoder a runAttoDate p t = case AT.parseOnly (p <* AT.endOfInput) t of Left err -> fail $ "Could not parse date: " <> err
src/Data/Hermes/Decoder/Value.hs view
@@ -18,6 +18,7 @@ , nullable , objectAsKeyValues , objectAsMap+ , parseScientific , scientific , string , text@@ -29,7 +30,6 @@ , withBool , withDouble , withInt- , withNull , withObject , withObjectAsMap , withRawByteString@@ -37,7 +37,6 @@ , withString , withText , withType- , withTypeM , withVector ) where @@ -89,44 +88,44 @@ {-# INLINE atPointer #-} -- | Helper to work with an Object parsed from a Value.-withObject :: (Object -> DecoderM a) -> Decoder a+withObject :: (Object -> Decoder a) -> Decoder a withObject f = Decoder $ \valPtr -> withRunInIO $ \ run -> allocaObject $ \oPtr -> do err <- getObjectFromValueImpl valPtr oPtr run $ do handleErrorCode (typePrefix "object") err- f oPtr+ runDecoder (f oPtr) valPtr {-# INLINE withObject #-} -- | Helper to work with an Int parsed from a Value.-withInt :: (Int -> DecoderM a) -> Decoder a-withInt f = Decoder $ getInt >=> f+withInt :: (Int -> Decoder a) -> Decoder a+withInt f = Decoder $ \val -> getInt val >>= \i -> runDecoder (f i) val {-# INLINE withInt #-} -- | Helper to work with a Double parsed from a Value.-withDouble :: (Double -> DecoderM a) -> Decoder a-withDouble f = Decoder $ getDouble >=> f+withDouble :: (Double -> Decoder a) -> Decoder a+withDouble f = Decoder $ \val -> getDouble val >>= \d -> runDecoder (f d) val {-# INLINE withDouble #-} -- | Helper to work with a Bool parsed from a Value.-withBool :: (Bool -> DecoderM a) -> Decoder a-withBool f = Decoder $ getBool >=> f+withBool :: (Bool -> Decoder a) -> Decoder a+withBool f = Decoder $ \val -> getBool val >>= \b -> runDecoder (f b) val {-# INLINE withBool #-} -- | Helper to work with the raw ByteString of the JSON token parsed from the given Value.-withRawByteString :: (BS.ByteString -> DecoderM a) -> Decoder a-withRawByteString f = Decoder $ getRawByteString >=> f+withRawByteString :: (BS.ByteString -> Decoder a) -> Decoder a+withRawByteString f = Decoder $ \val -> getRawByteString val >>= \b -> runDecoder (f b) val {-# INLINE withRawByteString #-} -- | Helper to work with a String parsed from a Value.-withString :: (String -> DecoderM a) -> Decoder a-withString f = Decoder $ getString >=> f+withString :: (String -> Decoder a) -> Decoder a+withString f = Decoder $ \val -> getString val >>= \s -> runDecoder (f s) val {-# INLINE withString #-} -- | Helper to work with a Text parsed from a Value.-withText :: (Text -> DecoderM a) -> Decoder a-withText f = Decoder $ getText >=> f+withText :: (Text -> Decoder a) -> Decoder a+withText f = Decoder $ \val -> getText val >>= \t -> runDecoder (f t) val {-# INLINE withText #-} -- | Returns True if the Value is null.@@ -163,32 +162,32 @@ {-# RULES "list double/listOfDouble" list double = listOfDouble #-} -- | Helper to work with an Array parsed from a Value.-withArray :: (Array -> DecoderM a) -> Decoder a+withArray :: (Array -> Decoder a) -> Decoder a withArray f = Decoder $ \val -> withRunInIO $ \run -> allocaArray $ \arrPtr -> do err <- getArrayFromValueImpl val arrPtr run $ do handleErrorCode (typePrefix "array") err- f arrPtr+ runDecoder (f arrPtr) val {-# INLINE withArray #-} -- | Find an object field by key, where an exception is thrown -- if the key is missing.-atKey :: Text -> Decoder a -> Object -> DecoderM a-atKey key parser obj = withUnorderedField parser obj key+atKey :: Text -> Decoder a -> Object -> Decoder a+atKey key parser obj = Decoder . const $ withUnorderedField parser obj key {-# INLINE atKey #-} -- | Find an object field by key, where Nothing is returned -- if the key is missing.-atKeyOptional :: Text -> Decoder a -> Object -> DecoderM (Maybe a)-atKeyOptional key parser obj = withUnorderedOptionalField parser obj key+atKeyOptional :: Text -> Decoder a -> Object -> Decoder (Maybe a)+atKeyOptional key parser obj = Decoder . const $ withUnorderedOptionalField parser obj key {-# INLINE atKeyOptional #-} -- | Uses find_field, which means if you access a field out-of-order -- this will throw an exception. It also cannot support optional fields.-atKeyStrict :: Text -> Decoder a -> Object -> DecoderM a-atKeyStrict key parser obj = withField parser obj key+atKeyStrict :: Text -> Decoder a -> Object -> Decoder a+atKeyStrict key parser obj = Decoder . const $ withField parser obj key {-# INLINE atKeyStrict #-} -- | Parse a homogenous JSON array into a Haskell list.@@ -201,14 +200,14 @@ vector f = withArrayLenIter $ iterateOverArrayLen f {-# INLINE vector #-} -withVector :: G.Vector v a => Decoder a -> (v a -> DecoderM a) -> Decoder a-withVector inner f = Decoder $ runDecoder (vector inner) >=> f+withVector :: G.Vector v a => Decoder a -> (v a -> Decoder a) -> Decoder a+withVector inner f = Decoder $ \val -> runDecoder (vector inner) val >>= \v -> runDecoder (f v) val {-# INLINE withVector #-} -- | Parse an object into a homogenous list of key-value tuples. objectAsKeyValues- :: (Text -> DecoderM k)- -- ^ Parses a Text key in the DecoderM monad. JSON keys are always text.+ :: (Text -> Decoder k)+ -- ^ Parses a Text key in the Decoder monad. JSON keys are always text. -> Decoder v -- ^ Decoder for the field value. -> Decoder [(k, v)]@@ -218,8 +217,8 @@ -- | Parse an object into a strict `Map`. objectAsMap :: Ord k- => (Text -> DecoderM k)- -- ^ Parses a Text key in the DecoderM monad. JSON keys are always text.+ => (Text -> Decoder k)+ -- ^ Parses a Text key in the Decoder monad. JSON keys are always text. -> Decoder v -- ^ Decoder for the field value. -> Decoder (Map k v)@@ -228,13 +227,13 @@ withObjectAsMap :: Ord k- => (Text -> DecoderM k)- -- ^ Parses a Text key in the DecoderM monad. JSON keys are always text.+ => (Text -> Decoder k)+ -- ^ Parses a Text key in the Decoder monad. JSON keys are always text. -> Decoder v -- ^ Decoder for the field value.- -> (Map k v -> DecoderM a)+ -> (Map k v -> Decoder a) -> Decoder a-withObjectAsMap kf vf f = Decoder $ runDecoder (objectAsMap kf vf) >=> f+withObjectAsMap kf vf f = Decoder $ \val -> runDecoder (objectAsMap kf vf) val >>= \m -> runDecoder (f m) val {-# INLINE withObjectAsMap #-} -- | Transforms a parser to return Nothing when the value is null.@@ -246,14 +245,6 @@ else Just <$> runDecoder parser val {-# INLINE nullable #-} -withNull :: (Bool -> DecoderM a) -> Decoder a-withNull f = Decoder $ \val -> do- nil <- runDecoder isNull val- if nil- then f True- else f False-{-# INLINE withNull #-}- -- | Parse only a single character. char :: Decoder Char char = Decoder $ getText >=> justOne@@ -297,8 +288,8 @@ scientific = withRawByteString parseScientific {-# INLINE scientific #-} -withScientific :: (Sci.Scientific -> DecoderM a) -> Decoder a-withScientific f = Decoder $ runDecoder scientific >=> f+withScientific :: (Sci.Scientific -> Decoder a) -> Decoder a+withScientific f = Decoder $ \val -> runDecoder scientific val >>= \sci -> runDecoder (f sci) val {-# INLINE withScientific #-} -- | Get the simdjson type of the Value.@@ -317,9 +308,13 @@ withType f = Decoder $ \val -> runDecoder getType val >>= \ty -> runDecoder (f ty) val {-# INLINE withType #-} -withTypeM :: (ValueType -> DecoderM a) -> Decoder a-withTypeM f = Decoder $ runDecoder getType >=> f-{-# INLINE withTypeM #-}+-- | Parse a Scientific using attoparsec's ByteString.Char8 parser.+parseScientific :: BS.ByteString -> Decoder Sci.Scientific+parseScientific+ = either (\err -> fail $ "Failed to parse Scientific: " <> err) pure+ . A.parseOnly (AC.scientific <* A.endOfInput)+ . BSC.strip+{-# INLINE parseScientific #-} -- Internal Functions @@ -398,17 +393,17 @@ withObjectIter :: (ObjectIter -> DecoderM a) -> Decoder a withObjectIter f = Decoder $ \valPtr -> withRunInIO $ \run ->- allocaObjectIter $ \iterPtr -> do- err <- getObjectIterFromValueImpl valPtr iterPtr- run $ do- handleErrorCode (typePrefix "object") err- f iterPtr+ allocaObjectIter $ \iterPtr -> do+ err <- getObjectIterFromValueImpl valPtr iterPtr+ run $ do+ handleErrorCode (typePrefix "object") err+ f iterPtr {-# INLINE withObjectIter #-} -- | Execute a function on each Field in an ObjectIter and accumulate into a `Map`. iterateOverFieldsMap :: Ord a- => (Text -> DecoderM a)+ => (Text -> Decoder a) -> Decoder b -> ObjectIter -> DecoderM (Map a b)@@ -430,7 +425,7 @@ (k, v) <- withKey keyTxt $ do- k <- fk keyTxt+ k <- runDecoder (fk keyTxt) valPtr v <- runDecoder fv valPtr pure (k, v) liftIO $ objectIterMoveNextImpl iterPtr@@ -442,7 +437,7 @@ -- | Execute a function on each Field in an ObjectIter and -- accumulate key-value tuples into a list. iterateOverFields- :: (Text -> DecoderM a)+ :: (Text -> Decoder a) -> Decoder b -> ObjectIter -> DecoderM [(a, b)]@@ -464,7 +459,7 @@ kv <- withKey keyTxt $ do- k <- fk keyTxt+ k <- runDecoder (fk keyTxt) valPtr v <- runDecoder fv valPtr pure (k, v) liftIO $ objectIterMoveNextImpl iterPtr@@ -486,23 +481,23 @@ withUnorderedOptionalField :: Decoder a -> Object -> Text -> DecoderM (Maybe a) withUnorderedOptionalField f objPtr key = withRunInIO $ \run ->- Unsafe.unsafeUseAsCStringLen (T.encodeUtf8 key) $ \(cstr, len) ->- allocaValue $ \vPtr -> run $ withKey key $ do- err <- liftIO $ findFieldUnorderedImpl objPtr cstr len vPtr- let errCode = toEnum $ fromIntegral err- if | errCode == SUCCESS -> Just <$> runDecoder f vPtr- | errCode == NO_SUCH_FIELD -> pure Nothing- | otherwise -> Nothing <$ handleErrorCode "" err+ Unsafe.unsafeUseAsCStringLen (T.encodeUtf8 key) $ \(cstr, len) ->+ allocaValue $ \vPtr -> run $ withKey key $ do+ err <- liftIO $ findFieldUnorderedImpl objPtr cstr len vPtr+ let errCode = toEnum $ fromIntegral err+ if | errCode == SUCCESS -> Just <$> runDecoder f vPtr+ | errCode == NO_SUCH_FIELD -> pure Nothing+ | otherwise -> Nothing <$ handleErrorCode "" err {-# INLINE withUnorderedOptionalField #-} withField :: Decoder a -> Object -> Text -> DecoderM a withField f objPtr key = withRunInIO $ \run -> Unsafe.unsafeUseAsCStringLen (T.encodeUtf8 key) $ \(cstr, len) ->- allocaValue $ \vPtr -> run $ withKey key $ do- err <- liftIO $ findFieldImpl objPtr cstr len vPtr+ allocaValue $ \val -> run $ withKey key $ do+ err <- liftIO $ findFieldImpl objPtr cstr len val handleErrorCode "" err- runDecoder f vPtr+ runDecoder f val {-# INLINE withField #-} getInt :: Value -> DecoderM Int@@ -522,14 +517,6 @@ handleErrorCode (typePrefix "double") err liftIO $ F.peek ptr {-# INLINE getDouble #-}---- | Parse a Scientific using attoparsec's ByteString.Char8 parser.-parseScientific :: BS.ByteString -> DecoderM Sci.Scientific-parseScientific- = either (\err -> fail $ "Failed to parse Scientific: " <> err) pure- . A.parseOnly (AC.scientific <* A.endOfInput)- . BSC.strip-{-# INLINE parseScientific #-} getBool :: Value -> DecoderM Bool getBool valPtr =