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

Bytezap.PokeCPS

Description

Low-level bytestring builder using continuation parsing.

bytezap's builder is highly performant. However, one thing it can't do is fail. We have no way to flag an error. If you force it, you will either

  • write an initial assert, followed by an unsafe builder that relies on it, or
  • build a builder as we assert, then execute it once we're ready

The former is inefficient in situations where the check scales similarly with the build (e.g. both must iterate over the input). And the latter is very silly since your builder will be allocating all over.

A naive failable builder might use Either e Int to flag errors. After executing, we check the result: if Right, we resize to the given actual length; if Left, we discard the buffer with the given error. This is fine... but it's an extra allocation, and limits us to Either. A shame.

Instead, we design a builder that takes a finalizer continuation Int# -> ByteString, which is passed the final offset. The builder calls this as it finishes, wrapping it as needed (or leaving as ByteString for a non-failable builder). The runner is expected to pass a continuation to perform any buffer reallocation necessary (if the actual length was less than the max length), and return a ByteString, possibly wrapped in e.g. Right.

This is much harder to use than the regular builder, and they can't be combined (the regular builder permits sequencing, which this can't support). But it fills a gap!

Unlike the regular builder we stick with IO, because the continuations get weird otherwise.

Synopsis

Documentation

type PokeCPS# r = Addr# -> Int# -> (Int# -> IO ByteString) -> IO r Source #

newtype PokeCPS r Source #

PokeCPS# newtype wrapper.

Does not permit a Semigroup instance because pokes do not return offset information.

Constructors

PokeCPS 

Fields

full :: ByteArray -> Ptr Word8 -> (Int -> IO r) -> (Word8 -> IO r) -> (Word8 -> IO r) -> Int -> Int -> Int -> IO r Source #

withHexNibbles :: (Word8 -> r) -> Word8 -> Word8 -> (Word8 -> r) -> r Source #

withByteAsHexDigit :: Word8 -> (Word8 -> r) -> (Word8 -> r) -> r Source #