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 variant | Postcard wire shape |
|---|---|
Null | (zero bytes — () / unit struct) |
Bool | 1 byte (0 = false, 1 = true) |
U64 | unsigned LEB128 varint |
I64 | zigzag-encoded varint |
F64 | 8 little-endian bytes |
String | varint length + UTF-8 bytes |
Bytes | varint 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
DynamicSchemauses an explicit stack (Vec<Frame>), not Rust-language recursion. Tree depth is bounded byMAX_SCHEMA_DEPTH. - Rule 2. Every
Seq/Mapdecode 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
DynamicSchemaitself. - Rule 7. Every fallible walker step propagates via
?; nounwrap/expecton byte-stream input.
Structs§
- Enum
Variant Schema - One variant of a
DynamicSchema::Enumdescription.
Enums§
- Dynamic
Schema - 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
DynamicSchematree that the walker will traverse. Exceeding this bound returnsError::SchemaDepthExceeded.
Traits§
- Schema
- A type whose postcard wire shape is describable by a
DynamicSchema.