Skip to main content

Module extension

Module extension 

Source
Expand description

Typed access to protobuf extensions stored in unknown fields.

Custom options — (buf.validate.field), (google.api.http), etc. — are declared with extend google.protobuf.FieldOptions { ... } and attached in proto source as [(my.option) = {...}]. Editions removed general-purpose message extensions but custom options remain the sanctioned use of extend: descriptor.proto still declares extensions 1000 to max; on every *Options message.

On the wire, extension values are ordinary fields at their declared field numbers. When an extendee is decoded without the extension in its schema, those fields land in UnknownFields — already preserved. This module provides a typed extraction/injection path on top of that storage.

§Usage

Codegen emits a pub const for each extend declaration:

// Generated from: extend google.protobuf.FieldOptions { optional FieldRules field = 1159; }
pub const FIELD: buffa::Extension<buffa::extension::codecs::MessageCodec<FieldRules>>
    = buffa::Extension::new(1159, "google.protobuf.FieldOptions");

The extendee (any message with unknown-field preservation) implements ExtensionSet:

use buffa::ExtensionSet;
let rules: Option<FieldRules> = field.options.extension(&buf_validate::FIELD);
opts.set_extension(&buf_validate::FIELD, my_rules);

§Panics

extension, set_extension, and clear_extension panic if the descriptor’s extendee does not match the extendee message’s PROTO_FQN. This catches bugs like field_options.extension(&MESSAGE_LEVEL_OPTION) at the first call site (matches protobuf-go, which panics, and protobuf-es, which throws). has_extension returns false gracefully on mismatch — “is this extension set here” when it can’t extend here has a legitimate answer.

§Defaults

Proto2 [default = ...] values are surfaced by extension_or_default, which returns the declared default when the extension is absent. Presence is still distinguishable via extension (returns None) or has_extension.

§JSON

Extension fields serialize as "[pkg.ext]" keys in proto3 JSON. This requires a populated TypeRegistry — see the type_registry module (available under the json or text feature). Without a registry, extension bytes stay in __buffa_unknown_fields and are silently dropped from JSON output.

§Presence semantics

Extensions always have explicit field presence, regardless of proto3 or editions IMPLICIT file defaults (see protocolbuffers/protobuf#8234). This falls out naturally from unknown-field storage: set_extension(&ext, 0) pushes a record with value 0, so has_extension returns true. Singular Output is therefore Option<T>, not T with a sentinel.

Modules§

codecs
Codec types — one per proto field type.

Structs§

Extension
Typed extension descriptor.

Traits§

ExtensionCodec
One impl per proto field type. Value is what users pass to set; Output is what get returns (Option<Value> for singular, Vec<Elem> for repeated).
ExtensionSet
Implemented by codegen on every message that preserves unknown fields.