Commits

Bryan O'Sullivan committed e765efd

Allow decoding of strict bytestrings (gh-99)

Comments (0)

Files changed (2)

     , eitherDecode
     , eitherDecode'
     , encode
+    -- ** Variants for strict bytestrings
+    , decodeStrict
+    , decodeStrict'
+    , eitherDecodeStrict
+    , eitherDecodeStrict'
     -- * Core JSON types
     , Value(..)
     , Array
     ) where
 
 import Data.Aeson.Encode (encode)
-import Data.Aeson.Parser.Internal (decodeWith, eitherDecodeWith, jsonEOF, json,
-                                   jsonEOF', json')
+import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith,
+                                   eitherDecodeWith, eitherDecodeStrictWith,
+                                   jsonEOF, json, jsonEOF', json')
 import Data.Aeson.Types
+import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 
 -- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
 decode = decodeWith jsonEOF fromJSON
 {-# INLINE decode #-}
 
+-- | Efficiently deserialize a JSON value from a strict 'B.ByteString'.
+-- If this fails due to incomplete or invalid input, 'Nothing' is
+-- returned.
+--
+-- The input must consist solely of a JSON document, with no trailing
+-- data except for whitespace.
+--
+-- This function parses immediately, but defers conversion.  See
+-- 'json' for details.
+decodeStrict :: (FromJSON a) => B.ByteString -> Maybe a
+decodeStrict = decodeStrictWith jsonEOF fromJSON
+{-# INLINE decodeStrict #-}
+
 -- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
 -- If this fails due to incomplete or invalid input, 'Nothing' is
 -- returned.
 decode' = decodeWith jsonEOF' fromJSON
 {-# INLINE decode' #-}
 
+-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
+-- If this fails due to incomplete or invalid input, 'Nothing' is
+-- returned.
+--
+-- The input must consist solely of a JSON document, with no trailing
+-- data except for whitespace.
+--
+-- This function parses and performs conversion immediately.  See
+-- 'json'' for details.
+decodeStrict' :: (FromJSON a) => B.ByteString -> Maybe a
+decodeStrict' = decodeStrictWith jsonEOF' fromJSON
+{-# INLINE decodeStrict' #-}
+
 -- | Like 'decode' but returns an error message when decoding fails.
 eitherDecode :: (FromJSON a) => L.ByteString -> Either String a
 eitherDecode = eitherDecodeWith jsonEOF fromJSON
 {-# INLINE eitherDecode #-}
 
+-- | Like 'decodeStrict' but returns an error message when decoding fails.
+eitherDecodeStrict :: (FromJSON a) => B.ByteString -> Either String a
+eitherDecodeStrict = eitherDecodeStrictWith jsonEOF fromJSON
+{-# INLINE eitherDecodeStrict #-}
+
 -- | Like 'decode'' but returns an error message when decoding fails.
 eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
 eitherDecode' = eitherDecodeWith jsonEOF' fromJSON
 {-# INLINE eitherDecode' #-}
 
+-- | Like 'decodeStrict'' but returns an error message when decoding fails.
+eitherDecodeStrict' :: (FromJSON a) => B.ByteString -> Either String a
+eitherDecodeStrict' = eitherDecodeStrictWith jsonEOF' fromJSON
+{-# INLINE eitherDecodeStrict' #-}
+
 -- $use
 --
 -- This section contains basic information on the different ways to

Data/Aeson/Parser/Internal.hs

     , value'
     -- * Helpers
     , decodeWith
+    , decodeStrictWith
     , eitherDecodeWith
+    , eitherDecodeStrictWith
     ) where
 
 import Blaze.ByteString.Builder (fromByteString, toByteString)
       _          -> Nothing
 {-# INLINE decodeWith #-}
 
-eitherDecodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Either String a
+decodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString
+                 -> Maybe a
+decodeStrictWith p to s =
+    case A.parse p s of
+      A.Done _ v -> case to v of
+                      Success a -> Just a
+                      _         -> Nothing
+      _          -> Nothing
+{-# INLINE decodeStrictWith #-}
+
+eitherDecodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString
+                 -> Either String a
 eitherDecodeWith p to s =
     case L.parse p s of
       L.Done _ v -> case to v of
       L.Fail _ _ msg -> Left msg
 {-# INLINE eitherDecodeWith #-}
 
+eitherDecodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString
+                       -> Either String a
+eitherDecodeStrictWith p to s =
+    case A.parse p s of
+      A.Done _ v -> case to v of
+                      Success a -> Right a
+                      Error msg -> Left msg
+      A.Fail _ _ msg -> Left msg
+      A.Partial _    -> Left "incomplete input"
+{-# INLINE eitherDecodeStrictWith #-}
+
 -- $lazy
 --
 -- The 'json' and 'value' parsers decouple identification from