bytezap-1.3.0: Bytestring builder with zero intermediate allocation
Safe HaskellSafe-Inferred
LanguageGHC2021

Bytezap.Struct

Description

Struct serializer: serialize fields of known length.

In Haskell-ish terminology, one may consider a C struct to be a product type where each field is of known length. Thus, fields may be accessed by a fixed offset from the struct start. This is convenient for efficient access, since those offsets may be turned into immediates on a register in a MOV instruction.

Given a struct-like type, we don't need to track "bytes serialized so far" like the general case. We can serialize fields in any order we like, since we know where they will sit in the resulting bytestring.

This module provides a serializer specifically for these struct-like types. Maybe GHC can write more efficient code for these super-simple types! I have no idea. So I'm trying it, and will compare performance.

Notably, this serializer is much less flexible. No monoid! I don't really expect anyone to write manual stuff with it-- you should just use the generics. That reminds me, TODO could easily provide some TH too, and again compare.

Synopsis

Documentation

type Poke# s = Addr# -> Int# -> State# s -> State# s Source #

A struct poker: base address (constant), byte offset, state token.

We could combine base address and byte offset, but we're aiming for code that stores the address in a register and uses immediates to access fields (like a good C compiler will do for its structs). So by keeping them separate, I'm hoping that we can nudge GHC towards such behaviour.

newtype Poke s Source #

Poke newtype wrapper.

Constructors

Poke 

Fields

unsafeRunPokeBS :: Int -> Poke RealWorld -> ByteString Source #

Execute a Poke at a fresh ByteString of the given length.

unsafeRunPoke :: MonadPrim s m => Poke s -> Ptr Word8 -> m () Source #

Execute a Poke at a pointer. Returns the number of bytes written.

The pointer must be a mutable buffer with enough space to hold the poke. Absolutely none of this is checked. Use with caution. Sensible uses:

  • implementing pokes to ByteStrings and the like
  • executing known-length (!!) pokes to known-length (!!) buffers e.g. together with allocaBytes

prim :: forall a s. Prim' a => a -> Poke s Source #

Poke a type via its Prim' instance.

emptyPoke :: Poke s Source #

The empty poke. Provided here as we can't provide it via empty.

sequencePokes :: Poke s -> Int -> Poke s -> Poke s Source #

Sequence two Pokes. We only require the length of the left poke.

replicateByte :: Int -> Word8 -> Poke RealWorld Source #

essentially memset