Skip to main content

ProtoString

Trait ProtoString 

Source
pub trait ProtoString:
    Clone
    + PartialEq
    + Default
    + Debug
    + Send
    + Sync
    + Deref<Target = str>
    + AsRef<str>
    + From<String>
    + for<'a> From<&'a str> {
    // Required method
    fn from_wire(payload: WirePayload<'_>) -> Result<Self, DecodeError>;
}
Expand description

The bound generated code places on the Rust type used for a proto string field.

buffa implements it for the default String. Select another representation with buffa_build’s string_type / string_type_custom. There is intentionally no blanket impl, and a foreign type cannot implement this trait (orphan rule) — wrap it in a local newtype that implements the trait; see examples/custom-types in the buffa repository for the canonical template (and buffa-smolstr in the same repository for a self-contained smol_str newtype).

The bounds are exactly what generated code requires of a string field:

  • from_wire (the required method, below) — the binary decode constructor.
  • Clone + PartialEq + Default + Debug — for the #[derive(...)] and the hand-written Debug impl on message structs, and for clear() (which resets the field to Default rather than relying on a String-specific clear, since a substituted type may be immutable).
  • Send + Sync — so a message owning such a field stays Send + Sync; without this bound an exotic string type could silently make every containing message thread-unsafe.
  • Deref<Target = str> and AsRef<str> — generated code borrows the field as &str by plain reference coercion (&self.field where encode_string / string_encoded_len expect &str), so the representation must Deref to str; AsRef<str> is also required for the call sites that ask for it explicitly.
  • From<String> and From<&str> — used by the JSON, text-format, and view→owned paths to construct the field from freshly decoded text (binary decode uses from_wire instead).

For the default String representation every conversion is the identity, so the generic path costs nothing relative to the specialized one.

§Contract

The bounds are structural and cannot capture these invariants; an implementation must uphold them:

  • Default is the empty string — generated clear() resets to Default::default() and implicit-presence encoding skips empty values, so a non-empty Default silently drops or corrupts cleared fields.
  • Deref, AsRef, and the constructors observe the same content — encoding borrows via Deref / AsRef and the view / reflect paths read the same way; if they disagree, a value encodes differently than it reads back.
  • from_wire is value-equivalent to From<String> / From<&str> — binary decode uses from_wire while JSON / text / view→owned use From, so a representation must not transform the text (e.g. case-fold) in one path but not the other.

§Limitations

These apply to a custom type used as a repeated element or in a map slot (map<string, V> key, map<K, string> value). Singular / optional / oneof uses have none of them and work with a foreign type directly. See the user guide’s “String and bytes field representations” section for the full table.

  • Must be crate-local. A custom type in a repeated element or map slot needs codegen-emitted ReflectElement / ReflectMapKey impls (for vtable reflection), which the orphan rule permits only when the type is local to the generating crate. A foreign custom type in those positions fails to compile — wrap it in a crate-local newtype.
  • JSON needs native serde. A custom string used as a repeated element or in a map serializes through its own serde, so it must derive Serialize / Deserialize (and, for an external type, enable its serde feature). Singular / optional / oneof custom strings use the proto_string with-module and need no serde impl.
  • A map key needs Hash + Eq (default / HashMap container) or Ord (map_type(BTreeMap)); the bound is enforced at the generated field type.
  • No Arbitrary impl required, except in a map. Under the arbitrary feature, singular / optional / repeated fields get a generic builder, so a custom type needs no native arbitrary::Arbitrary impl. The map arbitrary path currently has no per-key shim, so a custom string used as a map key or value must derive Arbitrary itself.

Required Methods§

Source

fn from_wire(payload: WirePayload<'_>) -> Result<Self, DecodeError>

Construct the representation from a decoded string field’s wire payload.

This is the decode constructor: it owns the validation/ownership choice, so a representation can borrow-and-inline a short string (no transient heap allocation) or validate UTF-8 only when it must. Validate-and-borrow with WirePayload::to_str (which uses buffa’s UTF-8 validator and so picks up the fast-utf8 feature), or read raw bytes with WirePayload::as_slice. There is intentionally no blanket impl — every representation provides its own optimal from_wire; the From<String>/From<&str> supertraits remain for the JSON, text, and view→owned paths.

§Errors

Returns DecodeError::InvalidUtf8 if the payload is not valid UTF-8. A representation that enforces additional invariants can reject the value with DecodeError::Custom (carrying a static reason), or return any other DecodeError variant.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl ProtoString for String

Source§

fn from_wire(payload: WirePayload<'_>) -> Result<Self, DecodeError>

Implementors§