{-# LANGUAGE Trustworthy #-}------------------------------------------------------------------------------- | Copyright : (c) 2010 Jasper Van der Jeugt-- (c) 2010-2011 Simon Meier-- License : BSD3-style (see LICENSE)---- Maintainer : Simon Meier <iridcode@gmail.com>-- Portability : GHC---- Extra functions for creating and executing 'Builder's. They are intended-- for application-specific fine-tuning the performance of 'Builder's.-------------------------------------------------------------------------------moduleData.ByteString.Builder.Extra(-- * Execution strategiestoLazyByteStringWith ,AllocationStrategy ,safeStrategy ,untrimmedStrategy ,smallChunkSize ,defaultChunkSize -- * Controlling chunk boundaries,byteStringCopy ,byteStringInsert ,byteStringThreshold ,lazyByteStringCopy ,lazyByteStringInsert ,lazyByteStringThreshold ,flush -- * Low level execution,BufferWriter ,Next (..),runBuilder -- * Host-specific binary encodings,intHost ,int16Host ,int32Host ,int64Host ,wordHost ,word16Host ,word32Host ,word64Host ,floatHost ,doubleHost )whereimportData.ByteString.Builder.Internal (Builder ,toLazyByteStringWith ,AllocationStrategy ,safeStrategy ,untrimmedStrategy ,smallChunkSize ,defaultChunkSize ,flush ,byteStringCopy ,byteStringInsert ,byteStringThreshold ,lazyByteStringCopy ,lazyByteStringInsert ,lazyByteStringThreshold )importqualifiedData.ByteString.Builder.Internal asIimportqualifiedData.ByteString.Builder.Prim asPimportqualifiedData.ByteString.Internal asSimportForeign-------------------------------------------------------------------------------- Builder execution public API-------------------------------------------------------------------------------- | A 'BufferWriter' represents the result of running a 'Builder'.-- It unfolds as a sequence of chunks of data. These chunks come in two forms:---- * an IO action for writing the Builder's data into a user-supplied memory-- buffer.---- * a pre-existing chunks of data represented by a 'S.StrictByteString'---- While this is rather low level, it provides you with full flexibility in-- how the data is written out.---- The 'BufferWriter' itself is an IO action: you supply it with a buffer-- (as a pointer and length) and it will write data into the buffer.-- It returns a number indicating how many bytes were actually written-- (which can be @0@). It also returns a 'Next' which describes what-- comes next.--typeBufferWriter =PtrWord8->Int->IO(Int,Next )-- | After running a 'BufferWriter' action there are three possibilities for-- what comes next:--dataNext =-- | This means we're all done. All the builder data has now been written.Done -- | This indicates that there may be more data to write. It-- gives you the next 'BufferWriter' action. You should call that action-- with an appropriate buffer. The int indicates the /minimum/ buffer size-- required by the next 'BufferWriter' action. That is, if you call the next-- action you /must/ supply it with a buffer length of at least this size.|More !IntBufferWriter -- | In addition to the data that has just been written into your buffer-- by the 'BufferWriter' action, it gives you a pre-existing chunk-- of data as a 'S.StrictByteString'. It also gives you the following 'BufferWriter'-- action. It is safe to run this following action using a buffer with as-- much free space as was left by the previous run action.|Chunk !S.StrictByteString BufferWriter -- | Turn a 'Builder' into its initial 'BufferWriter' action.--runBuilder ::Builder ->BufferWriter runBuilder :: Builder -> BufferWriter runBuilder =BuildStep () -> BufferWriter run (BuildStep () -> BufferWriter) -> (Builder -> BuildStep ()) -> Builder -> BufferWriter forall b c a. (b -> c) -> (a -> b) -> a -> c .Builder -> BuildStep () I.runBuilder wherebytesWritten :: Ptr b -> Ptr a -> Int bytesWritten Ptr b startPtr Ptr a endPtr =Ptr a endPtr Ptr a -> Ptr b -> Int forall a b. Ptr a -> Ptr b -> Int `minusPtr`Ptr b startPtr run ::I.BuildStep ()->BufferWriter run :: BuildStep () -> BufferWriter run BuildStep () step =\Ptr Word8 buf Int len ->letdoneH :: Ptr a -> () -> m (Int, Next) doneH Ptr a endPtr ()=let!wc :: Int wc =Ptr Word8 -> Ptr a -> Int forall a b. Ptr a -> Ptr b -> Int bytesWritten Ptr Word8 buf Ptr a endPtr next :: Next next =Next Done in(Int, Next) -> m (Int, Next) forall a. a -> m a forall (m :: * -> *) a. Monad m => a -> m a return(Int wc ,Next next )bufferFullH :: Ptr a -> Int -> BuildStep () -> m (Int, Next) bufferFullH Ptr a endPtr Int minReq BuildStep () step' =let!wc :: Int wc =Ptr Word8 -> Ptr a -> Int forall a b. Ptr a -> Ptr b -> Int bytesWritten Ptr Word8 buf Ptr a endPtr next :: Next next =Int -> BufferWriter -> Next More Int minReq (BuildStep () -> BufferWriter run BuildStep () step' )in(Int, Next) -> m (Int, Next) forall a. a -> m a forall (m :: * -> *) a. Monad m => a -> m a return(Int wc ,Next next )insertChunkH :: Ptr a -> StrictByteString -> BuildStep () -> m (Int, Next) insertChunkH Ptr a endPtr StrictByteString bs BuildStep () step' =let!wc :: Int wc =Ptr Word8 -> Ptr a -> Int forall a b. Ptr a -> Ptr b -> Int bytesWritten Ptr Word8 buf Ptr a endPtr next :: Next next =StrictByteString -> BufferWriter -> Next Chunk StrictByteString bs (BuildStep () -> BufferWriter run BuildStep () step' )in(Int, Next) -> m (Int, Next) forall a. a -> m a forall (m :: * -> *) a. Monad m => a -> m a return(Int wc ,Next next )br :: BufferRange br =Ptr Word8 -> Ptr Word8 -> BufferRange I.BufferRange Ptr Word8 buf (Ptr Word8 buf Ptr Word8 -> Int -> Ptr Word8 forall a b. Ptr a -> Int -> Ptr b `plusPtr`Int len )inBuildStep () -> (Ptr Word8 -> () -> IO (Int, Next)) -> (Ptr Word8 -> Int -> BuildStep () -> IO (Int, Next)) -> (Ptr Word8 -> StrictByteString -> BuildStep () -> IO (Int, Next)) -> BufferRange -> IO (Int, Next) forall a b. BuildStep a -> (Ptr Word8 -> a -> IO b) -> (Ptr Word8 -> Int -> BuildStep a -> IO b) -> (Ptr Word8 -> StrictByteString -> BuildStep a -> IO b) -> BufferRange -> IO b I.fillWithBuildStep BuildStep () step Ptr Word8 -> () -> IO (Int, Next) forall {m :: * -> *} {a}. Monad m => Ptr a -> () -> m (Int, Next) doneH Ptr Word8 -> Int -> BuildStep () -> IO (Int, Next) forall {m :: * -> *} {a}. Monad m => Ptr a -> Int -> BuildStep () -> m (Int, Next) bufferFullH Ptr Word8 -> StrictByteString -> BuildStep () -> IO (Int, Next) forall {m :: * -> *} {a}. Monad m => Ptr a -> StrictByteString -> BuildStep () -> m (Int, Next) insertChunkH BufferRange br -------------------------------------------------------------------------------- Host-specific encodings-------------------------------------------------------------------------------- | Encode a single native machine 'Int'. The 'Int' is encoded in host order,-- host endian form, for the machine you're on. On a 64 bit machine the 'Int'-- is an 8 byte value, on a 32 bit machine, 4 bytes. Values encoded this way-- are not portable to different endian or int sized machines, without-- conversion.--{-# INLINEintHost #-}intHost ::Int->Builder intHost :: Int -> Builder intHost =FixedPrim Int -> Int -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Int P.intHost -- | Encode a 'Int16' in native host order and host endianness.{-# INLINEint16Host #-}int16Host ::Int16->Builder int16Host :: Int16 -> Builder int16Host =FixedPrim Int16 -> Int16 -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Int16 P.int16Host -- | Encode a 'Int32' in native host order and host endianness.{-# INLINEint32Host #-}int32Host ::Int32->Builder int32Host :: Int32 -> Builder int32Host =FixedPrim Int32 -> Int32 -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Int32 P.int32Host -- | Encode a 'Int64' in native host order and host endianness.{-# INLINEint64Host #-}int64Host ::Int64->Builder int64Host :: Int64 -> Builder int64Host =FixedPrim Int64 -> Int64 -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Int64 P.int64Host -- | Encode a single native machine 'Word'. The 'Word' is encoded in host order,-- host endian form, for the machine you're on. On a 64 bit machine the 'Word'-- is an 8 byte value, on a 32 bit machine, 4 bytes. Values encoded this way-- are not portable to different endian or word sized machines, without-- conversion.--{-# INLINEwordHost #-}wordHost ::Word->Builder wordHost :: Word -> Builder wordHost =FixedPrim Word -> Word -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Word P.wordHost -- | Encode a 'Word16' in native host order and host endianness.{-# INLINEword16Host #-}word16Host ::Word16->Builder word16Host :: Word16 -> Builder word16Host =FixedPrim Word16 -> Word16 -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Word16 P.word16Host -- | Encode a 'Word32' in native host order and host endianness.{-# INLINEword32Host #-}word32Host ::Word32->Builder word32Host :: Word32 -> Builder word32Host =FixedPrim Word32 -> Word32 -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Word32 P.word32Host -- | Encode a 'Word64' in native host order and host endianness.{-# INLINEword64Host #-}word64Host ::Word64->Builder word64Host :: Word64 -> Builder word64Host =FixedPrim Word64 -> Word64 -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Word64 P.word64Host -- | Encode a 'Float' in native host order. Values encoded this way are not-- portable to different endian machines, without conversion.{-# INLINEfloatHost #-}floatHost ::Float->Builder floatHost :: Float -> Builder floatHost =FixedPrim Float -> Float -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Float P.floatHost -- | Encode a 'Double' in native host order.{-# INLINEdoubleHost #-}doubleHost ::Double->Builder doubleHost :: Double -> Builder doubleHost =FixedPrim Double -> Double -> Builder forall a. FixedPrim a -> a -> Builder P.primFixed FixedPrim Double P.doubleHost