Skip to content

Repository files navigation

ZeroSerializer

Zero-copy, Zero-allocation, Deserialize-on-Read

NuGet🇺🇸🇯🇵

ZeroSerializer is a C# source generator for reading serialized data directly from an existing byte[].

Why ZeroSerializer?

Receiving data over a network, reading a file, or calling another API often leaves you with an unavoidable byte[] allocation. ZeroSerializer generates a read-only view like ReadOnlySpan<T> or ReadOnlyMemory<T> that reuses that allocation and provides strongly typed values and slices without creating another buffer or a deserialized object graph. Each property is read only when accessed, and strings and arrays remain borrowed from the original memory.

Usage

// Some APIs require data to be received into a byte array.byte[]receivedBuffer=ReceivePacket();// Like ReadOnlySpan<T> or ReadOnlyMemory<T>,// a view provides strongly typed access over existing memory without owning it.varpacketView=newPacketView(receivedBuffer.AsMemory());// Each property is decoded directly from the original buffer only when accessed.intid=packetView.Id;ReadOnlySpan<char>name=packetView.Name;ReadOnlySpan<int>values=packetView.Values;// Adding attribute to generate readonly struct 'PacketView'.[ZeroSerializer]publicclassPacket{publicintId{get;}publicstringName{get;}publicint[]Values{get;}}

View construction does not read every property. Values are decoded directly from the original memory only on access.

The complete serialized region is also available through implicit conversion:

ReadOnlySpan<byte>serializedData=packetView;ReadOnlyMemory<byte>retainedData=packetView;

Supported values

  • Primitives and enums
  • Nullable values
  • string stored as UTF-16 (UTF-8 can be stored as byte[] by hand)
  • Nested [ZeroSerializer] types
  • Blittable structs with [StructLayout(LayoutKind.Sequential, Pack = 1)]
  • One-dimensional arrays of blittable values or structs

Serialized layout

Non-Blittable types store one relative offset per property, followed by payloads in declaration order:

[ int property offsets... ][ property payloads... ]

Offsets are relative to the start of the containing type. An offset of 0 represents null. Strings and arrays store their byte length before their data:

[ int byte length ][ data... ]

Blittable structs are stored directly as raw struct bytes without an offset table.

Notes

  • Keep the original memory alive and unchanged while its View is in use. This is the same rule as for Span<T> and Memory<T>.
  • RequiredByteLength is the exact size (including the offset table) unless it is negative. A negative value indicates that the type contains variable-length data, such as strings or arrays. Passing the exact serialized region is recommended, but View access only requires the correct starting position.
  • Validate integrity or authenticity before creating a View when required.
  • The wire format requires a little-endian runtime.
  • View structs expose a compile-time constant IsBlittable, indicating whether the underlying serialized type is a blittable struct.
  • You can use .AsMemory() extension method (returns ReadOnlyMemory<byte>) or .Materialize() extension method (for views of blittable structs to convert them back to the original struct).
  • Nested classes and structs must be marked with [ZeroSerializer]; otherwise the generator reports an unsupported field diagnostic.

About

Zero-copy, zero-allocation and deserialize-on-read binary serializer for C# / .NET providing strongly typed, Span-like view over existing byte array.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages