{-# LANGUAGE BangPatterns #-} {-# LANGUAGE PatternSynonyms #-} -- | @Data.Builder.Bytes@ specialized to @Bytes@. module Data.Builder.Catenable.Bytes ( -- * Type Builder (..) -- * Convenient infix operators , pattern (:<) , pattern (:>) -- * Run , run -- * Properties , length -- * Create , bytes , byteArray -- * Mimic data constructors , cons , snoc , append , empty ) where import Prelude hiding (length) import Control.Monad.ST (ST, runST) import Data.Bytes (Bytes) import Data.Bytes.Chunks (Chunks (ChunksNil)) import Data.Primitive (ByteArray) import qualified Data.Bytes as Bytes import qualified Data.Bytes.Builder as BB import qualified Data.Bytes.Builder.Unsafe as BBU infixr 5 :< infixl 5 :> data Builder = Empty | Cons {-# UNPACK #-} !Bytes !Builder | Snoc !Builder {-# UNPACK #-} !Bytes | Append !Builder !Builder instance Monoid Builder where {-# INLINE mempty #-} mempty = Empty instance Semigroup Builder where {-# INLINE (<>) #-} (<>) = Append pattern (:<) :: Bytes -> Builder -> Builder pattern (:<) x y = Cons x y pattern (:>) :: Builder -> Bytes -> Builder pattern (:>) x y = Snoc x y -- | Number of bytes in the sequence. length :: Builder -> Int length b0 = case b0 of Empty -> 0 Cons x b1 -> Bytes.length x + length b1 Snoc b1 x -> Bytes.length x + length b1 Append x y -> length x + length y run :: Builder -> Chunks {-# NOINLINE run #-} run b = runST $ do bldr0 <- BBU.newBuilderState 128 bldr1 <- pushCatenable bldr0 b BBU.reverseCommitsOntoChunks ChunksNil (BBU.closeBuilderState bldr1) pushCatenable :: BBU.BuilderState s -> Builder -> ST s (BBU.BuilderState s) pushCatenable !bldr0 b = case b of Empty -> pure bldr0 Cons x b1 -> do bldr1 <- BBU.pasteST (BB.bytes x) bldr0 pushCatenable bldr1 b1 Snoc b1 x -> do bldr1 <- pushCatenable bldr0 b1 BBU.pasteST (BB.bytes x) bldr1 Append x y -> do bldr1 <- pushCatenable bldr0 x pushCatenable bldr1 y bytes :: Bytes -> Builder bytes !b = Cons b Empty byteArray :: ByteArray -> Builder byteArray !b = Cons (Bytes.fromByteArray b) Empty snoc :: Builder -> Bytes -> Builder {-# INLINE snoc #-} snoc = Snoc cons :: Bytes -> Builder -> Builder {-# INLINE cons #-} cons = Cons empty :: Builder {-# INLINE empty #-} empty = Empty append :: Builder -> Builder -> Builder {-# INLINE append #-} append = Append