pub trait MapStorage {
type Key;
type Value;
// Required methods
fn storage_len(&self) -> usize;
fn storage_insert(&mut self, key: Self::Key, value: Self::Value);
fn storage_clear(&mut self);
fn storage_iter<'a>(
&'a self,
) -> impl Iterator<Item = (&'a Self::Key, &'a Self::Value)>
where Self::Key: 'a,
Self::Value: 'a;
}Expand description
The owned collection backing a proto map<K, V> field.
The default is the __private::HashMap alias above; buffa_build’s
map_type knob can instead select the buffa-provided
BTreeMap (deterministic iteration order,
no extra dependency) or a custom map. The five runtime helpers in this
module need only three operations from the container — count entries,
borrow-iterate entries, and insert one entry — so this trait captures that
minimal surface and lets the helpers stay generic over which map a field
uses rather than hard-coding __private::HashMap.
The wire format is identical regardless of the container; only the in-memory owned type changes, and view types are unaffected.
It is re-exported at the crate root, so downstream code can write
use buffa::MapStorage; (the longer buffa::map_codec::MapStorage path also
works).
§Sealing
Unlike [MapCodec] / [MapValueDecode], this trait is not sealed.
Those traits guard wire-format invariants the type system cannot express, so
they must stay closed. MapStorage carries no wire invariant: a buggy impl
can at worst iterate in an unusual order (already permitted for proto maps)
or drop the consumer’s own entries. Leaving it open lets a downstream crate
wrap a foreign map (e.g. indexmap::IndexMap) in a crate-local newtype and
implement MapStorage on it, exactly as the orphan rule requires. The
wire-format seal is orthogonal and unaffected.
§Contract
storage_insertis last-write-wins, matching proto map-merge semantics (a later entry for an existing key replaces the earlier value).storage_iterandstorage_lenmust agree: the iterator yields exactlystorage_len()entries.
The key/value types are associated types (Key /
Value), not trait parameters, and the per-collection key
bound (Eq + Hash for HashMap, Ord for BTreeMap) lives on each impl.
The generic helpers bound only C: MapStorage<Key = …, Value = …> and never
name a key bound themselves. Because the key/value are associated, a type
implements MapStorage at most once, so the container — and its key and
value types — resolve unambiguously everywhere the trait is used as a bound.
§Requirements (for a custom map)
This is the canonical list of what a custom map must provide. A custom map is always a crate-local newtype (the orphan rule blocks implementing the buffa-owned reflection / serde traits on a foreign map), and must implement:
MapStorageitself (this trait), naming itsKey/Value.Default+Clone+PartialEq+Debug— the generated owned message derives these, so its map field must support them.FromIterator<(Key, Value)>— the view→owned conversion.collect()s entries into the owned map.buffa_descriptor’sReflectMapunder the reflection / vtable path — not derivable, but aBTreeMap/HashMap-backed newtype can delegate to the inner map’s impl. This requirement isstd-only (vtable reflection requiresstd), so ano_stdbuild never needs it.arbitrary::Arbitraryunder thearbitraryfeature (derivable on a newtype).serde::Serialize/Deserializeunder a JSON-enabled build. The proto3 JSON codec drives serialization through this trait, so every proto map key/value type is supported regardless of the container — there is no string-key or scalar-value restriction. (When a newtype wraps the inner map in a single field, a derivedSerialize/Deserializealready routes transparently to the inner map; the with-modules call this trait’s methods directly rather than the newtype’s serde, so even that is only needed when the field type bypasses a with-module.)
The buffa-provided HashMap and BTreeMap already satisfy all of these, so
selecting BTreeMap needs no consumer code.
This trait is used only as a generic bound; it is not object-safe (the
storage_iter RPITIT precludes dyn MapStorage).
Required Associated Types§
Required Methods§
Sourcefn storage_len(&self) -> usize
fn storage_len(&self) -> usize
Number of entries.
Sourcefn storage_insert(&mut self, key: Self::Key, value: Self::Value)
fn storage_insert(&mut self, key: Self::Key, value: Self::Value)
Insert one entry (last-write-wins, matching proto map-merge semantics).
Sourcefn storage_clear(&mut self)
fn storage_clear(&mut self)
Remove all entries (the field’s cleared / default state), retaining
capacity where the underlying type allows. Invoked by the generated
message clear().
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".