Skip to main content

Module schema

Module schema 

Source
Expand description

DynamicSchema — declarative description of a postcard-encoded payload’s shape.

Postcard is not self-describing: a postcard payload is a flat byte stream whose meaning depends entirely on the type that produced it. To migrate a v1 document into a v2 type at decode time the codec needs some description of the v1 wire shape; DynamicSchema is that description.

A DynamicSchema is pure data — a tree of enum variants, no generics, no lifetimes beyond 'static, no allocations beyond the Vec/Box literal data carries. The schema describes the field order + per-field type of a postcard payload; the walker Dynamic::from_postcard_bytes consumes both schema and bytes and produces a structured Dynamic view.

§Wire-format dependency

DynamicSchema only describes postcard payloads. The mapping of schema variants → postcard byte-stream operations is the only postcard-specific knowledge in obj’s migration path:

Schema variantPostcard wire shape
Null(zero bytes — () / unit struct)
Bool1 byte (0 = false, 1 = true)
U64unsigned LEB128 varint
I64zigzag-encoded varint
F648 little-endian bytes
Stringvarint length + UTF-8 bytes
Bytesvarint length + raw bytes
Seq(elem)varint length, then N elements of the inner schema
Map(fields)each (name, schema) decoded in order — no field names
Enum(variants)varint u32 discriminant, then the matched variant’s payload

Postcard treats a Rust struct as a field-ordered tuple with no names, so Map in this schema does NOT correspond to postcard’s serialize_map; it corresponds to a sequence of per-field bytes. Field names are an obj-side convention used to tag fields in the resulting Dynamic for get / set / remove addressing.

For enums, postcard writes a varint u32 discriminant followed by the matched variant’s payload. Unit variants carry only the discriminant; newtype / tuple / struct variants follow with the inner type’s field-ordered bytes (no length prefix — the schema names every field for Dynamic::get addressing the same way Map does). Tuple variants are represented by Map with synthetic numeric field names ("0", "1", …) — there is no Tuple schema variant.

§Power-of-ten posture

  • Rule 1. The walker that consumes a DynamicSchema uses an explicit stack (Vec<Frame>), not Rust-language recursion. Tree depth is bounded by MAX_SCHEMA_DEPTH.
  • Rule 2. Every Seq / Map decode reads its length as a varint and bounds the per-frame iteration by that length; pathologically large lengths are rejected before any allocation.
  • Rule 5. Schema construction is pure-data — runtime correctness checks live in the walker, not in DynamicSchema itself.
  • Rule 7. Every fallible walker step propagates via ?; no unwrap / expect on byte-stream input.

Structs§

EnumVariantSchema
One variant of a DynamicSchema::Enum description.

Enums§

DynamicSchema
Describes the byte-stream shape of a postcard-encoded payload at one version. See module docs for the variant ↔ wire-format mapping.

Constants§

MAX_SCHEMA_DEPTH
Maximum nesting depth of a DynamicSchema tree that the walker will traverse. Exceeding this bound returns Error::SchemaDepthExceeded.

Traits§

Schema
A type whose postcard wire shape is describable by a DynamicSchema.