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, ®istry)
.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>
impl<'a, W: Write> Serializer<'a, W>
Sourcepub fn new(writer: W, registry: &'a TagRegistry) -> Self
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.
Sourcepub fn with_default_strategy(self, strategy: EncodingStrategy) -> Self
pub fn with_default_strategy(self, strategy: EncodingStrategy) -> Self
Change the default strategy applied to types without a per-type override.
Sourcepub fn with_strategy<T: MsgpackTagged>(self, strategy: EncodingStrategy) -> Self
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.
Sourcepub fn with_strategy_for_name(
self,
name: &'static str,
strategy: EncodingStrategy,
) -> Self
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.
Sourcepub fn strategy_for<T: MsgpackTagged>(&self) -> EncodingStrategy
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>
impl<'a, W: Write> Serializer<'a, W>
Sourcefn begin_product<'ser>(
&'ser mut self,
name: &'static str,
len: usize,
) -> Result<TaggedSerializeProduct<'ser, 'a, W>, Error>
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
Arrayit’s a correctness requirement — the decoder reads positionally and would otherwise see fields in the wrong slots. - Under
Taggedit’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.
Sourcefn begin_variant_payload<'ser>(
&'ser mut self,
name: &'static str,
variant: &'static str,
len: usize,
) -> Result<TaggedSerializeProduct<'ser, 'a, W>, Error>
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.
Sourcefn sub_serializer_into<'sub>(
&self,
writer: &'sub mut Vec<u8>,
) -> Serializer<'a, &'sub mut Vec<u8>>
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.
Sourcefn product_for(&self, name: &'static str) -> Product
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.
Sourcefn product_and_strategy_for(
&self,
name: &'static str,
) -> (Product, EncodingStrategy)
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.
Sourcefn strategy_for_name(&self, name: &str) -> EncodingStrategy
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.
Sourcefn variant_for(&self, name: &'static str, variant_name: &'static str) -> Variant
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.
Sourcefn write_variant_header(
&mut self,
name: &'static str,
variant_name: &'static str,
) -> Result<Variant, Error>
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>
impl<'ser, 'a, W: Write> Serializer for &'ser mut Serializer<'a, W>
Source§type Ok = ()
type Ok = ()
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 SerializeSeq = TaggedSerializeViaParent<'ser, 'a, W>
type SerializeSeq = TaggedSerializeViaParent<'ser, 'a, W>
serialize_seq for serializing the content of the
sequence.Source§type SerializeTuple = TaggedSerializeViaParent<'ser, 'a, W>
type SerializeTuple = TaggedSerializeViaParent<'ser, 'a, W>
serialize_tuple for serializing the content of
the tuple.Source§type SerializeTupleStruct = TaggedSerializeProduct<'ser, 'a, W>
type SerializeTupleStruct = TaggedSerializeProduct<'ser, 'a, W>
serialize_tuple_struct for serializing the
content of the tuple struct.Source§type SerializeTupleVariant = TaggedSerializeProduct<'ser, 'a, W>
type SerializeTupleVariant = TaggedSerializeProduct<'ser, 'a, W>
serialize_tuple_variant for serializing the
content of the tuple variant.Source§type SerializeMap = TaggedSerializeViaParent<'ser, 'a, W>
type SerializeMap = TaggedSerializeViaParent<'ser, 'a, W>
serialize_map for serializing the content of the
map.Source§type SerializeStruct = TaggedSerializeProduct<'ser, 'a, W>
type SerializeStruct = TaggedSerializeProduct<'ser, 'a, W>
serialize_struct for serializing the content of
the struct.Source§type SerializeStructVariant = TaggedSerializeProduct<'ser, 'a, W>
type SerializeStructVariant = TaggedSerializeProduct<'ser, 'a, W>
serialize_struct_variant for serializing the
content of the struct variant.Source§fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error>
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error>
bool value. Read moreSource§fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error>
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error>
i8 value. Read moreSource§fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error>
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error>
i16 value. Read moreSource§fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error>
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error>
i32 value. Read moreSource§fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>
i64 value. Read moreSource§fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error>
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error>
i128 value. Read moreSource§fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error>
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error>
u16 value. Read moreSource§fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error>
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error>
u32 value. Read moreSource§fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>
u64 value. Read moreSource§fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error>
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error>
u128 value. Read moreSource§fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error>
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error>
f32 value. Read moreSource§fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error>
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error>
f64 value. Read moreSource§fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error>
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error>
Source§fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error>
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error>
Source§fn serialize_newtype_struct<T>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
fn serialize_newtype_struct<T>( self, _name: &'static str, value: &T, ) -> Result<Self::Ok, Self::Error>
struct Millimeters(u8). Read moreSource§fn serialize_seq(
self,
len: Option<usize>,
) -> Result<Self::SerializeSeq, Self::Error>
fn serialize_seq( self, len: Option<usize>, ) -> Result<Self::SerializeSeq, Self::Error>
serialize_element, then a call to
end. Read moreSource§fn serialize_tuple(
self,
len: usize,
) -> Result<Self::SerializeTuple, Self::Error>
fn serialize_tuple( self, len: usize, ) -> Result<Self::SerializeTuple, Self::Error>
serialize_element,
then a call to end. Read moreSource§fn serialize_map(
self,
len: Option<usize>,
) -> Result<Self::SerializeMap, Self::Error>
fn serialize_map( self, len: Option<usize>, ) -> Result<Self::SerializeMap, Self::Error>
serialize_key and serialize_value, then a call to end. Read moreSource§fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error>
fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result<Self::SerializeTupleStruct, Self::Error>
struct Rgb(u8, u8, u8). This
call must be followed by zero or more calls to serialize_field, then a
call to end. Read moreSource§fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error>
fn serialize_struct( self, name: &'static str, len: usize, ) -> Result<Self::SerializeStruct, Self::Error>
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 moreSource§fn serialize_unit_variant(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error>
fn serialize_unit_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result<Self::Ok, Self::Error>
Source§fn serialize_newtype_variant<T>(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
fn serialize_newtype_variant<T>( self, name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result<Self::Ok, Self::Error>
Source§fn serialize_tuple_variant(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error>
fn serialize_tuple_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result<Self::SerializeTupleVariant, Self::Error>
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 moreSource§fn serialize_struct_variant(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error>
fn serialize_struct_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result<Self::SerializeStructVariant, Self::Error>
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 moreSource§fn collect_seq<I>(self, iter: I) -> Result<Self::Ok, Self::Error>
fn collect_seq<I>(self, iter: I) -> Result<Self::Ok, Self::Error>
Source§fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error>
fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error>
Source§fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
Display. Read moreSource§fn is_human_readable(&self) -> bool
fn is_human_readable(&self) -> bool
Serialize implementations should serialize in
human-readable form. Read more