Module serializer

Source
Expand description

Tagged-map msgpack serializer that wraps [rmp_serde::Serializer].

Most of serde::Serializer’s methods are forwarded to the inner rmp_serde serializer unchanged — we only intercept the structurally significant calls (serialize_struct, the variant methods, etc.) and re-emit them as integer-keyed msgpack maps using the TagRegistry.

The public entry point is msgpack_tagged_serialize, which builds the registry up front via T::register_into and runs the value through the wrapper. The wrapper in turn writes to a Vec<u8> we hand back to the caller.

Every aggregate shape is intercepted: named structs, multi-element tuple structs, sequences, fixed-length tuples, free-form maps, and all four variant kinds (unit / newtype / tuple / struct). Primitives, top-level newtype structs, and Option forward through to inner — recursing into nested values via this same wrapper so any tagged value reachable from the root keeps the int-keyed-map treatment.

§Known gaps vs. the design doc / macro syntax

The wrapper isn’t final — the bits below are accepted by #[derive(MsgpackTagged)] today but aren’t reflected in the wire bytes we produce yet.

  • Tag-ascending wire order. The design promises field/element entries on the wire in tag-ascending order so two semantically-equal values encode byte-identically regardless of source-declaration order. We currently emit in serde’s call-order = source-declaration order. Tightening this requires buffering field bytes before writing.
  • Encoding strategies. Only the Tagged strategy (int-keyed map) is implemented. Per-type strategy overrides — Array (positional msgpack array, smallest wire) and Named (rmp_serde default, string-keyed map) — are deferred follow-ups.
  • assert_eq! on len vs product.fields.len() — already tightened, but only inside the four product-shaped methods. New shapes that join the family should add the same assert.

Structs§

Serializer
Tagged-map msgpack serializer.
TaggedSerializeProduct
Adapter for product shapes — both named structs and multi-element tuple structs go through here. The two trait impls below differ only in how they resolve a serde call to a wire tag: named-struct calls carry a field-name string, tuple-struct calls carry an implicit position counter. The map header is already written in the corresponding serialize_* method before this adapter is constructed; from there each serialize_field call appends a (tag, value) pair to the writer through the parent Serializer, so any nested tagged value in value recurses through the wrapper instead of falling through to rmp_serde’s default positional-array struct encoding.
TaggedSerializeViaParent
Stateless pass-through adapter shared by every shape whose only job is to route element/key/value calls back through the parent Serializer. The msgpack header (array length or map length) is written upfront in the corresponding serialize_* method before the adapter is constructed; from there each entry is just one or two more values appended to the writer through the wrapper, so any tagged value nested inside still gets the int-keyed-map treatment.

Functions§

assert_field_count_matches 🔒
Assert that serde’s reported field count matches the registered Product’s — both should drop the same skipped fields, so they should always agree. A mismatch is a real misconfiguration: the most common cause is a PhantomData<T> field that’s missing #[serde(skip)], which would otherwise fail later with a confusing “field not found in registered Product” error from a tag lookup. The assert surfaces it earlier, with a more actionable message.
begin_product_payload 🔒
Decide whether to buffer + flush in tag-ascending order, write the outer header upfront in the direct case, and return the configured adapter. Shared by Serializer::begin_product (top-level) and Serializer::begin_variant_payload (enum payload).
downgrade_array_if_unsafe 🔒
Auto-downgrade ArrayTagged for products where the positional shape can’t safely round-trip the type’s own writes.
make_inner_rmp_serializer 🔒
Build the inner rmp_serde::Serializer for primitive / forwarded calls. Single construction point so every spawn site (Serializer::new, Serializer::sub_serializer_into) stays in lockstep.
msgpack_tagged_serialize
Build the tag registry from T::register_into, then serialize value through a Serializer into a freshly-allocated Vec<u8>. Uses the default EncodingStrategy::Tagged for all types. For strategy customization, build the registry and serializer directly and use the builder methods.
write_array_header 🔒
Write a msgpack array header (fixarray / array16 / array32 depending on len) directly to the underlying writer. Used by sequences and tuples.
write_map_header 🔒
Write a msgpack map header (fixmap / map16 / map32 depending on len) directly to the underlying writer. Used by structs, maps, and the variant shapes once those land.
write_strategy_header 🔒
Write the outer Product header in the shape required by strategy: Tagged → int-keyed fixmap, Array → positional fixarray. Used by both top-level struct paths and variant-payload paths.

Type Aliases§

RmpError 🔒
rmp_serde’s error type, re-exported for our serde::Serializer impl.