Struct Serializer

Source
pub struct Serializer<'a, W: Write> {
    inner: Serializer<W>,
    registry: &'a TagRegistry,
    default_strategy: EncodingStrategy,
    overrides: HashMap<&'static str, EncodingStrategy>,
}
Expand description

Tagged-map msgpack serializer.

Borrows a caller-owned TagRegistry and carries per-encode-session policy (default strategy + per-type overrides). The registry stays pure type metadata — strategy state lives only on the serializer. Typical usage:

let registry = TagRegistry::from_type::<Program<F>>();
let mut buf = Vec::new();
let mut s = msgpack_tagged::Serializer::new(&mut buf, &registry)
    .with_default_strategy(EncodingStrategy::Array)
    .with_strategy::<Program<F>>(EncodingStrategy::Tagged)
    .with_strategy::<Circuit<F>>(EncodingStrategy::Tagged);
program.serialize(&mut s)?;

new defaults the strategy to EncodingStrategy::Tagged (the most evolution-friendly shape); with_default_strategy swaps it, and with_strategy::<U> overrides for individual types (panicking on a registry miss). Policy sites that target types by string name — possibly without knowing whether the type is reachable — use with_strategy_for_name instead.

Fields§

§inner: Serializer<W>§registry: &'a TagRegistry§default_strategy: EncodingStrategy§overrides: HashMap<&'static str, EncodingStrategy>

