{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE CPP                 #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE MagicHash           #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies        #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE UnboxedTuples       #-}

{-|
Module      : Z.Data.Builder.Base
Description : Efficient serialization/format.
Copyright   : (c) Dong Han, 2017-2019
              (c) Tao He, 2018-2019
License     : BSD
Maintainer  : winterland1989@gmail.com
Stability   : experimental
Portability : non-portable

A 'Builder' records a buffer writing function, which can be 'mappend' in O(1) via composition.
In stdio a 'Builder' are designed to deal with different 'AllocateStrategy', it affects how
'Builder' react when writing across buffer boundaries:

  * When building a short strict 'Bytes' with 'buildBytes/buildByteswith',
    we do a 'DoubleBuffer'.

  * When building a large lazy @[Bytes]@ with 'buildBytesList/buildBytesListwith',
    we do an 'InsertChunk'.

  * When building and consuming are interlaced with 'buildAndRun/buildAndRunWith',
    we do an 'OneShotAction'.

Most of the time using combinators from this module to build 'Builder' s is enough,
but in case of rolling something shining from the ground, keep an eye on correct
'AllocateStrategy' handling.

-}

module Z.Data.Builder.Base
  ( -- * Builder type
    AllocateStrategy(..)
  , Buffer(..)
  , BuildStep
  , Builder(..)
  , append
   -- * Running a builder
  , buildBytes
  , buildBytesWith
  , buildBytesList
  , buildBytesListWith
  , buildAndRun
  , buildAndRunWith
    -- * Basic buiders
  , bytes
  , ensureN
  , atMost
  , writeN
   -- * Boundary handling
  , doubleBuffer
  , insertChunk
  , oneShotAction
   -- * Pritimive builders
  , encodePrim
  , encodePrimLE
  , encodePrimBE
  -- * More builders
  , stringModifiedUTF8, charModifiedUTF8, stringUTF8, charUTF8, string7, char7, string8, char8, text
  -- * Builder helpers
  , paren, curly, square, angle, quotes, squotes, colon, comma, intercalateVec, intercalateList
  ) where

import           Control.Monad
import           Control.Monad.Primitive
import           Control.Monad.ST
import           Control.Monad.ST.Unsafe            (unsafeInterleaveST)
import           Data.Bits                          (shiftL, shiftR, (.&.))
import           Data.Primitive.PrimArray           (MutablePrimArray (..))
import           Data.Primitive.Ptr                 (copyPtrToMutablePrimArray)
import           Data.String                        (IsString (..))
import           Data.Word
import           Data.Int
import           GHC.CString                        (unpackCString#, unpackCStringUtf8#)
import           GHC.Prim
import           GHC.Ptr
import           GHC.Types
import qualified Z.Data.Array                     as A
import           Z.Data.Array.UnalignedAccess
import qualified Z.Data.Text.Base                 as T
import qualified Z.Data.Text.UTF8Codec            as T
import qualified Z.Data.Vector.Base               as V
import qualified Z.Data.Vector                    as V
import           System.IO.Unsafe
import           Test.QuickCheck.Arbitrary (Arbitrary(..), CoArbitrary(..))

-- | 'AllocateStrategy' will decide how each 'BuildStep' proceed when previous buffer is not enough.
--
data AllocateStrategy s
    = DoubleBuffer       -- Double the buffer and continue building
    | InsertChunk {-# UNPACK #-} !Int   -- Insert a new chunk and continue building
    | OneShotAction (V.Bytes -> ST s ())  -- Freeze current chunk and perform action with it.
                                        -- Use the 'V.Bytes' argument outside the action is dangerous
                                        -- since we will reuse the buffer after action finished.

-- | Helper type to help ghc unpack
--
data Buffer s = Buffer {-# UNPACK #-} !(A.MutablePrimArray s Word8)  -- ^ the buffer content
                       {-# UNPACK #-} !Int  -- ^ writing offset

-- | @BuilderStep@ is a function that fill buffer under given conditions.
--
type BuildStep s = Buffer s -> ST s [V.Bytes]

-- | @Builder@ is a monad to help compose @BuilderStep@. With next @BuilderStep@ continuation,
-- we can do interesting things like perform some action, or interleave the build process.
--
-- Notes on 'IsString' instance: @Builder ()@'s 'IsString' instance use 'stringModifiedUTF8',
-- which is different from 'stringUTF8' in that it DOES NOT PROVIDE UTF8 GUARANTEES! :
--
-- * @\NUL@ will be written as @\xC0 \x80@.
-- * @\xD800@ ~ @\xDFFF@ will be encoded in three bytes as normal UTF-8 codepoints.
--
newtype Builder a = Builder
    { Builder a
-> forall s.
   AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
runBuilder :: forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s}

instance Show (Builder a) where
    show :: Builder a -> String
show = Bytes -> String
forall a. Show a => a -> String
show (Bytes -> String) -> (Builder a -> Bytes) -> Builder a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder a -> Bytes
forall a. Builder a -> Bytes
buildBytes

instance Functor Builder where
    {-# INLINE fmap #-}
    fmap :: (a -> b) -> Builder a -> Builder b
fmap a -> b
f (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b) = (forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s)
-> Builder b
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
al b -> BuildStep s
k -> AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b AllocateStrategy s
al (b -> BuildStep s
k (b -> BuildStep s) -> (a -> b) -> a -> BuildStep s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f))
    {-# INLINE (<$) #-}
    a
a <$ :: a -> Builder b -> Builder a
<$ (Builder forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
b) = (forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
al a -> BuildStep s
k -> AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
b AllocateStrategy s
al (\ b
_ -> a -> BuildStep s
k a
a))

instance Applicative Builder where
    {-# INLINE pure #-}
    pure :: a -> Builder a
pure a
x = (forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_ a -> BuildStep s
k -> a -> BuildStep s
k a
x)
    {-# INLINE (<*>) #-}
    (Builder forall s.
AllocateStrategy s -> ((a -> b) -> BuildStep s) -> BuildStep s
f) <*> :: Builder (a -> b) -> Builder a -> Builder b
<*> (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b) = (forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s)
-> Builder b
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
al b -> BuildStep s
k -> AllocateStrategy s -> ((a -> b) -> BuildStep s) -> BuildStep s
forall s.
AllocateStrategy s -> ((a -> b) -> BuildStep s) -> BuildStep s
f AllocateStrategy s
al ( \ a -> b
ab -> AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b AllocateStrategy s
al (b -> BuildStep s
k (b -> BuildStep s) -> (a -> b) -> a -> BuildStep s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
ab)))
    {-# INLINE (*>) #-}
    *> :: Builder a -> Builder b -> Builder b
(*>) = Builder a -> Builder b -> Builder b
forall a b. Builder a -> Builder b -> Builder b
append

instance Monad Builder where
    {-# INLINE (>>=) #-}
    (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b) >>= :: Builder a -> (a -> Builder b) -> Builder b
>>= a -> Builder b
f = (forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s)
-> Builder b
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
al b -> BuildStep s
k -> AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b AllocateStrategy s
al ( \ a
a -> Builder b
-> AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
forall a.
Builder a
-> forall s.
   AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
runBuilder (a -> Builder b
f a
a) AllocateStrategy s
al b -> BuildStep s
k))
    {-# INLINE (>>) #-}
    >> :: Builder a -> Builder b -> Builder b
(>>) = Builder a -> Builder b -> Builder b
forall a b. Builder a -> Builder b -> Builder b
append

instance Semigroup (Builder ()) where
    <> :: Builder () -> Builder () -> Builder ()
(<>) = Builder () -> Builder () -> Builder ()
forall a b. Builder a -> Builder b -> Builder b
append
    {-# INLINE (<>) #-}

instance Monoid (Builder ()) where
    mempty :: Builder ()
mempty = () -> Builder ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    {-# INLINE mempty #-}
    mappend :: Builder () -> Builder () -> Builder ()
mappend = Builder () -> Builder () -> Builder ()
forall a b. Builder a -> Builder b -> Builder b
append
    {-# INLINE mappend #-}
    mconcat :: [Builder ()] -> Builder ()
mconcat = (Builder () -> Builder () -> Builder ())
-> Builder () -> [Builder ()] -> Builder ()
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Builder () -> Builder () -> Builder ()
forall a b. Builder a -> Builder b -> Builder b
append (() -> Builder ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
    {-# INLINE mconcat #-}

instance (a ~ ()) => IsString (Builder a) where
    {-# INLINE fromString #-}
    fromString :: String -> Builder a
fromString = String -> Builder a
String -> Builder ()
stringModifiedUTF8

instance Arbitrary (Builder ()) where
    arbitrary :: Gen (Builder ())
arbitrary = Bytes -> Builder ()
bytes (Bytes -> Builder ()) -> Gen Bytes -> Gen (Builder ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Bytes
forall a. Arbitrary a => Gen a
arbitrary
    shrink :: Builder () -> [Builder ()]
shrink Builder ()
b = (Bytes -> Builder ()
bytes (Bytes -> Builder ())
-> ([Word8] -> Bytes) -> [Word8] -> Builder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> Bytes
forall (v :: * -> *) a. Vec v a => [a] -> v a
V.pack) ([Word8] -> Builder ()) -> [[Word8]] -> [Builder ()]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Word8] -> [[Word8]]
forall a. Arbitrary a => a -> [a]
shrink (Bytes -> [Word8]
forall (v :: * -> *) a. Vec v a => v a -> [a]
V.unpack (Builder () -> Bytes
forall a. Builder a -> Bytes
buildBytes Builder ()
b))

instance CoArbitrary (Builder ()) where
    coarbitrary :: Builder () -> Gen b -> Gen b
coarbitrary = Bytes -> Gen b -> Gen b
forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary (Bytes -> Gen b -> Gen b)
-> (Builder () -> Bytes) -> Builder () -> Gen b -> Gen b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder () -> Bytes
forall a. Builder a -> Bytes
buildBytes

-- | Encode string with modified UTF-8 encoding, will be rewritten to a memcpy if possible.
stringModifiedUTF8 :: String -> Builder ()
{-# INLINE CONLIKE [0] stringModifiedUTF8 #-}
{-# RULES
    "stringModifiedUTF8/packAddrModified" forall addr . stringModifiedUTF8 (unpackCString# addr) = packAddrModified addr
  #-}
{-# RULES
    "stringModifiedUTF8/packAddrModified" forall addr . stringModifiedUTF8 (unpackCStringUtf8# addr) = packAddrModified addr
  #-}
stringModifiedUTF8 :: String -> Builder ()
stringModifiedUTF8 = (Char -> Builder ()) -> String -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Char -> Builder ()
charModifiedUTF8

-- | Turn 'Char' into 'Builder' with Modified UTF8 encoding
--
-- '\NUL' is encoded as two bytes @C0 80@ , '\xD800' ~ '\xDFFF' is encoded as a three bytes normal UTF-8 codepoint.
charModifiedUTF8 :: Char -> Builder ()
{-# INLINE charModifiedUTF8 #-}
charModifiedUTF8 :: Char -> Builder ()
charModifiedUTF8 Char
chr = do
    Int -> Builder ()
ensureN Int
4
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
mba Int
i) -> do
        Int
i' <- MutablePrimArray (PrimState (ST s)) Word8
-> Int -> Char -> ST s Int
forall (m :: * -> *).
PrimMonad m =>
MutablePrimArray (PrimState m) Word8 -> Int -> Char -> m Int
T.encodeCharModifiedUTF8 MutablePrimArray s Word8
MutablePrimArray (PrimState (ST s)) Word8
mba Int
i Char
chr
        () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba Int
i'))

packAddrModified :: Addr# -> Builder ()
packAddrModified :: Addr# -> Builder ()
packAddrModified Addr#
addr0# = Addr# -> Builder ()
copy Addr#
addr0#
  where
    len :: Int
len = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> (IO CSize -> CSize) -> IO CSize -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO CSize -> CSize
forall a. IO a -> a
unsafeDupablePerformIO (IO CSize -> Int) -> IO CSize -> Int
forall a b. (a -> b) -> a -> b
$ Addr# -> IO CSize
V.c_strlen Addr#
addr0#
    copy :: Addr# -> Builder ()
copy Addr#
addr# = do
        Int -> Builder ()
ensureN Int
len
        (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
mba Int
i) -> do
           MutablePrimArray (PrimState (ST s)) Word8
-> Int -> Ptr Word8 -> Int -> ST s ()
forall (m :: * -> *) a.
(PrimMonad m, Prim a) =>
MutablePrimArray (PrimState m) a -> Int -> Ptr a -> Int -> m ()
copyPtrToMutablePrimArray MutablePrimArray s Word8
MutablePrimArray (PrimState (ST s)) Word8
mba Int
i (Addr# -> Ptr Word8
forall a. Addr# -> Ptr a
Ptr Addr#
addr#) Int
len
           () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len)))

append :: Builder a -> Builder b -> Builder b
{-# INLINE append #-}
append :: Builder a -> Builder b -> Builder b
append (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
f) (Builder forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
g) = (forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s)
-> Builder b
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
al b -> BuildStep s
k -> AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
f AllocateStrategy s
al ( \ a
_ ->  AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (b -> BuildStep s) -> BuildStep s
g AllocateStrategy s
al b -> BuildStep s
k))

--------------------------------------------------------------------------------

-- | Write a 'V.Bytes'.
bytes :: V.Bytes -> Builder ()
{-# INLINE bytes #-}
bytes :: Bytes -> Builder ()
bytes bs :: Bytes
bs@(V.PrimVector PrimArray Word8
arr Int
s Int
l) = (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
strategy () -> BuildStep s
k buffer :: Buffer s
buffer@(Buffer MutablePrimArray s Word8
buf Int
offset) ->
    case AllocateStrategy s
strategy of
        AllocateStrategy s
DoubleBuffer -> AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
copy AllocateStrategy s
strategy () -> BuildStep s
k Buffer s
buffer
        InsertChunk Int
chunkSiz
            | Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
chunkSiz Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
1 ->
                AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
copy AllocateStrategy s
strategy () -> BuildStep s
k Buffer s
buffer -- the copy limit is half the chunk size
            | Int
offset Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 ->
                 Int -> Int -> BuildStep s -> BuildStep s
forall s. Int -> Int -> BuildStep s -> BuildStep s
insertChunk Int
chunkSiz Int
0 (\ Buffer s
buffer' -> (Bytes
bsBytes -> [Bytes] -> [Bytes]
forall a. a -> [a] -> [a]
:) ([Bytes] -> [Bytes]) -> ST s [Bytes] -> ST s [Bytes]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` () -> BuildStep s
k () Buffer s
buffer') Buffer s
buffer
            | Bool
otherwise -> (Bytes
bsBytes -> [Bytes] -> [Bytes]
forall a. a -> [a] -> [a]
:) ([Bytes] -> [Bytes]) -> ST s [Bytes] -> ST s [Bytes]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` () -> BuildStep s
k () Buffer s
buffer
        OneShotAction Bytes -> ST s ()
action -> do
            Int
chunkSiz <- MArr PrimArray s Word8 -> ST s Int
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m Int
A.sizeofMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf
            case () of
                ()
_
                    | Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
chunkSiz Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
1 ->
                        AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
copy AllocateStrategy s
strategy () -> BuildStep s
k Buffer s
buffer
                    | Int
offset Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 ->
                        (Bytes -> ST s ()) -> Int -> BuildStep s -> BuildStep s
forall s. (Bytes -> ST s ()) -> Int -> BuildStep s -> BuildStep s
oneShotAction Bytes -> ST s ()
action Int
0 (\ Buffer s
buffer' -> Bytes -> ST s ()
action Bytes
bs ST s () -> ST s [Bytes] -> ST s [Bytes]
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> BuildStep s
k () Buffer s
buffer') Buffer s
buffer
                    | Bool
otherwise -> Bytes -> ST s ()
action Bytes
bs ST s () -> ST s [Bytes] -> ST s [Bytes]
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> BuildStep s
k () Buffer s
buffer)
  where
    copy :: forall s. AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
    copy :: AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
copy AllocateStrategy s
strategy () -> BuildStep s
k =
        Builder ()
-> AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s
forall a.
Builder a
-> forall s.
   AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
runBuilder (Int -> Builder ()
ensureN Int
l) AllocateStrategy s
strategy ( \ ()
_ (Buffer MutablePrimArray s Word8
buf Int
offset) -> do
                MArr PrimArray s Word8
-> Int -> PrimArray Word8 -> Int -> Int -> ST s ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> arr a -> Int -> Int -> m ()
A.copyArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf Int
offset PrimArray Word8
arr Int
s Int
l
                () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf (Int
offsetInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
l)))
    {-# INLINE copy #-}

-- | Ensure that there are at least @n@ many elements available.
ensureN :: Int -> Builder ()
{-# INLINE ensureN #-}
ensureN :: Int -> Builder ()
ensureN !Int
n = (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder ((forall s.
  AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
 -> Builder ())
-> (forall s.
    AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a b. (a -> b) -> a -> b
$ \ AllocateStrategy s
strategy () -> BuildStep s
k buffer :: Buffer s
buffer@(Buffer MutablePrimArray s Word8
buf Int
offset) -> do
    Int
siz <- MArr PrimArray s Word8 -> ST s Int
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m Int
A.sizeofMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf  -- You may think doing this will be slow
                                   -- but this value lives in CPU cache for most of the time
    if Int
siz Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
offset Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
n
    then () -> BuildStep s
k () Buffer s
buffer
    else AllocateStrategy s -> Int -> (() -> BuildStep s) -> BuildStep s
forall s.
AllocateStrategy s -> Int -> (() -> BuildStep s) -> BuildStep s
handleBoundary AllocateStrategy s
strategy Int
n () -> BuildStep s
k Buffer s
buffer
  where
    {-# NOINLINE handleBoundary #-} -- Don't inline this branchy code
    handleBoundary :: AllocateStrategy s -> Int -> (() -> BuildStep s) -> BuildStep s
handleBoundary AllocateStrategy s
DoubleBuffer Int
n' () -> BuildStep s
k Buffer s
buffer = Int -> BuildStep s -> BuildStep s
forall s. Int -> BuildStep s -> BuildStep s
doubleBuffer Int
n' (() -> BuildStep s
k ()) Buffer s
buffer
    handleBoundary (InsertChunk Int
chunkSiz) Int
n' () -> BuildStep s
k Buffer s
buffer = Int -> Int -> BuildStep s -> BuildStep s
forall s. Int -> Int -> BuildStep s -> BuildStep s
insertChunk Int
chunkSiz Int
n' (() -> BuildStep s
k ()) Buffer s
buffer
    handleBoundary (OneShotAction Bytes -> ST s ()
action) Int
n' () -> BuildStep s
k Buffer s
buffer = (Bytes -> ST s ()) -> Int -> BuildStep s -> BuildStep s
forall s. (Bytes -> ST s ()) -> Int -> BuildStep s -> BuildStep s
oneShotAction Bytes -> ST s ()
action Int
n' (() -> BuildStep s
k ()) Buffer s
buffer

--------------------------------------------------------------------------------
--
-- Handle chunk boundary

doubleBuffer :: Int -> BuildStep s -> BuildStep s
doubleBuffer :: Int -> BuildStep s -> BuildStep s
doubleBuffer !Int
wantSiz BuildStep s
k (Buffer MutablePrimArray s Word8
buf Int
offset) = do
    !Int
siz <- MArr PrimArray s Word8 -> ST s Int
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m Int
A.sizeofMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf
    let !siz' :: Int
siz' = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (Int
offset Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
wantSiz Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
1)
                    (Int
siz Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
1)
    MutablePrimArray s Word8
buf' <- MArr PrimArray s Word8 -> Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> m (MArr arr s a)
A.resizeMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf Int
siz'   -- double the buffer
    BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf' Int
offset)                -- continue building
{-# INLINE doubleBuffer #-}

insertChunk :: Int -> Int -> BuildStep s -> BuildStep s
{-# INLINE insertChunk #-}
insertChunk :: Int -> Int -> BuildStep s -> BuildStep s
insertChunk !Int
chunkSiz !Int
wantSiz BuildStep s
k (Buffer MutablePrimArray s Word8
buf Int
offset) = do
    !Int
siz <- MArr PrimArray s Word8 -> ST s Int
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m Int
A.sizeofMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf
    case () of
        ()
_
            | Int
offset Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 -> do
                Bool -> ST s () -> ST s ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
offset Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
siz)
                    (MArr PrimArray s Word8 -> Int -> ST s ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> m ()
A.shrinkMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf Int
offset)            -- shrink old buffer if not full
                PrimArray Word8
arr <- MArr PrimArray s Word8 -> ST s (PrimArray Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
A.unsafeFreezeArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf                   -- popup old buffer
                MutablePrimArray s Word8
buf' <- Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
wantSiz Int
chunkSiz)        -- make a new buffer
                [Bytes]
xs <- ST s [Bytes] -> ST s [Bytes]
forall s a. ST s a -> ST s a
unsafeInterleaveST (BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf' Int
0))   -- delay the rest building process
                let v :: Bytes
v = IArray PrimVector Word8 -> Int -> Int -> Bytes
forall (v :: * -> *) a. Vec v a => IArray v a -> Int -> Int -> v a
V.fromArr PrimArray Word8
IArray PrimVector Word8
arr Int
0 Int
offset
                Bytes
v Bytes -> ST s [Bytes] -> ST s [Bytes]
`seq` [Bytes] -> ST s [Bytes]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bytes
v Bytes -> [Bytes] -> [Bytes]
forall a. a -> [a] -> [a]
: [Bytes]
xs)
            | Int
wantSiz Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
siz -> BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf Int
0) -- this should certainly not hold, but we still guard it
            | Bool
otherwise -> do
                MutablePrimArray s Word8
buf' <- Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
wantSiz Int
chunkSiz)        -- make a new buffer
                BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf' Int
0)

oneShotAction :: (V.Bytes -> ST s ()) -> Int -> BuildStep s -> BuildStep s
{-# INLINE oneShotAction #-}
oneShotAction :: (Bytes -> ST s ()) -> Int -> BuildStep s -> BuildStep s
oneShotAction Bytes -> ST s ()
action !Int
wantSiz BuildStep s
k (Buffer MutablePrimArray s Word8
buf Int
offset) = do
    !Int
siz <- MArr PrimArray s Word8 -> ST s Int
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m Int
A.sizeofMutableArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf
    case () of
        ()
_
            | Int
offset Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 -> do
                PrimArray Word8
arr <- MArr PrimArray s Word8 -> ST s (PrimArray Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
A.unsafeFreezeArr MutablePrimArray s Word8
MArr PrimArray s Word8
buf             -- popup old buffer
                Bytes -> ST s ()
action (PrimArray Word8 -> Int -> Int -> Bytes
forall a. PrimArray a -> Int -> Int -> PrimVector a
V.PrimVector PrimArray Word8
arr Int
0 Int
offset)
                if Int
wantSiz Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
siz
                then BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf Int
0)                    -- continue building with old buf
                else do
                    MutablePrimArray s Word8
buf' <- Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr Int
wantSiz             -- make a new buffer
                    BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf' Int
0)
            | Int
wantSiz Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
siz -> BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf Int
0)
            | Bool
otherwise -> do
                MutablePrimArray s Word8
buf' <- Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr Int
wantSiz                -- make a new buffer
                BuildStep s
k (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf' Int
0 )

--------------------------------------------------------------------------------

-- | shortcut to 'buildBytesWith' 'V.defaultInitSize'.
buildBytes :: Builder a -> V.Bytes
{-# INLINE buildBytes #-}
buildBytes :: Builder a -> Bytes
buildBytes = Int -> Builder a -> Bytes
forall a. Int -> Builder a -> Bytes
buildBytesWith Int
V.defaultInitSize

-- | run Builder with 'DoubleBuffer' strategy, which is suitable
-- for building short bytes.
buildBytesWith :: Int -> Builder a -> V.Bytes
{-# INLINABLE buildBytesWith #-}
buildBytesWith :: Int -> Builder a -> Bytes
buildBytesWith Int
initSiz (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b) = (forall s. ST s Bytes) -> Bytes
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s Bytes) -> Bytes)
-> (forall s. ST s Bytes) -> Bytes
forall a b. (a -> b) -> a -> b
$ do
    MutablePrimArray s Word8
buf <- Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr Int
initSiz
    [Bytes
bs] <- AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b AllocateStrategy s
forall s. AllocateStrategy s
DoubleBuffer a -> BuildStep s
forall (m :: * -> *) p.
PrimMonad m =>
p -> Buffer (PrimState m) -> m [Bytes]
lastStep (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf Int
0 )
    Bytes -> ST s Bytes
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bytes
bs
  where
    lastStep :: p -> Buffer (PrimState m) -> m [Bytes]
lastStep p
_ (Buffer MutablePrimArray (PrimState m) Word8
buf Int
offset) = do
        Int
siz <- MArr PrimArray (PrimState m) Word8 -> m Int
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m Int
A.sizeofMutableArr MutablePrimArray (PrimState m) Word8
MArr PrimArray (PrimState m) Word8
buf
        Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
offset Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
siz) (MArr PrimArray (PrimState m) Word8 -> Int -> m ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> m ()
A.shrinkMutableArr MutablePrimArray (PrimState m) Word8
MArr PrimArray (PrimState m) Word8
buf Int
offset)
        PrimArray Word8
arr <- MArr PrimArray (PrimState m) Word8 -> m (PrimArray Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
A.unsafeFreezeArr MutablePrimArray (PrimState m) Word8
MArr PrimArray (PrimState m) Word8
buf
        [Bytes] -> m [Bytes]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [PrimArray Word8 -> Int -> Int -> Bytes
forall a. PrimArray a -> Int -> Int -> PrimVector a
V.PrimVector PrimArray Word8
arr Int
0 Int
offset]

-- | shortcut to 'buildBytesListWith' 'V.defaultChunkSize'.
buildBytesList :: Builder a -> [V.Bytes]
{-# INLINE buildBytesList #-}
buildBytesList :: Builder a -> [Bytes]
buildBytesList = Int -> Int -> Builder a -> [Bytes]
forall a. Int -> Int -> Builder a -> [Bytes]
buildBytesListWith  Int
V.smallChunkSize Int
V.defaultChunkSize

-- | run Builder with 'InsertChunk' strategy, which is suitable
-- for building lazy bytes chunks.
buildBytesListWith :: Int -> Int -> Builder a -> [V.Bytes]
{-# INLINABLE buildBytesListWith #-}
buildBytesListWith :: Int -> Int -> Builder a -> [Bytes]
buildBytesListWith Int
initSiz Int
chunkSiz (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b) = (forall s. ST s [Bytes]) -> [Bytes]
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s [Bytes]) -> [Bytes])
-> (forall s. ST s [Bytes]) -> [Bytes]
forall a b. (a -> b) -> a -> b
$ do
    MutablePrimArray s Word8
buf <- Int -> ST s (MArr PrimArray s Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr Int
initSiz
    AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b (Int -> AllocateStrategy s
forall s. Int -> AllocateStrategy s
InsertChunk Int
chunkSiz) a -> BuildStep s
forall (m :: * -> *) p.
PrimMonad m =>
p -> Buffer (PrimState m) -> m [Bytes]
lastStep (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf Int
0)
  where
    lastStep :: p -> Buffer (PrimState m) -> m [Bytes]
lastStep p
_ (Buffer MutablePrimArray (PrimState m) Word8
buf Int
offset) = do
        PrimArray Word8
arr <- MArr PrimArray (PrimState m) Word8 -> m (PrimArray Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
A.unsafeFreezeArr MutablePrimArray (PrimState m) Word8
MArr PrimArray (PrimState m) Word8
buf
        [Bytes] -> m [Bytes]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [PrimArray Word8 -> Int -> Int -> Bytes
forall a. PrimArray a -> Int -> Int -> PrimVector a
V.PrimVector PrimArray Word8
arr Int
0 Int
offset]

-- | shortcut to 'buildAndRunWith' 'V.defaultChunkSize'.
buildAndRun :: (V.Bytes -> IO ()) -> Builder a -> IO ()
buildAndRun :: (Bytes -> IO ()) -> Builder a -> IO ()
buildAndRun = Int -> (Bytes -> IO ()) -> Builder a -> IO ()
forall a. Int -> (Bytes -> IO ()) -> Builder a -> IO ()
buildAndRunWith Int
V.defaultChunkSize

-- | run Builder with 'OneShotAction' strategy, which is suitable
-- for doing effects while building.
buildAndRunWith :: Int -> (V.Bytes -> IO ()) -> Builder a -> IO ()
buildAndRunWith :: Int -> (Bytes -> IO ()) -> Builder a -> IO ()
buildAndRunWith Int
chunkSiz Bytes -> IO ()
action (Builder forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b) = do
    MutablePrimArray RealWorld Word8
buf <- Int -> IO (MArr PrimArray RealWorld Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
A.newArr Int
chunkSiz
    [Bytes]
_ <- ST RealWorld [Bytes] -> IO [Bytes]
forall a. ST RealWorld a -> IO a
stToIO (AllocateStrategy RealWorld
-> (a -> BuildStep RealWorld) -> BuildStep RealWorld
forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s
b ((Bytes -> ST RealWorld ()) -> AllocateStrategy RealWorld
forall s. (Bytes -> ST s ()) -> AllocateStrategy s
OneShotAction (\ Bytes
bs -> IO () -> ST RealWorld ()
forall (m :: * -> *) a.
(PrimMonad m, PrimState m ~ RealWorld) =>
IO a -> m a
ioToPrim (Bytes -> IO ()
action Bytes
bs))) a -> BuildStep RealWorld
forall a. a -> BuildStep RealWorld
lastStep (MutablePrimArray RealWorld Word8 -> Int -> Buffer RealWorld
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray RealWorld Word8
buf Int
0))
    () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  where
    lastStep :: a -> BuildStep RealWorld
    lastStep :: a -> BuildStep RealWorld
lastStep a
_ (Buffer MutablePrimArray RealWorld Word8
buf Int
offset) = do
        PrimArray Word8
arr <- MArr PrimArray RealWorld Word8 -> ST RealWorld (PrimArray Word8)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
A.unsafeFreezeArr MutablePrimArray RealWorld Word8
MArr PrimArray RealWorld Word8
buf
        IO () -> ST RealWorld ()
forall (m :: * -> *) a.
(PrimMonad m, PrimState m ~ RealWorld) =>
IO a -> m a
ioToPrim (Bytes -> IO ()
action (PrimArray Word8 -> Int -> Int -> Bytes
forall a. PrimArray a -> Int -> Int -> PrimVector a
V.PrimVector PrimArray Word8
arr Int
0 Int
offset))
        [Bytes] -> ST RealWorld [Bytes]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [] -- to match the silly pure type
{-# INLINABLE buildAndRun #-}

--------------------------------------------------------------------------------

atMost :: Int  -- ^ size bound
       -> (forall s. A.MutablePrimArray s Word8 -> Int -> ST s Int)  -- ^ the writer which pure a new offset
                                                                       -- for next write
       -> Builder ()
{-# INLINE atMost #-}
atMost :: Int
-> (forall s. MutablePrimArray s Word8 -> Int -> ST s Int)
-> Builder ()
atMost Int
n forall s. MutablePrimArray s Word8 -> Int -> ST s Int
f = Int -> Builder ()
ensureN Int
n Builder () -> Builder () -> Builder ()
forall a b. Builder a -> Builder b -> Builder b
`append`
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
buf Int
offset ) ->
        MutablePrimArray s Word8 -> Int -> ST s Int
forall s. MutablePrimArray s Word8 -> Int -> ST s Int
f MutablePrimArray s Word8
buf Int
offset ST s Int -> (Int -> ST s [Bytes]) -> ST s [Bytes]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ Int
offset' -> () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf Int
offset'))

writeN :: Int  -- ^ size bound
       -> (forall s. A.MutablePrimArray s Word8 -> Int -> ST s ())  -- ^ the writer which pure a new offset
                                                                    -- for next write
       -> Builder ()
{-# INLINE writeN #-}
writeN :: Int
-> (forall s. MutablePrimArray s Word8 -> Int -> ST s ())
-> Builder ()
writeN Int
n forall s. MutablePrimArray s Word8 -> Int -> ST s ()
f = Int -> Builder ()
ensureN Int
n Builder () -> Builder () -> Builder ()
forall a b. Builder a -> Builder b -> Builder b
`append`
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
buf Int
offset ) ->
        MutablePrimArray s Word8 -> Int -> ST s ()
forall s. MutablePrimArray s Word8 -> Int -> ST s ()
f MutablePrimArray s Word8
buf Int
offset ST s () -> ST s [Bytes] -> ST s [Bytes]
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
buf (Int
offsetInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
n)))

-- | write primitive types in host byte order.
encodePrim :: forall a. UnalignedAccess a => a -> Builder ()
{-# INLINE encodePrim #-}
{-# SPECIALIZE INLINE encodePrim :: Word -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Word64 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Word32 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Word16 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Word8 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Int -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Int64 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Int32 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Int16 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrim :: Int8 -> Builder () #-}
encodePrim :: a -> Builder ()
encodePrim a
x = do
    Int -> Builder ()
ensureN Int
n
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer (MutablePrimArray MutableByteArray# s
mba#) i :: Int
i@(I# Int#
i#)) -> do
        (State# (PrimState (ST s)) -> State# (PrimState (ST s))) -> ST s ()
forall (m :: * -> *).
PrimMonad m =>
(State# (PrimState m) -> State# (PrimState m)) -> m ()
primitive_ (MutableByteArray# s -> Int# -> a -> State# s -> State# s
forall a s.
UnalignedAccess a =>
MutableByteArray# s -> Int# -> a -> State# s -> State# s
writeWord8ArrayAs MutableByteArray# s
mba# Int#
i# a
x)
        () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer (MutableByteArray# s -> MutablePrimArray s Word8
forall s a. MutableByteArray# s -> MutablePrimArray s a
MutablePrimArray MutableByteArray# s
mba#) (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n)))
  where
    n :: Int
n = (UnalignedSize a -> Int
forall a. UnalignedSize a -> Int
getUnalignedSize (UnalignedSize a
forall a. UnalignedAccess a => UnalignedSize a
unalignedSize :: UnalignedSize a))

-- | write primitive types with little endianess.
encodePrimLE :: forall a. UnalignedAccess (LE a) => a -> Builder ()
{-# INLINE encodePrimLE #-}
{-# SPECIALIZE INLINE encodePrimLE :: Word -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Word64 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Word32 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Word16 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Int -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Int64 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Int32 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimLE :: Int16 -> Builder () #-}
encodePrimLE :: a -> Builder ()
encodePrimLE = LE a -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim (LE a -> Builder ()) -> (a -> LE a) -> a -> Builder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> LE a
forall a. a -> LE a
LE

-- | write primitive types with big endianess.
encodePrimBE :: forall a. UnalignedAccess (BE a) => a -> Builder ()
{-# INLINE encodePrimBE #-}
{-# SPECIALIZE INLINE encodePrimBE :: Word -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Word64 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Word32 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Word16 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Int -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Int64 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Int32 -> Builder () #-}
{-# SPECIALIZE INLINE encodePrimBE :: Int16 -> Builder () #-}
encodePrimBE :: a -> Builder ()
encodePrimBE = BE a -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim (BE a -> Builder ()) -> (a -> BE a) -> a -> Builder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> BE a
forall a. a -> BE a
BE

--------------------------------------------------------------------------------

-- | Turn 'String' into 'Builder' with UTF8 encoding
--
-- Illegal codepoints will be written as 'T.replacementChar's.
--
-- Note, if you're trying to write string literals builders, and you know it doen't contain
-- '\NUL' or surrgate codepoints, then you can open 'OverloadedStrings' and use 'Builder''s
-- 'IsString' instance, it can save an extra UTF-8 validation.
--
-- This function will be rewritten into a memcpy if possible, (running a fast UTF-8 validation
-- at runtime first).
stringUTF8 :: String -> Builder ()
{-# INLINE CONLIKE [0] stringUTF8 #-}
{-# RULES
    "stringUTF8/packASCIIAddr" forall addr . stringUTF8 (unpackCString# addr) = packASCIIAddr addr
  #-}
{-# RULES
    "stringUTF8/packUTF8Addr" forall addr . stringUTF8 (unpackCString# addr) = packUTF8Addr addr
  #-}
stringUTF8 :: String -> Builder ()
stringUTF8 = (Char -> Builder ()) -> String -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Char -> Builder ()
charUTF8

packASCIIAddr :: Addr# -> Builder ()
packASCIIAddr :: Addr# -> Builder ()
packASCIIAddr Addr#
addr0# = Addr# -> Builder ()
copy Addr#
addr0#
  where
    len :: Int
len = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> (IO CSize -> CSize) -> IO CSize -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO CSize -> CSize
forall a. IO a -> a
unsafeDupablePerformIO (IO CSize -> Int) -> IO CSize -> Int
forall a b. (a -> b) -> a -> b
$ Addr# -> IO CSize
V.c_strlen Addr#
addr0#
    copy :: Addr# -> Builder ()
copy Addr#
addr# = do
        Int -> Builder ()
ensureN Int
len
        (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
mba Int
i) -> do
           MutablePrimArray (PrimState (ST s)) Word8
-> Int -> Ptr Word8 -> Int -> ST s ()
forall (m :: * -> *) a.
(PrimMonad m, Prim a) =>
MutablePrimArray (PrimState m) a -> Int -> Ptr a -> Int -> m ()
copyPtrToMutablePrimArray MutablePrimArray s Word8
MutablePrimArray (PrimState (ST s)) Word8
mba Int
i (Addr# -> Ptr Word8
forall a. Addr# -> Ptr a
Ptr Addr#
addr#) Int
len
           () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len)))

packUTF8Addr :: Addr# -> Builder ()
packUTF8Addr :: Addr# -> Builder ()
packUTF8Addr Addr#
addr0# = Addr# -> Builder ()
validateAndCopy Addr#
addr0#
  where
    len :: Int
len = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> (IO CSize -> CSize) -> IO CSize -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO CSize -> CSize
forall a. IO a -> a
unsafeDupablePerformIO (IO CSize -> Int) -> IO CSize -> Int
forall a b. (a -> b) -> a -> b
$ Addr# -> IO CSize
V.c_strlen Addr#
addr0#
    valid :: Int
valid = IO Int -> Int
forall a. IO a -> a
unsafeDupablePerformIO (IO Int -> Int) -> IO Int -> Int
forall a b. (a -> b) -> a -> b
$ Addr# -> Int -> IO Int
T.c_utf8_validate_addr Addr#
addr0# Int
len
    validateAndCopy :: Addr# -> Builder ()
validateAndCopy Addr#
addr#
        | Int
valid Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = (Char -> Builder ()) -> String -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Char -> Builder ()
charUTF8 (Addr# -> String
unpackCString# Addr#
addr#)
        | Bool
otherwise = do
            Int -> Builder ()
ensureN Int
len
            (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
mba Int
i) -> do
               MutablePrimArray (PrimState (ST s)) Word8
-> Int -> Ptr Word8 -> Int -> ST s ()
forall (m :: * -> *) a.
(PrimMonad m, Prim a) =>
MutablePrimArray (PrimState m) a -> Int -> Ptr a -> Int -> m ()
copyPtrToMutablePrimArray MutablePrimArray s Word8
MutablePrimArray (PrimState (ST s)) Word8
mba Int
i (Addr# -> Ptr Word8
forall a. Addr# -> Ptr a
Ptr Addr#
addr#) Int
len
               () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len)))

-- | Turn 'Char' into 'Builder' with UTF8 encoding
--
-- Illegal codepoints will be written as 'T.replacementChar's.
charUTF8 :: Char -> Builder ()
{-# INLINE charUTF8 #-}
charUTF8 :: Char -> Builder ()
charUTF8 Char
chr = do
    Int -> Builder ()
ensureN Int
4
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer MutablePrimArray s Word8
mba Int
i) -> do
        Int
i' <- MutablePrimArray s Word8 -> Int -> Char -> ST s Int
forall s. MutablePrimArray s Word8 -> Int -> Char -> ST s Int
T.encodeChar MutablePrimArray s Word8
mba Int
i Char
chr
        () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba Int
i'))

-- | Turn 'String' into 'Builder' with ASCII7 encoding
--
-- Codepoints beyond @'\x7F'@ will be chopped.
string7 :: String -> Builder ()
{-# INLINE string7 #-}
string7 :: String -> Builder ()
string7 = (Char -> Builder ()) -> String -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Char -> Builder ()
char7

-- | Turn 'Char' into 'Builder' with ASCII7 encoding
--
-- Codepoints beyond @'\x7F'@ will be chopped.
char7 :: Char -> Builder ()
{-# INLINE char7 #-}
char7 :: Char -> Builder ()
char7 Char
chr = do
    Int -> Builder ()
ensureN Int
1
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer mba :: MutablePrimArray s Word8
mba@(MutablePrimArray MutableByteArray# s
mba#) i :: Int
i@(I# Int#
i#)) -> do
        let x :: Word8
x = Char -> Word8
V.c2w Char
chr Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x7F
        (State# (PrimState (ST s)) -> State# (PrimState (ST s))) -> ST s ()
forall (m :: * -> *).
PrimMonad m =>
(State# (PrimState m) -> State# (PrimState m)) -> m ()
primitive_ (MutableByteArray# s -> Int# -> Word8 -> State# s -> State# s
forall a s.
UnalignedAccess a =>
MutableByteArray# s -> Int# -> a -> State# s -> State# s
writeWord8ArrayAs MutableByteArray# s
mba# Int#
i# Word8
x)
        () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)))

-- | Turn 'String' into 'Builder' with ASCII8 encoding
--
-- Codepoints beyond @'\xFF'@ will be chopped.
-- Note, this encoding is NOT compatible with UTF8 encoding, i.e. bytes written
-- by this builder may not be legal UTF8 encoding bytes.
string8 :: String -> Builder ()
{-# INLINE string8 #-}
string8 :: String -> Builder ()
string8 = (Char -> Builder ()) -> String -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Char -> Builder ()
char8

-- | Turn 'Char' into 'Builder' with ASCII8 encoding
--
-- Codepoints beyond @'\xFF'@ will be chopped.
-- Note, this encoding is NOT compatible with UTF8 encoding, i.e. bytes written
-- by this builder may not be legal UTF8 encoding bytes.
char8 :: Char -> Builder ()
{-# INLINE char8 #-}
char8 :: Char -> Builder ()
char8 Char
chr = do
    Int -> Builder ()
ensureN Int
1
    (forall s.
 AllocateStrategy s -> (() -> BuildStep s) -> BuildStep s)
-> Builder ()
forall a.
(forall s. AllocateStrategy s -> (a -> BuildStep s) -> BuildStep s)
-> Builder a
Builder (\ AllocateStrategy s
_  () -> BuildStep s
k (Buffer mba :: MutablePrimArray s Word8
mba@(MutablePrimArray MutableByteArray# s
mba#) i :: Int
i@(I# Int#
i#)) -> do
        let x :: Word8
x = Char -> Word8
V.c2w Char
chr
        (State# (PrimState (ST s)) -> State# (PrimState (ST s))) -> ST s ()
forall (m :: * -> *).
PrimMonad m =>
(State# (PrimState m) -> State# (PrimState m)) -> m ()
primitive_ (MutableByteArray# s -> Int# -> Word8 -> State# s -> State# s
forall a s.
UnalignedAccess a =>
MutableByteArray# s -> Int# -> a -> State# s -> State# s
writeWord8ArrayAs MutableByteArray# s
mba# Int#
i# Word8
x)
        () -> BuildStep s
k () (MutablePrimArray s Word8 -> Int -> Buffer s
forall s. MutablePrimArray s Word8 -> Int -> Buffer s
Buffer MutablePrimArray s Word8
mba (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)))

-- | Write UTF8 encoded 'Text' using 'Builder'.
--
-- Note, if you're trying to write string literals builders,
-- please open 'OverloadedStrings' and use 'Builder's 'IsString' instance,
-- it will be rewritten into a memcpy.
text :: T.Text -> Builder ()
{-# INLINE text #-}
text :: Text -> Builder ()
text (T.Text Bytes
bs) = Bytes -> Builder ()
bytes Bytes
bs

--------------------------------------------------------------------------------

#define BACKSLASH 92
#define CLOSE_ANGLE 62
#define CLOSE_CURLY 125
#define CLOSE_PAREN 41
#define CLOSE_SQUARE 93
#define COMMA 44
#define COLON 58
#define DOUBLE_QUOTE 34
#define OPEN_ANGLE 60
#define OPEN_CURLY 123
#define OPEN_PAREN 40
#define OPEN_SQUARE 91
#define SINGLE_QUOTE 39

-- | add @{...}@ to original builder.
paren :: Builder () -> Builder ()
{-# INLINE paren #-}
paren :: Builder () -> Builder ()
paren Builder ()
b = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 OPEN_PAREN >> b >> encodePrim @Word8 CLOSE_PAREN

-- | add @{...}@ to original builder.
curly :: Builder () -> Builder ()
{-# INLINE curly #-}
curly :: Builder () -> Builder ()
curly Builder ()
b = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 OPEN_CURLY >> b >> encodePrim @Word8 CLOSE_CURLY

-- | add @[...]@ to original builder.
square :: Builder () -> Builder ()
{-# INLINE square #-}
square :: Builder () -> Builder ()
square Builder ()
b = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 OPEN_SQUARE >> b >> encodePrim @Word8 CLOSE_SQUARE

-- | add @<...>@ to original builder.
angle :: Builder () -> Builder ()
{-# INLINE angle #-}
angle :: Builder () -> Builder ()
angle Builder ()
b = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 OPEN_ANGLE >> b >> encodePrim @Word8 CLOSE_ANGLE

-- | add @"..."@ to original builder.
quotes :: Builder () -> Builder ()
{-# INLINE quotes #-}
quotes :: Builder () -> Builder ()
quotes Builder ()
b = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 DOUBLE_QUOTE >> b >> encodePrim @Word8 DOUBLE_QUOTE

-- | add @'...'@ to original builder.
squotes :: Builder () -> Builder ()
{-# INLINE squotes #-}
squotes :: Builder () -> Builder ()
squotes Builder ()
b = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 SINGLE_QUOTE >> b >> encodePrim @Word8 SINGLE_QUOTE

-- | write an ASCII @:@
colon :: Builder ()
{-# INLINE colon #-}
colon :: Builder ()
colon = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 COLON

-- | write an ASCII @,@
comma :: Builder ()
{-# INLINE comma #-}
comma :: Builder ()
comma = Word8 -> Builder ()
forall a. UnalignedAccess a => a -> Builder ()
encodePrim @Word8 COMMA

-- | Use separator to connect a vector of builders.
intercalateVec :: (V.Vec v a)
            => Builder ()           -- ^ the seperator
            -> (a -> Builder ())    -- ^ value formatter
            -> v a                  -- ^ value vector
            ->  Builder ()
{-# INLINE intercalateVec #-}
intercalateVec :: Builder () -> (a -> Builder ()) -> v a -> Builder ()
intercalateVec Builder ()
s a -> Builder ()
f v a
v = do
    (a -> Builder ()) -> v a -> Builder ()
forall (v :: * -> *) a (f :: * -> *) b.
(Vec v a, Applicative f) =>
(a -> f b) -> v a -> f ()
V.traverseVec_ (\ a
x -> a -> Builder ()
f a
x Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
s) (v a -> v a
forall (v :: * -> *) a. Vec v a => v a -> v a
V.initMayEmpty v a
v)
    Maybe a -> (a -> Builder ()) -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (v a -> Maybe a
forall (v :: * -> *) a. Vec v a => v a -> Maybe a
V.lastMaybe v a
v) a -> Builder ()
f

-- | Use separator to connect list of builders.
intercalateList :: Builder ()           -- ^ the seperator
                -> (a -> Builder ())    -- ^ value formatter
                -> [a]                  -- ^ value list
                -> Builder ()
{-# INLINE intercalateList #-}
intercalateList :: Builder () -> (a -> Builder ()) -> [a] -> Builder ()
intercalateList Builder ()
s a -> Builder ()
f [a]
xs = [a] -> Builder ()
go [a]
xs
  where
    go :: [a] -> Builder ()
go [] = () -> Builder ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    go [a
x] = a -> Builder ()
f a
x
    go (a
x:[a]
xs') = a -> Builder ()
f a
x Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
s Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [a] -> Builder ()
go [a]
xs'