- Warning:* this module is internal. If you find that you need it
then please contact the maintainers and explain what you are trying to
do and discuss what you would need in the public API. It is important
that you do this as the module may not be exposed at all in future
releases.
Core types and functions for the
Builder monoid and its
generalization, the
Put monad.
The design of the
Builder monoid is optimized such that
- buffers of arbitrary size can be filled as efficiently as possible
and
- sequencing of Builders is as cheap as possible.
We achieve (1) by completely handing over control over writing to the
buffer to the
BuildStep implementing the
Builder. This
BuildStep is just told the start and the end of the buffer
(represented as a
BufferRange). Then, the
BuildStep can
write to as big a prefix of this
BufferRange in any way it
desires. If the
BuildStep is done, the
BufferRange is
full, or a long sequence of bytes should be inserted directly, then
the
BuildStep signals this to its caller using a
BuildSignal.
We achieve (2) by requiring that every
Builder is implemented
by a
BuildStep that takes a continuation
BuildStep,
which it calls with the updated
BufferRange after it is done.
Therefore, only two pointers have to be passed in a function call to
implement concatenation of
Builders. Moreover, many
Builders are completely inlined, which enables the compiler to
sequence them without a function call and with no boxing at all.
This design gives the implementation of a
Builder full access
to the
IO monad. Therefore, utmost care has to be taken to not
overwrite anything outside the given
BufferRanges. Moreover,
further care has to be taken to ensure that
Builders and
Puts are referentially transparent. See the comments of the
builder and
put functions for further information. Note
that there are
no safety belts at all, when implementing a
Builder using an
IO action: you are writing code that
might enable the next buffer-overflow attack on a Haskell server!