Per-type strategy overrides keyed by serde name (the name #[serde(rename = "...")] resolves to, or the bare type ident when no rename is set). Keying by name — not std::any::TypeId — lets with_strategy::<Foo<F>> apply uniformly across field flavors (Foo<FieldElement> and Foo<OtherF> share the name “Foo”) and across shadow DTOs (a public Circuit<F> with #[tagged(via(CircuitWire<F>))] reaches the same “Circuit” override that CircuitWire registers under via #[serde(rename)]). See type_name_basename for the derivation rule.

Implementations§

Source§

impl<'a, W: Write> Serializer<'a, W>

Source

pub fn new(writer: W, registry: &'a TagRegistry) -> Self

Construct a serializer over writer borrowing the caller-built registry. The default per-type strategy is EncodingStrategy::Tagged.

Build the registry up front via TagRegistry::from_type::<T>() for the top-level type being serialized — the registration walk seeds every nested tagged type.

Source

pub fn with_default_strategy(self, strategy: EncodingStrategy) -> Self

Change the default strategy applied to types without a per-type override.

Source

pub fn with_strategy<T: MsgpackTagged>(self, strategy: EncodingStrategy) -> Self

Set the encoding strategy for a specific type T. Overrides the default for this type only; later calls for the same T win. Resolves T’s serde name via type_name_basename and inserts the override under that name.

Panics if T’s name isn’t in the registry — setting a strategy for an unreachable type is almost always a bug (the override would silently never fire). Use this at call sites where the override targets a type the caller knows should be reachable (typically tests, or a producer that just registered the type up front). Policy sites that configure overrides for a fixed catalog of potentially-top-level types — where the caller’s T might not reach all of them — should use Self::with_strategy_for_name instead.

Source

pub fn with_strategy_for_name( self, name: &'static str, strategy: EncodingStrategy, ) -> Self

Set the encoding strategy for the type registered under serde name. Never asserts — names not in the registry get a stray override entry that’s never looked up at encode time (harmless). Sibling of Self::with_strategy for policy sites that configure overrides for a fixed catalog of potentially-top-level types but don’t know which ones the caller will actually serialize.

For tests or producer call sites that want to fail fast on a registry miss, use Self::with_strategy instead.

Source

pub fn strategy_for<T: MsgpackTagged>(&self) -> EncodingStrategy

Look up the effective encoding strategy for the registered type T. Returns the per-type override if one was set; otherwise the default strategy. Used by the encode-time dispatch and exposed for tests.

Source§

impl<'a, W: Write> Serializer<'a, W>

Source

fn begin_product<'ser>( &'ser mut self, name: &'static str, len: usize, ) -> Result<TaggedSerializeProduct<'ser, 'a, W>, Error>

Shared body of serialize_struct / serialize_tuple_struct. Resolves the product + strategy, writes the strategy-appropriate resolves the product + strategy, returns a configured TaggedSerializeProduct. The two trait methods are identical at this level — only the trait impl fired on the returned adapter differs (which serde picks based on the caller’s serialize_* choice).

Buffering policy. Per-field bytes are buffered into the adapter and flushed in tag-ascending order at end() whenever the user’s source-declaration order has been deliberately reordered relative to the tags (!product.tag_order_matches_source). This is what makes both strategies emit canonical (tag-ascending) wire order:

  • Under Array it’s a correctness requirement — the decoder reads positionally and would otherwise see fields in the wrong slots.
  • Under Tagged it’s a byte-determinism requirement — the decoder doesn’t care about order (every wire entry carries its tag), but consumers reading the bytes do: cross-implementation compatibility, hashing, cryptographic commitments. The design doc’s “TAGS define the canonical field order” promise applies here.

Types whose source-declaration order is already tag-ascending (the common case — newly-added types and types using implicit positional tags) skip the buffer entirely: the outer header is written upfront and each field streams through to the parent directly, saving the per-field Vec<u8> allocation. The cost is paid only by types whose tags have drifted out of source order — typically schema-evolved types with retired-and-re-added fields. If you reorder fields, you’re opting into a per-field allocation at encode time.

Source

fn begin_variant_payload<'ser>( &'ser mut self, name: &'static str, variant: &'static str, len: usize, ) -> Result<TaggedSerializeProduct<'ser, 'a, W>, Error>

Shared body of serialize_tuple_variant / serialize_struct_variant. Writes the outer 1-entry {variant_tag: ...} discriminator map (always Tagged — variant identification is by integer tag under MsgpackTagged); same buffering policy as begin_product for the payload itself.

Source

fn sub_serializer_into<'sub>( &self, writer: &'sub mut Vec<u8>, ) -> Serializer<'a, &'sub mut Vec<u8>>

Spawn a sub-serializer over a fresh Vec<u8> buffer, inheriting this serializer’s registry + per-type strategy config. Used by TaggedSerializeProduct::serialize_tag_and_value to encode each field’s bytes into a temp buffer before flushing in tag-ascending order at end(). Cloning the overrides map is cheap in practice — it’s tiny (a few entries) and only walked per top-level value’s field count.

Source

fn product_for(&self, name: &'static str) -> Product

Resolve a registered Product by serde name. Used by both serialize_struct and serialize_tuple_struct. A registry miss or a sum-shaped entry signals a real bug — register_into should have reached every type encoded under our wrapper, and the macro guarantees product/sum shape matches the Rust definition — so we panic loudly per the design doc rather than fabricating a synthetic shape.

Source

fn product_and_strategy_for( &self, name: &'static str, ) -> (Product, EncodingStrategy)

Resolve a registered Product and the effective encoding strategy for the type registered under name. Used only on the top-level struct paths — variant payloads are forced Tagged at their construction sites.

Source

fn strategy_for_name(&self, name: &str) -> EncodingStrategy

Resolve the effective encoding strategy for the type registered under serde name. Overrides are keyed by the same serde-name string the caller passes here, so it’s a single hash lookup with no registry indirection. Absent any override the per-serializer default_strategy applies.

Source

fn variant_for(&self, name: &'static str, variant_name: &'static str) -> Variant

Resolve a registered Variant by enum-type name + variant name. Used by all four serialize_*_variant methods. A registry miss, a product-shaped entry, or an unknown variant name signals a real bug — the macro and serde-derive should agree on which name lives where.

Source

fn write_variant_header( &mut self, name: &'static str, variant_name: &'static str, ) -> Result<Variant, Error>

Write the outer {variant_tag: <payload>} map header common to all four variant shapes — looks up the variant, writes a 1-entry msgpack map header, and writes the variant tag as the map key. Returns the resolved variant so callers can use its payload for the rest of the shape (a payload map for tuple/struct, the inner value for newtype, nil for unit).

Trait Implementations§

Source§

impl<'ser, 'a, W: Write> Serializer for &'ser mut Serializer<'a, W>

Source§

type Ok = ()

The output type produced by this Serializer during successful serialization. Most serializers that produce text or binary output should set Ok = () and serialize into an io::Write or buffer contained within the Serializer instance. Serializers that build in-memory data structures may be simplified by using Ok to propagate the data structure around.
Source§

type Error = Error

The error type when some error occurs during serialization.
Source§

type SerializeSeq = TaggedSerializeViaParent<'ser, 'a, W>

Type returned from serialize_seq for serializing the content of the sequence.
Source§

type SerializeTuple = TaggedSerializeViaParent<'ser, 'a, W>

Type returned from serialize_tuple for serializing the content of the tuple.
Source§

type SerializeTupleStruct = TaggedSerializeProduct<'ser, 'a, W>

Type returned from serialize_tuple_struct for serializing the content of the tuple struct.
Source§

type SerializeTupleVariant = TaggedSerializeProduct<'ser, 'a, W>

Type returned from serialize_tuple_variant for serializing the content of the tuple variant.
Source§

type SerializeMap = TaggedSerializeViaParent<'ser, 'a, W>

Type returned from serialize_map for serializing the content of the map.
Source§

type SerializeStruct = TaggedSerializeProduct<'ser, 'a, W>

Type returned from serialize_struct for serializing the content of the struct.
Source§

type SerializeStructVariant = TaggedSerializeProduct<'ser, 'a, W>

Type returned from serialize_struct_variant for serializing the content of the struct variant.
Source§

fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error>

Serialize a bool value. Read more
Source§

fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error>

Serialize an i8 value. Read more
Source§

fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error>

Serialize an i16 value. Read more
Source§

fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error>

Serialize an i32 value. Read more
Source§

fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>

Serialize an i64 value. Read more
Source§

fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error>

Serialize an i128 value. Read more
Source§

fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error>

Serialize a u8 value. Read more
Source§

fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error>

Serialize a u16 value. Read more
Source§

fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error>

Serialize a u32 value. Read more
Source§

fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>

Serialize a u64 value. Read more
Source§

fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error>

Serialize a u128 value. Read more
Source§

fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error>

Serialize an f32 value. Read more
Source§

fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error>

Serialize an f64 value. Read more
Source§

fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error>

Serialize a character. Read more
Source§

fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error>

Serialize a &str. Read more
Source§

fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error>

Serialize a chunk of raw byte data. Read more
Source§

fn serialize_none(self) -> Result<Self::Ok, Self::Error>

Serialize a None value. Read more
Source§

fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where T: ?Sized + Serialize,

Serialize a Some(T) value. Read more
Source§

fn serialize_unit(self) -> Result<Self::Ok, Self::Error>

Serialize a () value. Read more
Source§

fn serialize_unit_struct( self, name: &'static str, ) -> Result<Self::Ok, Self::Error>

Serialize a unit struct like struct Unit or PhantomData<T>. Read more
Source§

fn serialize_newtype_struct<T>( self, _name: &'static str, value: &T, ) -> Result<Self::Ok, Self::Error>
where T: ?Sized + Serialize,

Serialize a newtype struct like struct Millimeters(u8). Read more
Source§

fn serialize_seq( self, len: Option<usize>, ) -> Result<Self::SerializeSeq, Self::Error>

Begin to serialize a variably sized sequence. This call must be followed by zero or more calls to serialize_element, then a call to end. Read more
Source§

fn serialize_tuple( self, len: usize, ) -> Result<Self::SerializeTuple, Self::Error>

Begin to serialize a statically sized sequence whose length will be known at deserialization time without looking at the serialized data. This call must be followed by zero or more calls to serialize_element, then a call to end. Read more
Source§

fn serialize_map( self, len: Option<usize>, ) -> Result<Self::SerializeMap, Self::Error>

Begin to serialize a map. This call must be followed by zero or more calls to serialize_key and serialize_value, then a call to end. Read more
Source§

fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result<Self::SerializeTupleStruct, Self::Error>

Begin to serialize a tuple struct like struct Rgb(u8, u8, u8). This call must be followed by zero or more calls to serialize_field, then a call to end. Read more
Source§

fn serialize_struct( self, name: &'static str, len: usize, ) -> Result<Self::SerializeStruct, Self::Error>

Begin to serialize a struct like struct Rgb { r: u8, g: u8, b: u8 }. This call must be followed by zero or more calls to serialize_field, then a call to end. Read more
Source§

fn serialize_unit_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result<Self::Ok, Self::Error>

Serialize a unit variant like E::A in enum E { A, B }. Read more
Source§

fn serialize_newtype_variant<T>( self, name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result<Self::Ok, Self::Error>
where T: ?Sized + Serialize,

Serialize a newtype variant like E::N in enum E { N(u8) }. Read more
Source§

fn serialize_tuple_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result<Self::SerializeTupleVariant, Self::Error>

Begin to serialize a tuple variant like E::T in enum E { T(u8, u8) }. This call must be followed by zero or more calls to serialize_field, then a call to end. Read more
Source§

fn serialize_struct_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result<Self::SerializeStructVariant, Self::Error>

Begin to serialize a struct variant like E::S in enum E { S { r: u8, g: u8, b: u8 } }. This call must be followed by zero or more calls to serialize_field, then a call to end. Read more
Source§

fn collect_seq<I>(self, iter: I) -> Result<Self::Ok, Self::Error>

Collect an iterator as a sequence. Read more
Source§

fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error>
where K: Serialize, V: Serialize, I: IntoIterator<Item = (K, V)>,

Collect an iterator as a map. Read more
Source§

fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where T: Display + ?Sized,

Serialize a string produced by an implementation of Display. Read more
Source§

fn is_human_readable(&self) -> bool

Determine whether Serialize implementations should serialize in human-readable form. Read more

Auto Trait Implementations§

§

impl<'a, W> Freeze for Serializer<'a, W>
where W: Freeze,

§

impl<'a, W> RefUnwindSafe for Serializer<'a, W>
where W: RefUnwindSafe,

§

impl<'a, W> Send for Serializer<'a, W>
where W: Send,

§

impl<'a, W> Sync for Serializer<'a, W>
where W: Sync,

§

impl<'a, W> Unpin for Serializer<'a, W>
where W: Unpin,

§

impl<'a, W> UnwindSafe for Serializer<'a, W>
where W: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.