{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Aeson.Extra.Stream
-- Copyright   :  (C) 2015-2016 Oleg Grenrus
-- License     :  BSD3
-- Maintainer  :  Oleg Grenrus <oleg.grenrus@iki.fi>
--
module Data.Aeson.Extra.Stream (
    streamDecode,
    ) where

import Prelude ()
import Prelude.Compat

import Control.Applicative (many, (<|>))
import Data.Aeson          (FromJSON, Result (..), Value, fromJSON)
import Data.Aeson.Parser   (value)

import qualified Data.Attoparsec.ByteString.Char8 as A8
import qualified Data.Attoparsec.ByteString.Lazy  as A
import qualified Data.ByteString.Lazy             as LBS

streamParse :: LBS.ByteString -> ([Value], Maybe String)
streamParse :: ByteString -> ([Value], Maybe String)
streamParse = ByteString -> ([Value], Maybe String)
start
  where
    start :: ByteString -> ([Value], Maybe String)
start ByteString
bs = case Parser Char -> ByteString -> Result Char
forall a. Parser a -> ByteString -> Result a
A.parse (Char -> Parser Char
lexemeChar Char
'[') ByteString
bs of
        A.Done ByteString
bs' Char
_    -> ByteString -> ([Value], Maybe String)
first ByteString
bs'
        A.Fail ByteString
_ [String]
_ String
err  -> ([], String -> Maybe String
forall a. a -> Maybe a
Just String
err)
    first :: ByteString -> ([Value], Maybe String)
first ByteString
bs = case Parser Char -> ByteString -> Result Char
forall a. Parser a -> ByteString -> Result a
A.parse (Char -> Parser Char
lexemeChar Char
']') 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 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 ByteString
_   (Value
r, Bool
False) -> ([Value
r], Maybe String
forall a. Maybe a
Nothing)
        A.Done ByteString
bs' (Value
r, Bool
True)  -> case ByteString -> ([Value], Maybe String)
go ByteString
bs' of
            ~([Value]
rs, Maybe String
end)  -> (Value
rValue -> [Value] -> [Value]
forall a. a -> [a] -> [a]
:[Value]
rs, Maybe String
end)
        A.Fail ByteString
_ [String]
_ 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 Char
',' 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 Char
']'
        (Value, Bool) -> Parser (Value, Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return (Value
v, Bool
c)
    lexemeChar :: Char -> Parser Char
lexemeChar 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

-- | Lazyly parse 'LBS.ByteString' with top-level JSON array.
--
-- /Note:/ inspecting result's second field will force the list!
--
-- @
-- let ~(values, err) = 'streamDecode' bs
-- traverse_ processValue values
-- maybe (pure ()) printError err
-- @
--
-- @since 0.3.2.0
streamDecode :: forall a. FromJSON a => LBS.ByteString -> ([a], Maybe String)
streamDecode :: ByteString -> ([a], Maybe String)
streamDecode ByteString
bs = [Value] -> ([a], Maybe String)
go [Value]
values
  where
    ([Value]
values, 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 (Value
v:[Value]
vs) = case Value -> Result a
forall a. FromJSON a => Value -> Result a
fromJSON Value
v of
        Error String
err'  -> ([], String -> Maybe String
forall a. a -> Maybe a
Just String
err')
        Success a
x  -> case [Value] -> ([a], Maybe String)
go [Value]
vs of
            ~([a]
xs, Maybe String
err') -> (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs, Maybe String
err')