module Data.Streaming.Blaze
( BlazeRecv
, BlazePopper
, BlazeFinish
, newBlazeRecv
, Buffer
, freeSize
, sliceSize
, bufferSize
, allocBuffer
, reuseBuffer
, nextSlice
, unsafeFreezeBuffer
, unsafeFreezeNonEmptyBuffer
, BufferAllocStrategy
, allNewBuffersStrategy
, reuseBufferStrategy
, defaultStrategy
) where
import Blaze.ByteString.Builder
import qualified Data.ByteString as S
#if MIN_VERSION_blaze_builder(0,4,0)
import Data.Streaming.ByteString.Builder
newBlazeRecv :: BufferAllocStrategy -> IO (BlazeRecv, BlazeFinish)
newBlazeRecv = newByteStringBuilderRecv
#else /* !MIN_VERSION_blaze_builder(0,4,0) */
import Blaze.ByteString.Builder.Internal hiding (insertByteString)
import Blaze.ByteString.Builder.Internal.Types hiding (insertByteString)
import Blaze.ByteString.Builder.Internal.Buffer (execBuildStep)
import Data.IORef
import Data.Streaming.ByteString.Builder.Buffer
newBlazeRecv :: BufferAllocStrategy -> IO (BlazeRecv, BlazeFinish)
newBlazeRecv (ioBufInit, nextBuf) = do
refBuf <- newIORef ioBufInit
return (push refBuf, finish refBuf)
where
finish refBuf = do
ioBuf <- readIORef refBuf
buf <- ioBuf
return $ unsafeFreezeNonEmptyBuffer buf
push refBuf builder = do
refStep <- newIORef $ Left $ unBuilder builder (buildStep finalStep)
return $ popper refBuf refStep
where
finalStep !(BufRange pf _) = return $ Done pf ()
popper refBuf refStep = do
ioBuf <- readIORef refBuf
ebStep <- readIORef refStep
case ebStep of
Left bStep -> do
!buf <- ioBuf
signal <- execBuildStep bStep buf
case signal of
Done op' _ -> do
writeIORef refBuf $ return $ updateEndOfSlice buf op'
return S.empty
BufferFull minSize op' bStep' -> do
let buf' = updateEndOfSlice buf op'
cont mbs = do
ioBuf' <- nextBuf minSize buf'
writeIORef refBuf ioBuf'
writeIORef refStep $ Left bStep'
case mbs of
Just bs | not $ S.null bs -> return bs
_ -> popper refBuf refStep
cont $ unsafeFreezeNonEmptyBuffer buf'
InsertByteString op' bs bStep' -> do
let buf' = updateEndOfSlice buf op'
let yieldBS = do
nextBuf 1 buf' >>= writeIORef refBuf
writeIORef refStep $ Left bStep'
if S.null bs
then popper refBuf refStep
else return bs
case unsafeFreezeNonEmptyBuffer buf' of
Nothing -> yieldBS
Just bs' -> do
writeIORef refStep $ Right yieldBS
return bs'
Right action -> action
#endif /* !MIN_VERSION_blaze_builder(0,4,0) */
type BlazePopper = IO S.ByteString
type BlazeRecv = Builder -> IO BlazePopper
type BlazeFinish = IO (Maybe S.ByteString)