← The Dry Stack

Zao

Zeroes And Ones — blit-fast serializer with tiered codegen; the memcpy-tier runs at the speed of memory itself.

What it is. The piece that turns your data into bytes and back. For simple types it does no work at all — it just copies memory, so the fast path runs at the speed of memcpy itself.

The problem it kills. Serializers like Protobuf or JSON walk every field, allocate, and encode — real CPU on data that's about to be thrown away. Where the layout already matches, Zao charges nothing for it.

For example. In the F1 replay, each telemetry sample carries a packed blob alongside its numeric columns — Zao is what packs and unpacks those at line rate. The throughput run below is real, captured live.

See it move a race ⟶
vs. the field · BenchmarkDotNet · .NET 10 · Ryzen 9 7950X3D

Encode, measured fairly. Zao writes into a caller-owned buffer — zero allocation. MemoryPack and MessagePack get a reused buffer too, so nobody is charged for a throwaway array. Only MemoryPack stays in the same order of magnitude — and it still trails by 1.4–3.6×. MessagePack is 4–60× back; Protobuf and JSON, one to three orders. Lower is better. Zao, MemoryPack and MessagePack here allocate zero bytes; Protobuf and JSON have no zero-alloc path and allocate on every call.

Message Zao
WriteTo
MemoryPack
reused buf
MessagePack
reused buf
Protobuf
Serialize→[]
JSON
Serialize→[]
PlayerMoved · 16 B blit0.87 ns3.11 ns42 ns141 ns305 ns
SpawnEntity · + string12.5 ns26 ns58 ns143 ns282 ns
Snapshot · 32 entities10.8 ns36.7 ns491 ns1,997 ns8,265 ns
Snapshot · 1024 entities238 ns335 ns14,249 ns63,875 ns254,741 ns
Inventory · 128-key map1.65 µs3.18 µs2.74 µs8.20 µs3.49 µs

Where Zao doesn't win — plainly: it isn't the smallest on the wire; MessagePack's varint packing beats it on small, integer-heavy messages. On decode it's fastest across the board and allocates less for value-type messages (72 B vs 128 B on SpawnEntity), but for collection-heavy messages everyone must build the same array / map / strings, so memory ties. The honest headline is the table above: the fastest zero-allocation encode in .NET.

Full benchmark summary · samples/Zao.Benchmarks · raw output ⟶

The table above reads from the rows below: Zao's *_Encode and the competitors' *_EncodeReuse. Every figure is BenchmarkDotNet output, unedited.

loading…