Table of Contents

Prefixing buffer writer

The PrefixingBufferWriter<T> type implements and wraps an IBufferWriter<T>. It reserves space in the wrapped IBufferWriter<T> for a fixed size header to be written after some later buffer has been written. This is particularly useful for length-prefixed lists where the length of the list is not known until it is written out.

Sample usage

Wrap the IBufferWriter<T> you have with this class, and specify the length of the header to reserve space for. Write the payload, and then complete the operation by providing the content for the header.

void WriteList<T>(IBufferWriter<byte> writer, IEnumerable<T> items)
{
    var prefixingWriter = new PrefixingBufferWriter<byte>(writer, sizeof(int));
    Serialize(prefixingWriter, items);

    // Write out the header indicating the length of the serialized data just written.
    // We're writing *bytes* here, so Length returns the length of the data in bytes.
    // (in a networking app, think about big vs. little endian too).
    BitConverter.GetBytes(prefixingWriter.Length).AsSpan().CopyTo(prefixingWriter.Prefix);

    // Commit the whole result to the underlying writer.
    prefixingWriter.Commit();
}

void Serialize<T>(IBufferWriter<byte> writer, T item)
{
    // How to serialize an item is out of scope of this doc.
    // You're probably using a serialization library for this part.
}

Performance considerations

Performance in the worst case is an additional copy of some of the written buffer. Since IBufferWriter<T> does not allow writing a buffer, advancing, then going back to edit the previously advanced buffer, this wrapper does not call Advance on the underlying writer until the header is known. Given an adequately large initial buffer size, all copying is avoided. If the payload exceeds the estimated max size, then additional buffers will be allocated internally to store the data until the header is known, after which the additional buffers are copied into the underlying writer's buffers and Advance is called.

Reuse

The same PrefixingBufferWriter<T> instance can be used to write any number of length-prefixed buffers. After calling Commit simply use it again.