{-# LANGUAGE ScopedTypeVariables #-}
module Data.Aeson.Extra.Stream (
streamDecode,
) where
import Prelude ()
import Prelude.Compat
import Control.Applicative ((<|>), many)
import Data.Aeson.Compat (FromJSON, Result (..), Value, fromJSON)
import Data.Aeson.Parser (value)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Attoparsec.ByteString.Char8 as A8
import qualified Data.Attoparsec.ByteString.Lazy as A
streamParse :: LBS.ByteString -> ([Value], Maybe String)
streamParse :: ByteString -> ([Value], Maybe String)
streamParse = ByteString -> ([Value], Maybe String)
start
where
start :: ByteString -> ([Value], Maybe String)
start bs :: ByteString
bs = case Parser Char -> ByteString -> Result Char
forall a. Parser a -> ByteString -> Result a
A.parse (Char -> Parser Char
lexemeChar '[') ByteString
bs of
A.Done bs' :: ByteString
bs' _ -> ByteString -> ([Value], Maybe String)
first ByteString
bs'
A.Fail _ _ err :: String
err -> ([], String -> Maybe String
forall a. a -> Maybe a
Just String
err)
first :: ByteString -> ([Value], Maybe String)
first bs :: ByteString
bs = case Parser Char -> ByteString -> Result Char
forall a. Parser a -> ByteString -> Result a
A.parse (Char -> Parser Char
lexemeChar ']') ByteString
bs of
A.Done {} -> ([], Maybe String
forall a. Maybe a
Nothing)
A.Fail {} -> ByteString -> ([Value], Maybe String)
go ByteString
bs
go :: ByteString -> ([Value], Maybe String)
go bs :: ByteString
bs = case Parser (Value, Bool) -> ByteString -> Result (Value, Bool)
forall a. Parser a -> ByteString -> Result a
A.parse Parser (Value, Bool)
valueEnd ByteString
bs of
A.Done _ (r :: Value
r, False) -> ([Value
r], Maybe String
forall a. Maybe a
Nothing)
A.Done bs' :: ByteString
bs' (r :: Value
r, True) -> case ByteString -> ([Value], Maybe String)
go ByteString
bs' of
~(rs :: [Value]
rs, end :: Maybe String
end) -> (Value
rValue -> [Value] -> [Value]
forall a. a -> [a] -> [a]
:[Value]
rs, Maybe String
end)
A.Fail _ _ err :: String
err -> ([], String -> Maybe String
forall a. a -> Maybe a
Just String
err)
valueEnd :: Parser (Value, Bool)
valueEnd = do
Value
v <- Parser Value
value
Bool
c <- Bool
True Bool -> Parser Char -> Parser ByteString Bool
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
lexemeChar ',' Parser ByteString Bool
-> Parser ByteString Bool -> Parser ByteString Bool
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Bool
False Bool -> Parser Char -> Parser ByteString Bool
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
lexemeChar ']'
(Value, Bool) -> Parser (Value, Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return (Value
v, Bool
c)
lexemeChar :: Char -> Parser Char
lexemeChar c :: Char
c = Parser Char -> Parser ByteString String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Char
A8.space Parser ByteString String -> Parser Char -> Parser Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Char -> Parser Char
A8.char Char
c Parser Char -> Parser ByteString String -> Parser Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Char -> Parser ByteString String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Char
A8.space
streamDecode :: forall a. FromJSON a => LBS.ByteString -> ([a], Maybe String)
streamDecode :: ByteString -> ([a], Maybe String)
streamDecode bs :: ByteString
bs = [Value] -> ([a], Maybe String)
go [Value]
values
where
(values :: [Value]
values, err :: Maybe String
err) = ByteString -> ([Value], Maybe String)
streamParse ByteString
bs
go :: [Value] -> ([a], Maybe String)
go :: [Value] -> ([a], Maybe String)
go [] = ([], Maybe String
err)
go (v :: Value
v:vs :: [Value]
vs) = case Value -> Result a
forall a. FromJSON a => Value -> Result a
fromJSON Value
v of
Error err' :: String
err' -> ([], String -> Maybe String
forall a. a -> Maybe a
Just String
err')
Success x :: a
x -> case [Value] -> ([a], Maybe String)
go [Value]
vs of
~(xs :: [a]
xs, err' :: Maybe String
err') -> (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs, Maybe String
err')