packages feed

json-stream 0.4.2.4 → 0.4.3.0

raw patch · 6 files changed

+89/−24 lines, 6 filesdep ~aesonPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: aeson

API changes (from Hackage documentation)

+ Data.JsonStream.Parser: byteString :: Parser ByteString
+ Data.JsonStream.Parser: safeByteString :: Int -> Parser ByteString
- Data.JsonStream.Parser: ParseYield :: a -> (ParseOutput a) -> ParseOutput a
+ Data.JsonStream.Parser: ParseYield :: a -> ParseOutput a -> ParseOutput a

Files

Data/JsonStream/CLexer.hs view
@@ -20,7 +20,6 @@ import qualified Data.ByteString.Char8       as BS import           Data.ByteString.Unsafe      (unsafeUseAsCString) import           Data.Scientific             (Scientific, scientific)-import           Data.Text.Encoding          (decodeUtf8') import           Data.Text.Internal.Unsafe   (inlinePerformIO) import           Foreign import           Foreign.C.Types@@ -28,7 +27,7 @@  import           Data.JsonStream.CLexType import           Data.JsonStream.TokenParser (Element (..), TokenResult (..))-import           Data.JsonStream.Unescape+import           Data.JsonStream.Unescape (unescapeText)  -- | Limit for maximum size of a number; fail if larger number is found -- this is needed to make this constant-space, otherwise we would eat@@ -174,7 +173,7 @@  -- | Parse particular result parseResults :: TempData -> (CInt, Header, Int, ResultPtr) -> TokenResult-parseResults (TempData {tmpNumbers=tmpNumbers, tmpBuffer=bs}) (err, hdr, rescount, resptr) = parse 0+parseResults TempData{tmpNumbers=tmpNumbers, tmpBuffer=bs} (err, hdr, rescount, resptr) = parse 0   where     newtemp = TempData bs hdr (err /= 0)     -- We iterate the items from CNT to 1, 1 is the last element, CNT is the first@@ -218,14 +217,8 @@                        Just num -> PartialResult (JValue (AE.Number num)) next                        Nothing -> TokFailed         | resType == resString ->-          if | resAddData == -1 -> -- One-part string without escaped characters-                case decodeUtf8' textSection  of-                  Right ctext -> PartialResult (JValue (AE.String ctext)) next-                  Left _ -> TokFailed-             | resAddData == 0 -> -- One-part string with escaped characters-                case unescapeText textSection of-                  Right ctext -> PartialResult (JValue (AE.String ctext)) next-                  _ -> TokFailed+          if | resAddData == -1 || resAddData == 0 -> -- One-part string without escaped characters; with escaped+                PartialResult (StringRaw textSection) next              | otherwise -> PartialResult (StringContent textSection) -- Final part of partial strings                             (PartialResult StringEnd next)         | resType == resStringPartial ->@@ -237,7 +230,7 @@ estResultLimit dta = fromIntegral $ 20 + BS.length dta `quot` 5  getNextResult :: TempData -> TokenResult-getNextResult tmp@(TempData {..})+getNextResult tmp@TempData{..}   | tmpError = TokFailed   | hdrPosition tmpHeader < hdrLength tmpHeader = parseResults tmp (callLex tmpBuffer tmpHeader)   | otherwise = TokMoreData newdata
Data/JsonStream/Parser.hs view
@@ -48,6 +48,7 @@     -- * FromJSON parser   , value   , string+  , byteString     -- * Constant space parsers   , safeString   , number@@ -55,6 +56,7 @@   , real   , bool   , jNull+  , safeByteString     -- * Structure operators   , (.:)   , (.:?)@@ -91,7 +93,13 @@ import qualified Data.ByteString.Lazy.Char8  as BL import qualified Data.ByteString.Lazy.Internal as BL import           Data.Char                   (isSpace)+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.KeyMap           as AEK+import qualified Data.Aeson.Key              as AEK+import           Data.Bifunctor              (first)+#else import qualified Data.HashMap.Strict         as HMap+#endif import           Data.Scientific             (Scientific, isInteger,                                               toBoundedInteger, toRealFloat) import qualified Data.Text                   as T@@ -307,12 +315,17 @@     (PartialResult ObjectBegin ntp) -> moreData (nextitem False) ntp     (PartialResult _ _) -> callParse ignoreVal tp -- Run ignoreval parser on the same output we got     (TokMoreData ntok) -> MoreData (object' once valparse, ntok)-    (TokFailed) -> Failed "Array - token failed"+    TokFailed -> Failed "Array - token failed"   where     nextitem _ _ (ObjectEnd ctx) ntok = Done ctx ntok-    nextitem yielded _ (JValue (AE.String key)) ntok = objcontent yielded (callParse (valparse key) ntok)+    nextitem yielded _ (JValue (AE.String key)) ntok =+      objcontent yielded (callParse (valparse key) ntok)+    nextitem yielded _ (StringRaw bs) ntok = +      case unescapeText bs of+        Right t -> objcontent yielded (callParse (valparse t) ntok)+        Left e -> Failed (show e)     nextitem yielded _ (StringContent str) ntok =-          objcontent yielded $ moreData (getLongKey [str] (BS.length str)) ntok+      objcontent yielded $ moreData (getLongKey [str] (BS.length str)) ntok     nextitem _ _ el _ = Failed $ "Object - unexpected item: " ++ show el      -- If we already yielded and should yield once, ignore the rest of the object@@ -368,13 +381,21 @@ aeValue :: Parser AE.Value aeValue = Parser $ moreData value'   where+#if MIN_VERSION_aeson(2,0,0)+    tomap = AEK.fromList . map (first AEK.fromText)+#else+    tomap = HMap.fromList+#endif     value' tok el ntok =       case el of         JValue val -> Yield val (Done "" ntok)         JInteger val -> Yield (AE.Number $ fromIntegral val) (Done "" ntok)         StringContent _ -> callParse (AE.String <$> longString Nothing) tok+        StringRaw bs -> case unescapeText bs of+              Right t -> Yield (AE.String t) (Done "" ntok)+              Left e -> Failed (show e)         ArrayBegin -> AE.Array . Vec.fromList <$> callParse (many (arrayOf aeValue)) tok-        ObjectBegin -> AE.Object . HMap.fromList <$> callParse (manyReverse (objectItems aeValue)) tok+        ObjectBegin -> AE.Object . tomap <$> callParse (manyReverse (objectItems aeValue)) tok         _ -> Failed ("aeValue - unexpected token: " ++ show el)  -- | Optimized function for aeson objects - evades reversing the objects@@ -402,13 +423,44 @@         _ -> callParse ignoreVal tok  +longByteString :: Maybe Int -> Parser BS.ByteString+longByteString mbounds = Parser $ moreData (handle id 0)+  where+    handle acc !len tok el ntok =+      case el of+        JValue (AE.String _) -> Failed "INTERNAL ERROR! - got decoded JValue instead of string"+        StringRaw bs -> Yield bs (Done "" ntok)+        StringContent str+          | (Just bounds) <- mbounds, len > bounds -- If the string exceeds bounds, discard it+                          -> callParse (ignoreStrRestThen (Parser $ Done "")) ntok+          | otherwise     -> moreData (handle (acc . (str:)) (len + BS.length str)) ntok+        StringEnd -> Yield (BS.concat (acc [])) (Done "" ntok)+        _ ->  callParse ignoreVal tok+++-- | Parse raw bytestring value (json string expected), skip parsing otherwise.+-- The returned value is not unescaped.+byteString :: Parser BS.ByteString+byteString = longByteString Nothing++-- | Stops parsing string after the limit is reached. The string will not be matched+-- if it exceeds the size. The size is the size of escaped string including escape+-- characters. +-- The return value is not unescaped.+safeByteString :: Int -> Parser BS.ByteString+safeByteString limit = longByteString (Just limit)+ -- | Match a possibly bounded string roughly limited by a limit longString :: Maybe Int -> Parser T.Text-longString mbounds = Parser $ moreData (handle (BS.empty :) 0)+longString mbounds = Parser $ moreData (handle id 0)   where     handle acc !len tok el ntok =       case el of         JValue (AE.String str) -> Yield str (Done "" ntok)+        StringRaw bs -> +          case unescapeText bs of+            Right t -> Yield t (Done "" ntok)+            Left e -> Failed (show e)         StringContent str           | (Just bounds) <- mbounds, len > bounds -- If the string exceeds bounds, discard it                           -> callParse (ignoreStrRestThen (Parser $ Done "")) ntok@@ -546,6 +598,7 @@      handleTok :: Int -> TokenResult -> Element -> TokenResult -> ParseResult a     handleTok 0 _ (JValue _) ntok = Done "" ntok+    handleTok 0 _ (StringRaw _) ntok = Done "" ntok     handleTok 0 _ (JInteger _) ntok = Done "" ntok     handleTok 0 _ (ArrayEnd _) _ = Failed "ArrayEnd in ignoreval on 0 level"     handleTok 0 _ (ObjectEnd _) _ = Failed "ObjectEnd in ignoreval on 0 level"@@ -556,6 +609,7 @@         JValue _ -> moreData (handleTok level) ntok         JInteger _ -> moreData (handleTok level) ntok         StringContent _ -> moreData (handleLongString level) ntok+        StringRaw _ -> moreData (handleTok level) ntok         ArrayEnd _ -> moreData (handleTok (level - 1)) ntok         ObjectEnd _ -> moreData (handleTok (level - 1)) ntok         ArrayBegin -> moreData (handleTok (level + 1)) ntok
Data/JsonStream/TokenParser.hs view
@@ -9,14 +9,21 @@ import qualified Data.ByteString.Char8 as BS import           Foreign.C.Types -data Element = ArrayBegin | ArrayEnd BS.ByteString | ObjectBegin | ObjectEnd BS.ByteString-               | StringContent BS.ByteString | StringEnd-               | JValue AE.Value | JInteger CLong-               deriving (Show, Eq)+data Element = +    ArrayBegin+  | ArrayEnd !BS.ByteString+  | ObjectBegin+  | ObjectEnd !BS.ByteString+  | StringContent !BS.ByteString+  | StringRaw !BS.ByteString -- Allow raw strings to go into parser as bytestring+  | StringEnd+  | JValue !AE.Value+  | JInteger !CLong+  deriving (Show, Eq)  -- | Public interface for parsing JSON tokens. data TokenResult =  TokMoreData (BS.ByteString -> TokenResult)-                  | PartialResult Element (TokenResult)+                  | PartialResult Element TokenResult                   -- ^ found element, continuation, actual parsing view - so that we can report the unparsed                   -- data when the parsing finishes.                   | TokFailed
changelog.md view
@@ -1,3 +1,8 @@+# 0.4.3.0++- Aeson 2.0 compatibility+- Added support for raw bytestring+ # 0.4.2.4  Fix compiling with new ghc.
json-stream.cabal view
@@ -1,5 +1,5 @@ name:                json-stream-version:             0.4.2.4+version:             0.4.3.0 synopsis:            Incremental applicative JSON parser description:         Easy to use JSON parser fully supporting incremental parsing.                      Parsing grammar in applicative form.@@ -41,7 +41,7 @@   build-depends:         base >=4.7 && <5                        , bytestring                        , text-                       , aeson >= 0.7+                       , aeson >= 0.7 && < 2.1                        , vector                        , unordered-containers                        , scientific
test/ParserSpec.hs view
@@ -118,6 +118,12 @@         msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]     msg `shouldBe` [10,1,20] +  it "Has working byteString parser" $ do+    let test = ["[\"abcd\\n\\rxyz\"]"]+        parser = arrayOf byteString :: Parser BS.ByteString+        msg = parseLazyByteString parser (BL.fromChunks test) :: [BS.ByteString]+    msg `shouldBe` ["abcd\\n\\rxyz"]+ specEdge :: Spec specEdge = describe "Edge cases" $ do   it "Correct incremental parsing 1" $ do