1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
{-# 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.
--
-----------------------------------------------------------------------------
module Data.ByteString.Builder.Extra
(
-- * Execution strategies
toLazyByteStringWith
, 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
) where
import Data.ByteString.Builder.Internal
( Builder, toLazyByteStringWith
, AllocationStrategy, safeStrategy, untrimmedStrategy
, smallChunkSize, defaultChunkSize, flush
, byteStringCopy, byteStringInsert, byteStringThreshold
, lazyByteStringCopy, lazyByteStringInsert, lazyByteStringThreshold )
import qualified Data.ByteString.Builder.Internal as I
import qualified Data.ByteString.Builder.Prim as P
import qualified Data.ByteString.Internal as S
import Foreign
------------------------------------------------------------------------------
-- 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.
--
type BufferWriter = Ptr Word8 -> Int -> IO (Int, Next)
-- | After running a 'BufferWriter' action there are three possibilities for
-- what comes next:
--
data Next =
-- | 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 !Int BufferWriter
-- | 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 = run . I.runBuilder
where
bytesWritten startPtr endPtr = endPtr `minusPtr` startPtr
run :: I.BuildStep () -> BufferWriter
run step = \buf len ->
let doneH endPtr () =
let !wc = bytesWritten buf endPtr
next = Done
in return (wc, next)
bufferFullH endPtr minReq step' =
let !wc = bytesWritten buf endPtr
next = More minReq (run step')
in return (wc, next)
insertChunkH endPtr bs step' =
let !wc = bytesWritten buf endPtr
next = Chunk bs (run step')
in return (wc, next)
br = I.BufferRange buf (buf `plusPtr` len)
in I.fillWithBuildStep step doneH bufferFullH insertChunkH 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.
--
{-# INLINE intHost #-}
intHost :: Int -> Builder
intHost = P.primFixed P.intHost
-- | Encode a 'Int16' in native host order and host endianness.
{-# INLINE int16Host #-}
int16Host :: Int16 -> Builder
int16Host = P.primFixed P.int16Host
-- | Encode a 'Int32' in native host order and host endianness.
{-# INLINE int32Host #-}
int32Host :: Int32 -> Builder
int32Host = P.primFixed P.int32Host
-- | Encode a 'Int64' in native host order and host endianness.
{-# INLINE int64Host #-}
int64Host :: Int64 -> Builder
int64Host = P.primFixed 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.
--
{-# INLINE wordHost #-}
wordHost :: Word -> Builder
wordHost = P.primFixed P.wordHost
-- | Encode a 'Word16' in native host order and host endianness.
{-# INLINE word16Host #-}
word16Host :: Word16 -> Builder
word16Host = P.primFixed P.word16Host
-- | Encode a 'Word32' in native host order and host endianness.
{-# INLINE word32Host #-}
word32Host :: Word32 -> Builder
word32Host = P.primFixed P.word32Host
-- | Encode a 'Word64' in native host order and host endianness.
{-# INLINE word64Host #-}
word64Host :: Word64 -> Builder
word64Host = P.primFixed P.word64Host
-- | Encode a 'Float' in native host order. Values encoded this way are not
-- portable to different endian machines, without conversion.
{-# INLINE floatHost #-}
floatHost :: Float -> Builder
floatHost = P.primFixed P.floatHost
-- | Encode a 'Double' in native host order.
{-# INLINE doubleHost #-}
doubleHost :: Double -> Builder
doubleHost = P.primFixed P.doubleHost
|