Skip to content

Zero-copy deserialization

Level: 301 · deep dive

One line: A deserialized struct can borrow its strings from the input buffer instead of allocating them — &'a str fields and #[serde(borrow)] — which costs a lifetime on the type and fails outright on a JSON string that contains an escape.

Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.

What it has to cover

  • struct Row<'a> { name: &'a str } with serde_json::from_str: the allocation count with and without borrowing, measured with a counting allocator (see the global allocator)
  • The failure: a string with \n or \" in it cannot be a slice of the input — the error text serde_json gives, and Cow<'a, str> with #[serde(borrow)] as the fix that borrows when it can
  • What the lifetime does to the caller: the input buffer must outlive every row — the lifetimes at the call site story
  • Binary formats built for this: rkyv (archived types read in place), zerocopy and bytemuck (casting byte slices to #[repr(C)] structs), and what each checks — alignment, validity, endianness
  • When it is not worth it: small inputs, data that outlives the buffer, and the complexity a lifetime parameter adds to every signature

The trap it exists for

Switching every String field to &'a str and meeting the escape error in production, on the first input with a quote in it. Borrowing is conditional on the bytes, which is exactly what Cow models.

Where this sits

Deriving Serialize and Deserialize is the owned, allocate-everything version. Cow is the type that makes borrowing conditional. String slices is what zero-copy means for text.

See also

If you are coming from another language

  • C. Casting a received buffer to a struct pointer is C's default, and the C library's a record on the wire ↗ page shows what padding and byte order do to it. zerocopy and bytemuck exist to make that cast checked.
  • Python. memoryview and struct.unpack_from read in place without copying; the difference is that nothing stops the view outliving a buffer you meant to reuse.
  • Java. ByteBuffer views and flyweight decoders (SBE, FlatBuffers) are the same idea, with the garbage collector keeping the buffer alive instead of a lifetime proving it.

Po polsku

Deserializacja bez kopiowania (zero-copy) oznacza, że pola tekstowe struktury pożyczają fragmenty bufora wejściowego zamiast alokować własne Stringi. Ceną jest parametr czasu życia na typie, a pułapką — napis JSON zawierający sekwencję ucieczki, którego nie da się wyciąć z wejścia; stąd Cow<'a, str> z #[serde(borrow)].

Szukaj po polsku: deserializacja bez kopiowania · serde borrow cow str · rkyv zero copy · rust zerocopy bytemuck