A function that fills a BufferRange, calls the continuation with
the updated BufferRange and its computed value once its done, and
signals its caller how to proceed using done, bufferFull, or
insertChunk signals.
This function must be referentially transparent; i.e., calling it
multiple times with equally sized BufferRanges must result in the
same sequence of bytes being written and the same value being
computed. If you need mutable state, then you must allocate it anew
upon each call of this function. Moreover, this function must call
the continuation once its done. Otherwise, monadic sequencing of
Puts does not work. Finally, this function must write to all bytes
that it claims it has written. Otherwise, the resulting Put is
not guaranteed to be referentially transparent and sensitive data
might leak.
Construct a Put action. In contrast to BuildSteps, Puts are
referentially transparent in the sense that sequencing the same Put
multiple times yields every time the same value with the same side-effect.
A Put action denotes a computation of a value that writes a stream of
bytes as a side-effect. Puts are strict in their side-effect; i.e., the
stream of bytes will always be written before the computed value is
returned.
Puts are a generalization of Builders. The typical use case is the
implementation of an encoding that might fail (e.g., an interface to the
zlib
compression library or the conversion from Base64 encoded data to
8-bit data). For a Builder, the only way to handle and report such a
failure is ignore it or call error. In contrast, Put actions are
expressive enough to allow reporting and handling such a failure in a pure
fashion.
Put () actions are isomorphic to Builders. The functions putBuilder
and fromPut convert between these two types. Where possible, you should
use Builders, as sequencing them is slightly cheaper than sequencing
Puts because they do not carry around a computed value.
Instances3Monad, Functor, Applicative
MonadPutDefined in bytestring-0.12.2.0 · Data.ByteString.Builder.Internal
FunctorPutDefined in bytestring-0.12.2.0 · Data.ByteString.Builder.Internal
ApplicativePutDefined in bytestring-0.12.2.0 · Data.ByteString.Builder.Internal
Create a Builder denoting the same sequence of bytes as a
StrictByteString.
The Builder inserts large StrictByteStrings directly, but copies small ones
to ensure that the generated chunks are large on average.
Run a Put action redirecting the produced output to a Handle.
The output is buffered using the Handles associated buffer. If this
buffer is too small to execute one step of the Put action, then
it is replaced with a large enough buffer.
Create a Builder denoting the same sequence of bytes as a lazy
LazyByteString.
The Builder inserts large chunks of the LazyByteString directly,
but copies small ones to ensure that the generated chunks are large on
average.
Execute a Builder and return the generated chunks as a LazyByteString.
The work is performed lazy, i.e., only when a chunk of the LazyByteString
is forced.
BuildStep to run on the next BufferRange. This BuildStep
may assume that it is called with a BufferRange of at least the
required minimal size; i.e., the caller of this BuildStep must
guarantee this.
This function must be referentially transparent; i.e., calling it
multiple times with equally sized BufferRanges must result in the
same sequence of bytes being written. If you need mutable state,
then you must allocate it anew upon each call of this function.
Moreover, this function must call the continuation once its done.
Otherwise, concatenation of Builders does not work. Finally, this
function must write to all bytes that it claims it has written.
Otherwise, the resulting Builder is not guaranteed to be
referentially transparent and sensitive data might leak.
Use this function to create Builders from smallish (<= 4kb)
StrictByteStrings or if you need to guarantee that the StrictByteString is not
shared with the chunks generated by the Builder.
This implies flushing the output buffer, even if it contains just
a single byte. You should therefore use byteStringInsert only for large
(> 8kb) StrictByteStrings. Otherwise, the generated chunks are too
fragmented to be processed efficiently afterwards.
Construct a Builder that copies the StrictByteStrings, if it is
smaller than the treshold, and inserts it directly otherwise.
For example, byteStringThreshold 1024 copies StrictByteStrings whose size
is less or equal to 1kb, and inserts them directly otherwise. This implies
that the average chunk-size of the generated LazyByteString may be as
low as 513 bytes, as there could always be just a single byte between the
directly inserted 1025 byte, StrictByteStrings.
If Nothing is given, then a new first buffer should be allocated.
If Just (oldBuf, minSize) is given, then a buffer with minimal
size minSize must be returned. The strategy may reuse oldBuf only if
oldBuf is large enough and the consumer can guarantee that this will
not result in a violation of referential transparency.
Warning: for multithreaded programs, it is generally unsafe to reuse
buffers when using the consumers of Builder in this package. For
example, if toLazyByteStringWith is called with an
AllocationStrategy that reuses buffers, evaluating the result by
multiple threads simultaneously may lead to corrupted output.
type DecodingState = ...
decodeBase64 :: StrictByteString -> DecodingState -> Put (Maybe DecodingState)
decodeBase64 = ...
The above function takes a StrictByteString supposed to represent
Base64 encoded data and the current decoding state.
It writes the decoded bytes as the side-effect of the Put and returns the
new decoding state, if the decoding of all data in the StrictByteString was
successful. The checking if the StrictByteString represents Base64
encoded data and the actual decoding are fused. This makes the common case,
where all data represents Base64 encoded data, more efficient. It also
implies that all data must be decoded before the final decoding
state can be returned. Puts are intended for implementing such fused
checking and decoding/encoding, which is reflected in their strictness
properties.
Use this strategy for generating LazyByteStrings whose chunks are
likely to survive one garbage collection. This strategy trims buffers
that are filled less than half in order to avoid spilling too much memory.
Heavy inlining. Execute a Builder with custom execution parameters.
This function is inlined despite its heavy code-size to allow fusing with
the allocation strategy. For example, the default Builder execution
function toLazyByteString is defined as follows.
In most cases, the parameters used by toLazyByteString give good
performance. A sub-performing case of toLazyByteString is executing short
(<128 bytes) Builders. In this case, the allocation overhead for the first
4kb buffer and the trimming cost dominate the cost of executing the
Builder. You can avoid this problem using
This reduces the allocation and trimming overhead, as all generated
LazyByteStrings fit into the first buffer and there is no trimming
required, if more than 64 bytes and less than 128 bytes are written.
Use this strategy for generating LazyByteStrings whose chunks are
discarded right after they are generated. For example, if you just generate
them to write them to a network socket.
A stream of chunks that are constructed in the IO monad.
This datatype serves as the common interface for the buffer-by-buffer
execution of a BuildStep by buildStepToCIOS. Typical users of this
interface are ciosToLazyByteString or iteratee-style libraries like
enumerator.