diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d851d..f856fd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Added +- **`buffa::MessageName` trait exposes a generated message's protobuf + identifiers as compile-time `&'static str` constants.** Codegen emits + `impl MessageName for #Msg` (and `for #MsgView<'a>`) with four consts: + `PACKAGE` (`"my.pkg"`, empty for the unnamed root package), `NAME` + (`"Outer.Inner"` — unqualified, with `.` between nesting levels), + `FULL_NAME` (`"my.pkg.Outer.Inner"`), and `TYPE_URL` + (`"type.googleapis.com/my.pkg.Outer.Inner"` — the + `google.protobuf.Any.type_url` form). All four are computed at codegen + time as string literals, so there's no runtime allocation or + concatenation — unlike `prost::Name`, whose `full_name()` and + `type_url()` are runtime `format!` calls. `PACKAGE` and `NAME` are + separate consts because the dotted `FULL_NAME` cannot be split + unambiguously (`foo.Bar.Baz` could be package `foo.Bar` + message `Baz` + or package `foo` + nested `Bar.Baz`). + + The trait has no supertrait — it doesn't reach into the wire codec — + so view types implement it too: a generic event-sourcing registry can + bound on `T: MessageName` and dispatch zero-copy views and owned + messages identically. Useful for type-erased registries, logging, and + any code that needs the protobuf name without the descriptor machinery. + The inherent `Foo::TYPE_URL` const generated since 0.4.0 is unchanged + and equal to `::TYPE_URL`; for messages that also + implement `ExtensionSet`, `FULL_NAME` is equal to + `ExtensionSet::PROTO_FQN` (all derive from the same codegen source). + `MessageName` is **not** object-safe (associated `const` only) — use it + as a bound, not `dyn MessageName`. Migrating from `prost::Name`: rename + the bound and replace runtime `M::full_name()` / `M::type_url()` calls + with the consts. ([#108](https://github.com/anthropics/buffa/pull/108), + by @yordis) + - **`buf.build/anthropics/buffa` is published to the public Buf Schema Registry.** `buf generate` can now reference `protoc-gen-buffa` as a `remote:` plugin with no local install: `remote: buf.build/anthropics/buffa` diff --git a/buffa-codegen/src/impl_message.rs b/buffa-codegen/src/impl_message.rs index 8ce3f50..31d710c 100644 --- a/buffa-codegen/src/impl_message.rs +++ b/buffa-codegen/src/impl_message.rs @@ -322,6 +322,54 @@ fn message_uses_size_cache( /// Generate `impl DefaultInstance` and `impl Message` for a message. /// +/// Emit `impl #generics ::buffa::MessageName for #ty { … }`. +/// +/// `generics` is the impl-side generic parameter list (`<'a>` for the +/// view type, empty for the owned message). `ty` is the implementing +/// type *with* any generics applied (`Foo` or `FooView<'a>`). +/// +/// All four consts are computed at codegen time as string literals so +/// `T::FULL_NAME` etc. are zero-cost at runtime — no `format!`, +/// `concat!`, or lazy static. `PACKAGE` and `NAME` are split here rather +/// than left to the consumer because the dotted `FULL_NAME` cannot be +/// re-split unambiguously: `foo.Bar.Baz` could be package `foo.Bar` + +/// message `Baz`, or package `foo` + nested `Bar.Baz`. Codegen knows +/// which. +pub(crate) fn message_name_impl( + current_package: &str, + proto_fqn: &str, + generics: &TokenStream, + ty: &TokenStream, +) -> TokenStream { + let name = if current_package.is_empty() { + proto_fqn.to_string() + } else { + // Strip `"."` atomically — a two-step + // `strip_prefix(package)` then `strip_prefix(".")` would + // partial-match a prefix-overlapping package (`package = "foo"` + // against `proto_fqn = "food.Bar"`) and silently violate the + // documented `PACKAGE + "." + NAME == FULL_NAME` invariant. + // + // `proto_fqn` is always `"."` for a non-empty + // package (it's built by joining message segments onto the + // package), so the strip should never fail. Fall back + // defensively rather than panic on a malformed descriptor. + proto_fqn + .strip_prefix(&format!("{current_package}.")) + .unwrap_or(proto_fqn) + .to_string() + }; + let type_url = format!("type.googleapis.com/{proto_fqn}"); + quote! { + impl #generics ::buffa::MessageName for #ty { + const PACKAGE: &'static str = #current_package; + const NAME: &'static str = #name; + const FULL_NAME: &'static str = #proto_fqn; + const TYPE_URL: &'static str = #type_url; + } + } +} + /// `preserve_unknown_fields`: when `true`, the generated merge collects /// unknown fields into `self.__buffa_unknown_fields` and both `compute_size` and /// `write_to` include them. @@ -543,6 +591,13 @@ pub fn generate_message_impl( quote! {} }; + let message_name_impl = message_name_impl( + current_package, + proto_fqn, + "e! {}, + "e! { #name_ident }, + ); + Ok(quote! { impl ::buffa::DefaultInstance for #name_ident { fn default_instance() -> &'static Self { @@ -552,6 +607,8 @@ pub fn generate_message_impl( } } + #message_name_impl + impl ::buffa::Message for #name_ident { /// Returns the total encoded size in bytes. /// diff --git a/buffa-codegen/src/tests/feature_gating.rs b/buffa-codegen/src/tests/feature_gating.rs index 854dcb9..d048068 100644 --- a/buffa-codegen/src/tests/feature_gating.rs +++ b/buffa-codegen/src/tests/feature_gating.rs @@ -198,6 +198,45 @@ fn gated_view_module_is_cfg_blocked() { squashed.contains(r#"#[cfg(feature = "views")] pub mod view"#), "the views cfg must precede `pub mod view`: {content}" ); + // The view's `impl MessageName for FooView<'a>` lives in the + // `.__view.rs` content file, which the stitcher `include!`s + // *inside* the `#[cfg(feature = "views")] pub mod view` block, so + // it disappears with the feature. The owned-message impl is in the + // `.rs` content file (unconditional). Pin both: a refactor + // that emits the view impl into a non-View content file would ship + // a name-resolution error against a cfg'd-out type. + let cfg = CodeGenConfig { + generate_json: true, + generate_views: true, + generate_text: false, + preserve_unknown_fields: true, + gate_impls_on_crate_features: true, + ..CodeGenConfig::default() + }; + let files = + generate(&[fixture()], &["gated.proto".to_string()], &cfg).expect("should generate"); + for f in &files { + let has_view_impl = f.content.contains("MessageName for OuterView"); + let has_owned_impl = squash(&f.content).contains("impl ::buffa::MessageName for Outer "); + match f.kind { + GeneratedFileKind::View => assert!( + has_view_impl, + "view MessageName impl must be in the view content file ({})", + f.name + ), + GeneratedFileKind::Owned => assert!( + has_owned_impl && !has_view_impl, + "owned content file must have the owned (not view) MessageName impl ({})", + f.name + ), + _ => assert!( + !has_view_impl && !has_owned_impl, + "MessageName impl leaked into a {:?} file ({})", + f.kind, + f.name + ), + } + } } #[test] diff --git a/buffa-codegen/src/tests/generation.rs b/buffa-codegen/src/tests/generation.rs index aa29cb1..c36b153 100644 --- a/buffa-codegen/src/tests/generation.rs +++ b/buffa-codegen/src/tests/generation.rs @@ -1241,6 +1241,77 @@ fn test_type_url_doubly_nested() { ); } +#[test] +fn test_message_name_consts() { + // The four `MessageName` consts must hold the documented invariant + // `PACKAGE + "." + NAME == FULL_NAME` (joining dot omitted when + // `PACKAGE` is empty), and `TYPE_URL == "type.googleapis.com/" + + // FULL_NAME`. The atomic-prefix-strip in `message_name_impl` makes + // a partial-match (`package = "foo"` against `proto_fqn = + // "food.Bar"`) impossible to slip through silently — pin the shape + // here so a refactor that re-introduces a two-step strip fails this + // test instead of shipping a broken `NAME`. + let mut file = proto3_file("named.proto"); + file.package = Some("my.pkg".to_string()); + file.message_type.push(DescriptorProto { + name: Some("Outer".to_string()), + nested_type: vec![DescriptorProto { + name: Some("Inner".to_string()), + ..Default::default() + }], + ..Default::default() + }); + let files = generate( + &[file], + &["named.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect("should generate"); + let content = joined(&files); + // Top-level: PACKAGE + "." + NAME == FULL_NAME. + for snippet in [ + r#"const PACKAGE: &'static str = "my.pkg""#, + r#"const NAME: &'static str = "Outer""#, + r#"const FULL_NAME: &'static str = "my.pkg.Outer""#, + r#"const TYPE_URL: &'static str = "type.googleapis.com/my.pkg.Outer""#, + // Nested: NAME carries the dotted nesting path; PACKAGE stays + // at the proto package — NOT `DescriptorProto.name` (which is + // just `"Inner"`). + r#"const NAME: &'static str = "Outer.Inner""#, + r#"const FULL_NAME: &'static str = "my.pkg.Outer.Inner""#, + ] { + assert!(content.contains(snippet), "missing `{snippet}`: {content}"); + } + + // Empty package: PACKAGE is "", NAME == FULL_NAME, no joining dot. + let mut root = proto3_file("root.proto"); + root.message_type.push(DescriptorProto { + name: Some("Root".to_string()), + nested_type: vec![DescriptorProto { + name: Some("Leaf".to_string()), + ..Default::default() + }], + ..Default::default() + }); + let files = generate( + &[root], + &["root.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect("should generate"); + let content = joined(&files); + for snippet in [ + r#"const PACKAGE: &'static str = """#, + r#"const NAME: &'static str = "Root""#, + r#"const FULL_NAME: &'static str = "Root""#, + r#"const NAME: &'static str = "Root.Leaf""#, + r#"const FULL_NAME: &'static str = "Root.Leaf""#, + r#"const TYPE_URL: &'static str = "type.googleapis.com/Root.Leaf""#, + ] { + assert!(content.contains(snippet), "missing `{snippet}`: {content}"); + } +} + #[test] fn test_message_scalar_fields() { let mut file = proto3_file("scalars.proto"); diff --git a/buffa-codegen/src/view.rs b/buffa-codegen/src/view.rs index d874be0..6989567 100644 --- a/buffa-codegen/src/view.rs +++ b/buffa-codegen/src/view.rs @@ -166,6 +166,17 @@ pub(crate) fn generate_view_with_nesting( } }; + // The view participates in the same name-keyed registries as the + // owned message — a generic event-sourcing dispatch should not have + // to round-trip a zero-copy view through `to_owned_message()` just + // to read its FQN. Same consts, different `Self`. + let message_name_impl = crate::impl_message::message_name_impl( + current_package, + proto_fqn, + "e! { <'a> }, + "e! { #view_ident<'a> }, + ); + let serialize_impl = if ctx.config.generate_json { crate::feature_gates::cfg_block( generate_view_serialize( @@ -337,6 +348,8 @@ pub(crate) fn generate_view_with_nesting( #serialize_impl + #message_name_impl + impl<'v> ::buffa::DefaultViewInstance for #view_ident<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs index 19278d1..fd122f6 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs @@ -257,6 +257,12 @@ impl<'__a> ::serde::Serialize for VersionView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for VersionView<'a> { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "Version"; + const FULL_NAME: &'static str = "google.protobuf.compiler.Version"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.Version"; +} impl<'v> ::buffa::DefaultViewInstance for VersionView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -655,6 +661,12 @@ impl<'__a> ::serde::Serialize for CodeGeneratorRequestView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for CodeGeneratorRequestView<'a> { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "CodeGeneratorRequest"; + const FULL_NAME: &'static str = "google.protobuf.compiler.CodeGeneratorRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.CodeGeneratorRequest"; +} impl<'v> ::buffa::DefaultViewInstance for CodeGeneratorRequestView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1000,6 +1012,12 @@ impl<'__a> ::serde::Serialize for CodeGeneratorResponseView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for CodeGeneratorResponseView<'a> { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "CodeGeneratorResponse"; + const FULL_NAME: &'static str = "google.protobuf.compiler.CodeGeneratorResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.CodeGeneratorResponse"; +} impl<'v> ::buffa::DefaultViewInstance for CodeGeneratorResponseView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1360,6 +1378,12 @@ pub mod code_generator_response { __map.end() } } + impl<'a> ::buffa::MessageName for FileView<'a> { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "CodeGeneratorResponse.File"; + const FULL_NAME: &'static str = "google.protobuf.compiler.CodeGeneratorResponse.File"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.CodeGeneratorResponse.File"; + } impl<'v> ::buffa::DefaultViewInstance for FileView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs index 71fb8a6..42256f5 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs @@ -73,6 +73,12 @@ impl ::buffa::DefaultInstance for Version { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Version { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "Version"; + const FULL_NAME: &'static str = "google.protobuf.compiler.Version"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.Version"; +} impl ::buffa::Message for Version { /// Returns the total encoded size in bytes. /// @@ -411,6 +417,12 @@ impl ::buffa::DefaultInstance for CodeGeneratorRequest { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for CodeGeneratorRequest { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "CodeGeneratorRequest"; + const FULL_NAME: &'static str = "google.protobuf.compiler.CodeGeneratorRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.CodeGeneratorRequest"; +} impl ::buffa::Message for CodeGeneratorRequest { /// Returns the total encoded size in bytes. /// @@ -819,6 +831,12 @@ impl ::buffa::DefaultInstance for CodeGeneratorResponse { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for CodeGeneratorResponse { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "CodeGeneratorResponse"; + const FULL_NAME: &'static str = "google.protobuf.compiler.CodeGeneratorResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.CodeGeneratorResponse"; +} impl ::buffa::Message for CodeGeneratorResponse { /// Returns the total encoded size in bytes. /// @@ -1367,6 +1385,12 @@ pub mod code_generator_response { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for File { + const PACKAGE: &'static str = "google.protobuf.compiler"; + const NAME: &'static str = "CodeGeneratorResponse.File"; + const FULL_NAME: &'static str = "google.protobuf.compiler.CodeGeneratorResponse.File"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.compiler.CodeGeneratorResponse.File"; + } impl ::buffa::Message for File { /// Returns the total encoded size in bytes. /// diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs index 4f9b8f6..5203847 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs @@ -179,6 +179,12 @@ impl<'__a> ::serde::Serialize for FileDescriptorSetView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FileDescriptorSetView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FileDescriptorSet"; + const FULL_NAME: &'static str = "google.protobuf.FileDescriptorSet"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FileDescriptorSet"; +} impl<'v> ::buffa::DefaultViewInstance for FileDescriptorSetView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -939,6 +945,12 @@ impl<'__a> ::serde::Serialize for FileDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FileDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FileDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.FileDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FileDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for FileDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1589,6 +1601,12 @@ impl<'__a> ::serde::Serialize for DescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for DescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.DescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for DescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1870,6 +1888,12 @@ pub mod descriptor_proto { __map.end() } } + impl<'a> ::buffa::MessageName for ExtensionRangeView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DescriptorProto.ExtensionRange"; + const FULL_NAME: &'static str = "google.protobuf.DescriptorProto.ExtensionRange"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DescriptorProto.ExtensionRange"; + } impl<'v> ::buffa::DefaultViewInstance for ExtensionRangeView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -2091,6 +2115,12 @@ pub mod descriptor_proto { __map.end() } } + impl<'a> ::buffa::MessageName for ReservedRangeView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DescriptorProto.ReservedRange"; + const FULL_NAME: &'static str = "google.protobuf.DescriptorProto.ReservedRange"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DescriptorProto.ReservedRange"; + } impl<'v> ::buffa::DefaultViewInstance for ReservedRangeView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -2449,6 +2479,12 @@ impl<'__a> ::serde::Serialize for ExtensionRangeOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for ExtensionRangeOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ExtensionRangeOptions"; + const FULL_NAME: &'static str = "google.protobuf.ExtensionRangeOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ExtensionRangeOptions"; +} impl<'v> ::buffa::DefaultViewInstance for ExtensionRangeOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -2755,6 +2791,12 @@ pub mod extension_range_options { __map.end() } } + impl<'a> ::buffa::MessageName for DeclarationView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ExtensionRangeOptions.Declaration"; + const FULL_NAME: &'static str = "google.protobuf.ExtensionRangeOptions.Declaration"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ExtensionRangeOptions.Declaration"; + } impl<'v> ::buffa::DefaultViewInstance for DeclarationView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -3313,6 +3355,12 @@ impl<'__a> ::serde::Serialize for FieldDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FieldDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.FieldDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for FieldDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -3543,6 +3591,12 @@ impl<'__a> ::serde::Serialize for OneofDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for OneofDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "OneofDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.OneofDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.OneofDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for OneofDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -3950,6 +4004,12 @@ impl<'__a> ::serde::Serialize for EnumDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for EnumDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.EnumDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for EnumDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -4177,6 +4237,12 @@ pub mod enum_descriptor_proto { __map.end() } } + impl<'a> ::buffa::MessageName for EnumReservedRangeView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumDescriptorProto.EnumReservedRange"; + const FULL_NAME: &'static str = "google.protobuf.EnumDescriptorProto.EnumReservedRange"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumDescriptorProto.EnumReservedRange"; + } impl<'v> ::buffa::DefaultViewInstance for EnumReservedRangeView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -4441,6 +4507,12 @@ impl<'__a> ::serde::Serialize for EnumValueDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for EnumValueDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumValueDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.EnumValueDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumValueDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for EnumValueDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -4723,6 +4795,12 @@ impl<'__a> ::serde::Serialize for ServiceDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for ServiceDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ServiceDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.ServiceDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ServiceDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for ServiceDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -5062,6 +5140,12 @@ impl<'__a> ::serde::Serialize for MethodDescriptorProtoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for MethodDescriptorProtoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "MethodDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.MethodDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.MethodDescriptorProto"; +} impl<'v> ::buffa::DefaultViewInstance for MethodDescriptorProtoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -5953,6 +6037,12 @@ impl<'__a> ::serde::Serialize for FileOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FileOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FileOptions"; + const FULL_NAME: &'static str = "google.protobuf.FileOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FileOptions"; +} impl<'v> ::buffa::DefaultViewInstance for FileOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -6408,6 +6498,12 @@ impl<'__a> ::serde::Serialize for MessageOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for MessageOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "MessageOptions"; + const FULL_NAME: &'static str = "google.protobuf.MessageOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.MessageOptions"; +} impl<'v> ::buffa::DefaultViewInstance for MessageOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -7165,6 +7261,12 @@ impl<'__a> ::serde::Serialize for FieldOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FieldOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldOptions"; + const FULL_NAME: &'static str = "google.protobuf.FieldOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldOptions"; +} impl<'v> ::buffa::DefaultViewInstance for FieldOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -7389,6 +7491,12 @@ pub mod field_options { __map.end() } } + impl<'a> ::buffa::MessageName for EditionDefaultView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldOptions.EditionDefault"; + const FULL_NAME: &'static str = "google.protobuf.FieldOptions.EditionDefault"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldOptions.EditionDefault"; + } impl<'v> ::buffa::DefaultViewInstance for EditionDefaultView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -7709,6 +7817,12 @@ pub mod field_options { __map.end() } } + impl<'a> ::buffa::MessageName for FeatureSupportView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldOptions.FeatureSupport"; + const FULL_NAME: &'static str = "google.protobuf.FieldOptions.FeatureSupport"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldOptions.FeatureSupport"; + } impl<'v> ::buffa::DefaultViewInstance for FeatureSupportView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -7969,6 +8083,12 @@ impl<'__a> ::serde::Serialize for OneofOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for OneofOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "OneofOptions"; + const FULL_NAME: &'static str = "google.protobuf.OneofOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.OneofOptions"; +} impl<'v> ::buffa::DefaultViewInstance for OneofOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -8320,6 +8440,12 @@ impl<'__a> ::serde::Serialize for EnumOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for EnumOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumOptions"; + const FULL_NAME: &'static str = "google.protobuf.EnumOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumOptions"; +} impl<'v> ::buffa::DefaultViewInstance for EnumOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -8696,6 +8822,12 @@ impl<'__a> ::serde::Serialize for EnumValueOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for EnumValueOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumValueOptions"; + const FULL_NAME: &'static str = "google.protobuf.EnumValueOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumValueOptions"; +} impl<'v> ::buffa::DefaultViewInstance for EnumValueOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -8989,6 +9121,12 @@ impl<'__a> ::serde::Serialize for ServiceOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for ServiceOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ServiceOptions"; + const FULL_NAME: &'static str = "google.protobuf.ServiceOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ServiceOptions"; +} impl<'v> ::buffa::DefaultViewInstance for ServiceOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -9325,6 +9463,12 @@ impl<'__a> ::serde::Serialize for MethodOptionsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for MethodOptionsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "MethodOptions"; + const FULL_NAME: &'static str = "google.protobuf.MethodOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.MethodOptions"; +} impl<'v> ::buffa::DefaultViewInstance for MethodOptionsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -9721,6 +9865,12 @@ impl<'__a> ::serde::Serialize for UninterpretedOptionView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for UninterpretedOptionView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UninterpretedOption"; + const FULL_NAME: &'static str = "google.protobuf.UninterpretedOption"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UninterpretedOption"; +} impl<'v> ::buffa::DefaultViewInstance for UninterpretedOptionView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -9922,6 +10072,12 @@ pub mod uninterpreted_option { __map.end() } } + impl<'a> ::buffa::MessageName for NamePartView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UninterpretedOption.NamePart"; + const FULL_NAME: &'static str = "google.protobuf.UninterpretedOption.NamePart"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UninterpretedOption.NamePart"; + } impl<'v> ::buffa::DefaultViewInstance for NamePartView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -10416,6 +10572,12 @@ impl<'__a> ::serde::Serialize for FeatureSetView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FeatureSetView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSet"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSet"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSet"; +} impl<'v> ::buffa::DefaultViewInstance for FeatureSetView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -10567,6 +10729,12 @@ pub mod feature_set { __map.end() } } + impl<'a> ::buffa::MessageName for VisibilityFeatureView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSet.VisibilityFeature"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSet.VisibilityFeature"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSet.VisibilityFeature"; + } impl<'v> ::buffa::DefaultViewInstance for VisibilityFeatureView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -10856,6 +11024,12 @@ impl<'__a> ::serde::Serialize for FeatureSetDefaultsView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for FeatureSetDefaultsView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSetDefaults"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSetDefaults"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSetDefaults"; +} impl<'v> ::buffa::DefaultViewInstance for FeatureSetDefaultsView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -11183,6 +11357,12 @@ pub mod feature_set_defaults { __map.end() } } + impl<'a> ::buffa::MessageName for FeatureSetEditionDefaultView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSetDefaults.FeatureSetEditionDefault"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault"; + } impl<'v> ::buffa::DefaultViewInstance for FeatureSetEditionDefaultView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -11431,6 +11611,12 @@ impl<'__a> ::serde::Serialize for SourceCodeInfoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for SourceCodeInfoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "SourceCodeInfo"; + const FULL_NAME: &'static str = "google.protobuf.SourceCodeInfo"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.SourceCodeInfo"; +} impl<'v> ::buffa::DefaultViewInstance for SourceCodeInfoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -11886,6 +12072,12 @@ pub mod source_code_info { __map.end() } } + impl<'a> ::buffa::MessageName for LocationView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "SourceCodeInfo.Location"; + const FULL_NAME: &'static str = "google.protobuf.SourceCodeInfo.Location"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.SourceCodeInfo.Location"; + } impl<'v> ::buffa::DefaultViewInstance for LocationView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -12087,6 +12279,12 @@ impl<'__a> ::serde::Serialize for GeneratedCodeInfoView<'__a> { __map.end() } } +impl<'a> ::buffa::MessageName for GeneratedCodeInfoView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "GeneratedCodeInfo"; + const FULL_NAME: &'static str = "google.protobuf.GeneratedCodeInfo"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.GeneratedCodeInfo"; +} impl<'v> ::buffa::DefaultViewInstance for GeneratedCodeInfoView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -12452,6 +12650,12 @@ pub mod generated_code_info { __map.end() } } + impl<'a> ::buffa::MessageName for AnnotationView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "GeneratedCodeInfo.Annotation"; + const FULL_NAME: &'static str = "google.protobuf.GeneratedCodeInfo.Annotation"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.GeneratedCodeInfo.Annotation"; + } impl<'v> ::buffa::DefaultViewInstance for AnnotationView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.rs index 6f71fbd..b820f21 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.rs @@ -395,6 +395,12 @@ impl ::buffa::DefaultInstance for FileDescriptorSet { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FileDescriptorSet { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FileDescriptorSet"; + const FULL_NAME: &'static str = "google.protobuf.FileDescriptorSet"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FileDescriptorSet"; +} impl ::buffa::Message for FileDescriptorSet { /// Returns the total encoded size in bytes. /// @@ -898,6 +904,12 @@ impl ::buffa::DefaultInstance for FileDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FileDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FileDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.FileDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FileDescriptorProto"; +} impl ::buffa::Message for FileDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -1717,6 +1729,12 @@ impl ::buffa::DefaultInstance for DescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for DescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.DescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DescriptorProto"; +} impl ::buffa::Message for DescriptorProto { /// Returns the total encoded size in bytes. /// @@ -2342,6 +2360,12 @@ pub mod descriptor_proto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for ExtensionRange { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DescriptorProto.ExtensionRange"; + const FULL_NAME: &'static str = "google.protobuf.DescriptorProto.ExtensionRange"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DescriptorProto.ExtensionRange"; + } impl ::buffa::Message for ExtensionRange { /// Returns the total encoded size in bytes. /// @@ -2596,6 +2620,12 @@ pub mod descriptor_proto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for ReservedRange { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DescriptorProto.ReservedRange"; + const FULL_NAME: &'static str = "google.protobuf.DescriptorProto.ReservedRange"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DescriptorProto.ReservedRange"; + } impl ::buffa::Message for ReservedRange { /// Returns the total encoded size in bytes. /// @@ -2847,6 +2877,12 @@ impl ::buffa::DefaultInstance for ExtensionRangeOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for ExtensionRangeOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ExtensionRangeOptions"; + const FULL_NAME: &'static str = "google.protobuf.ExtensionRangeOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ExtensionRangeOptions"; +} impl ::buffa::Message for ExtensionRangeOptions { /// Returns the total encoded size in bytes. /// @@ -3563,6 +3599,12 @@ pub mod extension_range_options { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for Declaration { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ExtensionRangeOptions.Declaration"; + const FULL_NAME: &'static str = "google.protobuf.ExtensionRangeOptions.Declaration"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ExtensionRangeOptions.Declaration"; + } impl ::buffa::Message for Declaration { /// Returns the total encoded size in bytes. /// @@ -4023,6 +4065,12 @@ impl ::buffa::DefaultInstance for FieldDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FieldDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.FieldDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldDescriptorProto"; +} impl ::buffa::Message for FieldDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -4924,6 +4972,12 @@ impl ::buffa::DefaultInstance for OneofDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for OneofDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "OneofDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.OneofDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.OneofDescriptorProto"; +} impl ::buffa::Message for OneofDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -5206,6 +5260,12 @@ impl ::buffa::DefaultInstance for EnumDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for EnumDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.EnumDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumDescriptorProto"; +} impl ::buffa::Message for EnumDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -5607,6 +5667,12 @@ pub mod enum_descriptor_proto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for EnumReservedRange { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumDescriptorProto.EnumReservedRange"; + const FULL_NAME: &'static str = "google.protobuf.EnumDescriptorProto.EnumReservedRange"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumDescriptorProto.EnumReservedRange"; + } impl ::buffa::Message for EnumReservedRange { /// Returns the total encoded size in bytes. /// @@ -5828,6 +5894,12 @@ impl ::buffa::DefaultInstance for EnumValueDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for EnumValueDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumValueDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.EnumValueDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumValueDescriptorProto"; +} impl ::buffa::Message for EnumValueDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -6090,6 +6162,12 @@ impl ::buffa::DefaultInstance for ServiceDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for ServiceDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ServiceDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.ServiceDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ServiceDescriptorProto"; +} impl ::buffa::Message for ServiceDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -6410,6 +6488,12 @@ impl ::buffa::DefaultInstance for MethodDescriptorProto { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for MethodDescriptorProto { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "MethodDescriptorProto"; + const FULL_NAME: &'static str = "google.protobuf.MethodDescriptorProto"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.MethodDescriptorProto"; +} impl ::buffa::Message for MethodDescriptorProto { /// Returns the total encoded size in bytes. /// @@ -7100,6 +7184,12 @@ impl ::buffa::DefaultInstance for FileOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FileOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FileOptions"; + const FULL_NAME: &'static str = "google.protobuf.FileOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FileOptions"; +} impl ::buffa::Message for FileOptions { /// Returns the total encoded size in bytes. /// @@ -8662,6 +8752,12 @@ impl ::buffa::DefaultInstance for MessageOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for MessageOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "MessageOptions"; + const FULL_NAME: &'static str = "google.protobuf.MessageOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.MessageOptions"; +} impl ::buffa::Message for MessageOptions { /// Returns the total encoded size in bytes. /// @@ -9451,6 +9547,12 @@ impl ::buffa::DefaultInstance for FieldOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FieldOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldOptions"; + const FULL_NAME: &'static str = "google.protobuf.FieldOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldOptions"; +} impl ::buffa::Message for FieldOptions { /// Returns the total encoded size in bytes. /// @@ -11110,6 +11212,12 @@ pub mod field_options { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for EditionDefault { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldOptions.EditionDefault"; + const FULL_NAME: &'static str = "google.protobuf.FieldOptions.EditionDefault"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldOptions.EditionDefault"; + } impl ::buffa::Message for EditionDefault { /// Returns the total encoded size in bytes. /// @@ -11383,6 +11491,12 @@ pub mod field_options { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for FeatureSupport { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldOptions.FeatureSupport"; + const FULL_NAME: &'static str = "google.protobuf.FieldOptions.FeatureSupport"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldOptions.FeatureSupport"; + } impl ::buffa::Message for FeatureSupport { /// Returns the total encoded size in bytes. /// @@ -11708,6 +11822,12 @@ impl ::buffa::DefaultInstance for OneofOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for OneofOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "OneofOptions"; + const FULL_NAME: &'static str = "google.protobuf.OneofOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.OneofOptions"; +} impl ::buffa::Message for OneofOptions { /// Returns the total encoded size in bytes. /// @@ -12154,6 +12274,12 @@ impl ::buffa::DefaultInstance for EnumOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for EnumOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumOptions"; + const FULL_NAME: &'static str = "google.protobuf.EnumOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumOptions"; +} impl ::buffa::Message for EnumOptions { /// Returns the total encoded size in bytes. /// @@ -12714,6 +12840,12 @@ impl ::buffa::DefaultInstance for EnumValueOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for EnumValueOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "EnumValueOptions"; + const FULL_NAME: &'static str = "google.protobuf.EnumValueOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.EnumValueOptions"; +} impl ::buffa::Message for EnumValueOptions { /// Returns the total encoded size in bytes. /// @@ -13261,6 +13393,12 @@ impl ::buffa::DefaultInstance for ServiceOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for ServiceOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ServiceOptions"; + const FULL_NAME: &'static str = "google.protobuf.ServiceOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ServiceOptions"; +} impl ::buffa::Message for ServiceOptions { /// Returns the total encoded size in bytes. /// @@ -13728,6 +13866,12 @@ impl ::buffa::DefaultInstance for MethodOptions { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for MethodOptions { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "MethodOptions"; + const FULL_NAME: &'static str = "google.protobuf.MethodOptions"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.MethodOptions"; +} impl ::buffa::Message for MethodOptions { /// Returns the total encoded size in bytes. /// @@ -14441,6 +14585,12 @@ impl ::buffa::DefaultInstance for UninterpretedOption { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for UninterpretedOption { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UninterpretedOption"; + const FULL_NAME: &'static str = "google.protobuf.UninterpretedOption"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UninterpretedOption"; +} impl ::buffa::Message for UninterpretedOption { /// Returns the total encoded size in bytes. /// @@ -14843,6 +14993,12 @@ pub mod uninterpreted_option { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for NamePart { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UninterpretedOption.NamePart"; + const FULL_NAME: &'static str = "google.protobuf.UninterpretedOption.NamePart"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UninterpretedOption.NamePart"; + } impl ::buffa::Message for NamePart { /// Returns the total encoded size in bytes. /// @@ -15131,6 +15287,12 @@ impl ::buffa::DefaultInstance for FeatureSet { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FeatureSet { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSet"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSet"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSet"; +} impl ::buffa::Message for FeatureSet { /// Returns the total encoded size in bytes. /// @@ -16908,6 +17070,12 @@ pub mod feature_set { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for VisibilityFeature { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSet.VisibilityFeature"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSet.VisibilityFeature"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSet.VisibilityFeature"; + } impl ::buffa::Message for VisibilityFeature { /// Returns the total encoded size in bytes. /// @@ -17277,6 +17445,12 @@ impl ::buffa::DefaultInstance for FeatureSetDefaults { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FeatureSetDefaults { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSetDefaults"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSetDefaults"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSetDefaults"; +} impl ::buffa::Message for FeatureSetDefaults { /// Returns the total encoded size in bytes. /// @@ -17579,6 +17753,12 @@ pub mod feature_set_defaults { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for FeatureSetEditionDefault { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FeatureSetDefaults.FeatureSetEditionDefault"; + const FULL_NAME: &'static str = "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault"; + } impl ::buffa::Message for FeatureSetEditionDefault { /// Returns the total encoded size in bytes. /// @@ -17898,6 +18078,12 @@ impl ::buffa::DefaultInstance for SourceCodeInfo { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for SourceCodeInfo { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "SourceCodeInfo"; + const FULL_NAME: &'static str = "google.protobuf.SourceCodeInfo"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.SourceCodeInfo"; +} impl ::buffa::Message for SourceCodeInfo { /// Returns the total encoded size in bytes. /// @@ -18364,6 +18550,12 @@ pub mod source_code_info { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for Location { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "SourceCodeInfo.Location"; + const FULL_NAME: &'static str = "google.protobuf.SourceCodeInfo.Location"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.SourceCodeInfo.Location"; + } impl ::buffa::Message for Location { /// Returns the total encoded size in bytes. /// @@ -18754,6 +18946,12 @@ impl ::buffa::DefaultInstance for GeneratedCodeInfo { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for GeneratedCodeInfo { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "GeneratedCodeInfo"; + const FULL_NAME: &'static str = "google.protobuf.GeneratedCodeInfo"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.GeneratedCodeInfo"; +} impl ::buffa::Message for GeneratedCodeInfo { /// Returns the total encoded size in bytes. /// @@ -19006,6 +19204,12 @@ pub mod generated_code_info { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } + impl ::buffa::MessageName for Annotation { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "GeneratedCodeInfo.Annotation"; + const FULL_NAME: &'static str = "google.protobuf.GeneratedCodeInfo.Annotation"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.GeneratedCodeInfo.Annotation"; + } impl ::buffa::Message for Annotation { /// Returns the total encoded size in bytes. /// diff --git a/buffa-test/src/tests/basic.rs b/buffa-test/src/tests/basic.rs index 9c91fdf..7ff9a17 100644 --- a/buffa-test/src/tests/basic.rs +++ b/buffa-test/src/tests/basic.rs @@ -3,7 +3,43 @@ use super::round_trip; use crate::basic::__buffa::oneof; use crate::basic::*; -use buffa::Message; +use buffa::{Message, MessageName}; + +#[test] +fn test_message_name_consts() { + // Top-level messages: PACKAGE + "." + NAME == FULL_NAME, and TYPE_URL + // is the `Any.type_url` form. The FQNs are observable on the wire (in + // `Any.type_url`, JSON field keys for extensions, registry keys), so + // codegen must keep emitting them verbatim. + assert_eq!(Empty::PACKAGE, "basic"); + assert_eq!(Empty::NAME, "Empty"); + assert_eq!(Empty::FULL_NAME, "basic.Empty"); + assert_eq!(Empty::TYPE_URL, "type.googleapis.com/basic.Empty"); + // The trait const equals the inherent const codegen has emitted since + // 0.4.0 — both come from the same `proto_fqn` source. + assert_eq!(::TYPE_URL, Empty::TYPE_URL); + + assert_eq!(Person::FULL_NAME, "basic.Person"); + assert_eq!(AllScalars::FULL_NAME, "basic.AllScalars"); + + // Nested messages: NAME carries the dotted nesting path while PACKAGE + // stays at the proto package. This is why both consts exist — + // `FULL_NAME` alone can't be split unambiguously. + use crate::nested::outer::middle::Inner; + assert_eq!(Inner::PACKAGE, "test.nested"); + assert_eq!(Inner::NAME, "Outer.Middle.Inner"); + assert_eq!(Inner::FULL_NAME, "test.nested.Outer.Middle.Inner"); + + // The view type implements `MessageName` too — same consts, different + // `Self`, so a generic name-keyed registry can dispatch zero-copy + // views and owned messages identically. + assert_eq!(PersonView::FULL_NAME, Person::FULL_NAME); + assert_eq!(PersonView::TYPE_URL, Person::TYPE_URL); + fn name_of() -> &'static str { + T::FULL_NAME + } + assert_eq!(name_of::(), name_of::>()); +} #[test] fn test_empty_message_encodes_to_zero_bytes() { diff --git a/buffa-types/src/generated/google.protobuf.any.__view.rs b/buffa-types/src/generated/google.protobuf.any.__view.rs index 02aa8cd..addd6c1 100644 --- a/buffa-types/src/generated/google.protobuf.any.__view.rs +++ b/buffa-types/src/generated/google.protobuf.any.__view.rs @@ -281,6 +281,12 @@ impl<'a> ::buffa::ViewEncode<'a> for AnyView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for AnyView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Any"; + const FULL_NAME: &'static str = "google.protobuf.Any"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Any"; +} impl<'v> ::buffa::DefaultViewInstance for AnyView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.any.rs b/buffa-types/src/generated/google.protobuf.any.rs index f9e6b9d..29bf12e 100644 --- a/buffa-types/src/generated/google.protobuf.any.rs +++ b/buffa-types/src/generated/google.protobuf.any.rs @@ -164,6 +164,12 @@ impl ::buffa::DefaultInstance for Any { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Any { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Any"; + const FULL_NAME: &'static str = "google.protobuf.Any"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Any"; +} impl ::buffa::Message for Any { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/generated/google.protobuf.duration.__view.rs b/buffa-types/src/generated/google.protobuf.duration.__view.rs index d174ee2..70fad8c 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__view.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__view.rs @@ -222,6 +222,12 @@ impl<'a> ::buffa::ViewEncode<'a> for DurationView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for DurationView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Duration"; + const FULL_NAME: &'static str = "google.protobuf.Duration"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Duration"; +} impl<'v> ::buffa::DefaultViewInstance for DurationView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.duration.rs b/buffa-types/src/generated/google.protobuf.duration.rs index 793792b..ad7fd48 100644 --- a/buffa-types/src/generated/google.protobuf.duration.rs +++ b/buffa-types/src/generated/google.protobuf.duration.rs @@ -107,6 +107,12 @@ impl ::buffa::DefaultInstance for Duration { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Duration { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Duration"; + const FULL_NAME: &'static str = "google.protobuf.Duration"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Duration"; +} impl ::buffa::Message for Duration { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/generated/google.protobuf.empty.__view.rs b/buffa-types/src/generated/google.protobuf.empty.__view.rs index ab39221..efba066 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__view.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__view.rs @@ -114,6 +114,12 @@ impl<'a> ::buffa::ViewEncode<'a> for EmptyView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for EmptyView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Empty"; + const FULL_NAME: &'static str = "google.protobuf.Empty"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Empty"; +} impl<'v> ::buffa::DefaultViewInstance for EmptyView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.empty.rs b/buffa-types/src/generated/google.protobuf.empty.rs index af554f5..d546cbc 100644 --- a/buffa-types/src/generated/google.protobuf.empty.rs +++ b/buffa-types/src/generated/google.protobuf.empty.rs @@ -34,6 +34,12 @@ impl ::buffa::DefaultInstance for Empty { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Empty { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Empty"; + const FULL_NAME: &'static str = "google.protobuf.Empty"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Empty"; +} impl ::buffa::Message for Empty { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs index b6f0bce..a39dba1 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs @@ -354,6 +354,12 @@ impl<'a> ::buffa::ViewEncode<'a> for FieldMaskView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for FieldMaskView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldMask"; + const FULL_NAME: &'static str = "google.protobuf.FieldMask"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldMask"; +} impl<'v> ::buffa::DefaultViewInstance for FieldMaskView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.field_mask.rs b/buffa-types/src/generated/google.protobuf.field_mask.rs index 062dd7c..b562721 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.rs @@ -252,6 +252,12 @@ impl ::buffa::DefaultInstance for FieldMask { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FieldMask { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FieldMask"; + const FULL_NAME: &'static str = "google.protobuf.FieldMask"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FieldMask"; +} impl ::buffa::Message for FieldMask { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/generated/google.protobuf.struct.__view.rs b/buffa-types/src/generated/google.protobuf.struct.__view.rs index 7adb630..ac264dc 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view.rs @@ -222,6 +222,12 @@ impl<'a> ::buffa::ViewEncode<'a> for StructView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for StructView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Struct"; + const FULL_NAME: &'static str = "google.protobuf.Struct"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Struct"; +} impl<'v> ::buffa::DefaultViewInstance for StructView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -594,6 +600,12 @@ impl<'a> ::buffa::ViewEncode<'a> for ValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for ValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Value"; + const FULL_NAME: &'static str = "google.protobuf.Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Value"; +} impl<'v> ::buffa::DefaultViewInstance for ValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -765,6 +777,12 @@ impl<'a> ::buffa::ViewEncode<'a> for ListValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for ListValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ListValue"; + const FULL_NAME: &'static str = "google.protobuf.ListValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ListValue"; +} impl<'v> ::buffa::DefaultViewInstance for ListValueView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.struct.rs b/buffa-types/src/generated/google.protobuf.struct.rs index f4eaca3..d35f48a 100644 --- a/buffa-types/src/generated/google.protobuf.struct.rs +++ b/buffa-types/src/generated/google.protobuf.struct.rs @@ -78,6 +78,12 @@ impl ::buffa::DefaultInstance for Struct { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Struct { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Struct"; + const FULL_NAME: &'static str = "google.protobuf.Struct"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Struct"; +} impl ::buffa::Message for Struct { /// Returns the total encoded size in bytes. /// @@ -349,6 +355,12 @@ impl ::buffa::DefaultInstance for Value { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Value { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Value"; + const FULL_NAME: &'static str = "google.protobuf.Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Value"; +} impl ::buffa::Message for Value { /// Returns the total encoded size in bytes. /// @@ -760,6 +772,12 @@ impl ::buffa::DefaultInstance for ListValue { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for ListValue { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "ListValue"; + const FULL_NAME: &'static str = "google.protobuf.ListValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.ListValue"; +} impl ::buffa::Message for ListValue { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs index 22de12e..f3f0e6e 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs @@ -257,6 +257,12 @@ impl<'a> ::buffa::ViewEncode<'a> for TimestampView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for TimestampView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Timestamp"; + const FULL_NAME: &'static str = "google.protobuf.Timestamp"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Timestamp"; +} impl<'v> ::buffa::DefaultViewInstance for TimestampView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.timestamp.rs b/buffa-types/src/generated/google.protobuf.timestamp.rs index db64a11..2c5101f 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.rs @@ -142,6 +142,12 @@ impl ::buffa::DefaultInstance for Timestamp { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Timestamp { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Timestamp"; + const FULL_NAME: &'static str = "google.protobuf.Timestamp"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Timestamp"; +} impl ::buffa::Message for Timestamp { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs index 2d25eb2..e9a8be4 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs @@ -131,6 +131,12 @@ impl<'a> ::buffa::ViewEncode<'a> for DoubleValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for DoubleValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DoubleValue"; + const FULL_NAME: &'static str = "google.protobuf.DoubleValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DoubleValue"; +} impl<'v> ::buffa::DefaultViewInstance for DoubleValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -279,6 +285,12 @@ impl<'a> ::buffa::ViewEncode<'a> for FloatValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for FloatValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FloatValue"; + const FULL_NAME: &'static str = "google.protobuf.FloatValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FloatValue"; +} impl<'v> ::buffa::DefaultViewInstance for FloatValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -427,6 +439,12 @@ impl<'a> ::buffa::ViewEncode<'a> for Int64ValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for Int64ValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Int64Value"; + const FULL_NAME: &'static str = "google.protobuf.Int64Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Int64Value"; +} impl<'v> ::buffa::DefaultViewInstance for Int64ValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -575,6 +593,12 @@ impl<'a> ::buffa::ViewEncode<'a> for UInt64ValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for UInt64ValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UInt64Value"; + const FULL_NAME: &'static str = "google.protobuf.UInt64Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UInt64Value"; +} impl<'v> ::buffa::DefaultViewInstance for UInt64ValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -723,6 +747,12 @@ impl<'a> ::buffa::ViewEncode<'a> for Int32ValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for Int32ValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Int32Value"; + const FULL_NAME: &'static str = "google.protobuf.Int32Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Int32Value"; +} impl<'v> ::buffa::DefaultViewInstance for Int32ValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -871,6 +901,12 @@ impl<'a> ::buffa::ViewEncode<'a> for UInt32ValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for UInt32ValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UInt32Value"; + const FULL_NAME: &'static str = "google.protobuf.UInt32Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UInt32Value"; +} impl<'v> ::buffa::DefaultViewInstance for UInt32ValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1019,6 +1055,12 @@ impl<'a> ::buffa::ViewEncode<'a> for BoolValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for BoolValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "BoolValue"; + const FULL_NAME: &'static str = "google.protobuf.BoolValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.BoolValue"; +} impl<'v> ::buffa::DefaultViewInstance for BoolValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1170,6 +1212,12 @@ impl<'a> ::buffa::ViewEncode<'a> for StringValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for StringValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "StringValue"; + const FULL_NAME: &'static str = "google.protobuf.StringValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.StringValue"; +} impl<'v> ::buffa::DefaultViewInstance for StringValueView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -1321,6 +1369,12 @@ impl<'a> ::buffa::ViewEncode<'a> for BytesValueView<'a> { self.__buffa_unknown_fields.write_to(buf); } } +impl<'a> ::buffa::MessageName for BytesValueView<'a> { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "BytesValue"; + const FULL_NAME: &'static str = "google.protobuf.BytesValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.BytesValue"; +} impl<'v> ::buffa::DefaultViewInstance for BytesValueView<'v> { fn default_view_instance<'a>() -> &'a Self where diff --git a/buffa-types/src/generated/google.protobuf.wrappers.rs b/buffa-types/src/generated/google.protobuf.wrappers.rs index 6aceba3..19f0d8a 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.rs @@ -32,6 +32,12 @@ impl ::buffa::DefaultInstance for DoubleValue { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for DoubleValue { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "DoubleValue"; + const FULL_NAME: &'static str = "google.protobuf.DoubleValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.DoubleValue"; +} impl ::buffa::Message for DoubleValue { /// Returns the total encoded size in bytes. /// @@ -171,6 +177,12 @@ impl ::buffa::DefaultInstance for FloatValue { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for FloatValue { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "FloatValue"; + const FULL_NAME: &'static str = "google.protobuf.FloatValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.FloatValue"; +} impl ::buffa::Message for FloatValue { /// Returns the total encoded size in bytes. /// @@ -310,6 +322,12 @@ impl ::buffa::DefaultInstance for Int64Value { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Int64Value { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Int64Value"; + const FULL_NAME: &'static str = "google.protobuf.Int64Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Int64Value"; +} impl ::buffa::Message for Int64Value { /// Returns the total encoded size in bytes. /// @@ -449,6 +467,12 @@ impl ::buffa::DefaultInstance for UInt64Value { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for UInt64Value { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UInt64Value"; + const FULL_NAME: &'static str = "google.protobuf.UInt64Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UInt64Value"; +} impl ::buffa::Message for UInt64Value { /// Returns the total encoded size in bytes. /// @@ -588,6 +612,12 @@ impl ::buffa::DefaultInstance for Int32Value { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Int32Value { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "Int32Value"; + const FULL_NAME: &'static str = "google.protobuf.Int32Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.Int32Value"; +} impl ::buffa::Message for Int32Value { /// Returns the total encoded size in bytes. /// @@ -727,6 +757,12 @@ impl ::buffa::DefaultInstance for UInt32Value { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for UInt32Value { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "UInt32Value"; + const FULL_NAME: &'static str = "google.protobuf.UInt32Value"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.UInt32Value"; +} impl ::buffa::Message for UInt32Value { /// Returns the total encoded size in bytes. /// @@ -866,6 +902,12 @@ impl ::buffa::DefaultInstance for BoolValue { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for BoolValue { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "BoolValue"; + const FULL_NAME: &'static str = "google.protobuf.BoolValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.BoolValue"; +} impl ::buffa::Message for BoolValue { /// Returns the total encoded size in bytes. /// @@ -1005,6 +1047,12 @@ impl ::buffa::DefaultInstance for StringValue { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for StringValue { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "StringValue"; + const FULL_NAME: &'static str = "google.protobuf.StringValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.StringValue"; +} impl ::buffa::Message for StringValue { /// Returns the total encoded size in bytes. /// @@ -1147,6 +1195,12 @@ impl ::buffa::DefaultInstance for BytesValue { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for BytesValue { + const PACKAGE: &'static str = "google.protobuf"; + const NAME: &'static str = "BytesValue"; + const FULL_NAME: &'static str = "google.protobuf.BytesValue"; + const TYPE_URL: &'static str = "type.googleapis.com/google.protobuf.BytesValue"; +} impl ::buffa::Message for BytesValue { /// Returns the total encoded size in bytes. /// diff --git a/buffa-types/src/lib.rs b/buffa-types/src/lib.rs index 06d8391..69b4f71 100644 --- a/buffa-types/src/lib.rs +++ b/buffa-types/src/lib.rs @@ -89,3 +89,24 @@ pub use timestamp_ext::TimestampError; // Re-export the WKT registry function for `Any` JSON + text support. pub use any_ext::register_wkt_types; + +#[cfg(test)] +mod full_name_tests { + use super::google::protobuf::*; + use buffa::MessageName; + + // Regression test: the WKT FQNs are baked into Any type-URLs, JSON + // serialization, and the type registry. Codegen must keep emitting them + // verbatim — these strings are observable on the wire. + #[test] + fn well_known_types_full_names_match_proto() { + assert_eq!(Timestamp::FULL_NAME, "google.protobuf.Timestamp"); + assert_eq!(Duration::FULL_NAME, "google.protobuf.Duration"); + assert_eq!(Any::FULL_NAME, "google.protobuf.Any"); + assert_eq!(Empty::FULL_NAME, "google.protobuf.Empty"); + assert_eq!(FieldMask::FULL_NAME, "google.protobuf.FieldMask"); + assert_eq!(Struct::FULL_NAME, "google.protobuf.Struct"); + assert_eq!(Value::FULL_NAME, "google.protobuf.Value"); + assert_eq!(ListValue::FULL_NAME, "google.protobuf.ListValue"); + } +} diff --git a/buffa/src/extension.rs b/buffa/src/extension.rs index d6643c1..f914dfc 100644 --- a/buffa/src/extension.rs +++ b/buffa/src/extension.rs @@ -215,6 +215,18 @@ pub trait ExtensionSet { /// Checked against [`Extension::extendee`] on every `extension()`, /// `set_extension()`, and `clear_extension()` call. A mismatch panics: /// passing an extension for the wrong message is a bug in the caller. + /// + /// Equal to [`MessageName::FULL_NAME`](crate::MessageName::FULL_NAME) + /// for generated messages — both come from the same `proto_fqn` in + /// codegen. Hand-written impls that implement both traits must keep the + /// two strings in sync; a mismatch surfaces as a runtime panic on + /// extension access rather than at compile time. + /// + /// If you only need the message's full name (no extension access), prefer + /// [`MessageName::FULL_NAME`](crate::MessageName::FULL_NAME): it + /// is a standalone trait that doesn't require the extension machinery or + /// the `unknown_fields=true` codegen option (which adds an + /// `__buffa_unknown_fields` storage field to the generated struct). const PROTO_FQN: &'static str; /// Immutable access to the extendee's unknown-field storage. diff --git a/buffa/src/lib.rs b/buffa/src/lib.rs index 96ca6b5..4241434 100644 --- a/buffa/src/lib.rs +++ b/buffa/src/lib.rs @@ -83,6 +83,7 @@ //! | Type | Purpose | //! |------|---------| //! | [`Message`] | Core trait for encode / decode / merge | +//! | [`MessageName`] | Compile-time `FULL_NAME` const (`"pkg.Msg"`) for generic dispatch | //! | [`DecodeOptions`] | Configurable recursion and size limits | //! | [`MessageField`](MessageField) | Optional sub-message with transparent `Deref` to default | //! | [`EnumValue`](EnumValue) | Open enum wrapper (`Known(E)` / `Unknown(i32)`) | @@ -213,7 +214,7 @@ pub mod view; pub use enumeration::{EnumValue, Enumeration}; pub use error::{DecodeError, EncodeError}; pub use extension::{Extension, ExtensionCodec, ExtensionSet}; -pub use message::{DecodeOptions, Message, RECURSION_LIMIT}; +pub use message::{DecodeOptions, Message, MessageName, RECURSION_LIMIT}; pub use message_field::{DefaultInstance, MessageField}; pub use oneof::Oneof; pub use size_cache::SizeCache; diff --git a/buffa/src/message.rs b/buffa/src/message.rs index 248b7fb..006ba12 100644 --- a/buffa/src/message.rs +++ b/buffa/src/message.rs @@ -417,6 +417,99 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { fn clear(&mut self); } +/// Compile-time access to a generated message's protobuf identifiers. +/// +/// Generic code that needs to *name* a message type — type-erased event +/// registries, structured logging, `Any` packing, schema lookups — can +/// bound on `T: MessageName` and read [`PACKAGE`], [`NAME`], +/// [`FULL_NAME`], or [`TYPE_URL`] without descriptor machinery or runtime +/// reflection. All four are `&'static str` literals computed at codegen +/// time, so there's no allocation or concatenation at runtime — unlike +/// `prost::Name`, whose `full_name()` and `type_url()` are runtime +/// `format!` calls. +/// +/// Bring `buffa::MessageName` into scope to use `MyMessage::FULL_NAME`. +/// Without the trait in scope, use +/// `::FULL_NAME`. +/// +/// Codegen implements `MessageName` for both the owned message type and +/// its zero-copy view type (`MyMessageView<'a>`), so the same generic +/// bound dispatches either. The trait has **no** [`Message`] supertrait — +/// it doesn't reach into the wire codec and a name-keyed registry should +/// be able to register a type without proving it can encode. +/// +/// Hand-written [`Message`] implementations can opt in by also +/// implementing `MessageName`; it is a separate trait specifically so +/// that omitting it stays non-breaking. For messages that also implement +/// [`ExtensionSet`](crate::ExtensionSet), [`FULL_NAME`] is guaranteed +/// equal to [`ExtensionSet::PROTO_FQN`](crate::ExtensionSet::PROTO_FQN); +/// the inherent `MyMessage::TYPE_URL` const is equal to [`TYPE_URL`]. +/// All derive from the same `proto_fqn` source in codegen. +/// +/// Because the only items are associated `const`s, this trait is **not** +/// object-safe (`dyn MessageName` does not compile). Use it as a generic +/// bound (`fn foo()`), not a trait object. +/// +/// ``` +/// # use buffa::MessageName; +/// /// A name-keyed registry can register any `MessageName` type — owned +/// /// or view — without proving it can encode. +/// fn registry_key() -> &'static str { +/// T::FULL_NAME +/// } +/// # // No generated types in `buffa` itself; just check it monomorphises. +/// # struct Demo; +/// # impl MessageName for Demo { +/// # const PACKAGE: &'static str = "demo"; +/// # const NAME: &'static str = "Demo"; +/// # const FULL_NAME: &'static str = "demo.Demo"; +/// # const TYPE_URL: &'static str = "type.googleapis.com/demo.Demo"; +/// # } +/// assert_eq!(registry_key::(), "demo.Demo"); +/// ``` +/// +/// [`PACKAGE`]: Self::PACKAGE +/// [`NAME`]: Self::NAME +/// [`FULL_NAME`]: Self::FULL_NAME +/// [`TYPE_URL`]: Self::TYPE_URL +pub trait MessageName { + /// The protobuf package the message is declared in. + /// + /// `"my.pkg"` for `package my.pkg;`. Empty string for the unnamed + /// root package. Does not include a leading or trailing dot. + const PACKAGE: &'static str; + + /// The unqualified message name, with `.` between nesting levels. + /// + /// `"Foo"` for a top-level message; `"Outer.Inner"` for a message + /// nested inside `Outer`. This is the "type name relative to the + /// package" — what `prost::Name::NAME` calls the same thing — *not* + /// `DescriptorProto.name`, which is only the leaf segment (`"Inner"`) + /// for nested types. + const NAME: &'static str; + + /// The fully-qualified protobuf type name with no leading dot. + /// + /// `"my.pkg.Outer.Inner"` for a nested message in package `my.pkg`, + /// or just `"Foo"` for a top-level message in the unnamed root + /// package. Equal to `PACKAGE` + `"."` + `NAME` (with the joining + /// dot omitted when `PACKAGE` is empty); shipped as its own const + /// because consumers almost always want the joined form and the + /// dotted string can't be re-split unambiguously + /// (`foo.Bar.Baz` could be package `foo.Bar` + message `Baz`, or + /// package `foo` + nested `Bar.Baz`). + const FULL_NAME: &'static str; + + /// The `google.protobuf.Any.type_url` form for this message. + /// + /// `"type.googleapis.com/" + FULL_NAME`. This is the value the + /// runtime stores in [`Any::type_url`] when packing a message, and + /// the one a generic `Any` registry should key on. + /// + /// [`Any::type_url`]: https://protobuf.dev/programming-guides/proto3/#any + const TYPE_URL: &'static str; +} + /// Options for configuring message decoding behavior. /// /// Use this to set custom recursion depth limits or maximum message sizes diff --git a/docs/guide.md b/docs/guide.md index 6c0303a..2360ea2 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1666,6 +1666,16 @@ Note what's *not* needed: - **`UnknownFields`** — omitted since this is a simple leaf type where round-trip preservation of unknown fields isn't important. Unknown tags are silently skipped via `skip_field`. - **Any size-caching field** — sizes live in the external `SizeCache` threaded through `compute_size` / `write_to`. A leaf type like this doesn't touch the cache; types with nested message fields reserve a slot before recursing (see the `compute_size` comment above). +- **`MessageName`** — opt-in. Implement it on your extern-mapped type if you have generic code that dispatches on `T::FULL_NAME`, `T::TYPE_URL`, etc. (event stores, type-erased registries, `Any` packing); otherwise leave it off. The trait has no `Message` supertrait, so it's also implementable on types that don't (or can't) participate in the wire codec: + + ```rust,ignore + impl buffa::MessageName for Int64Range { + const PACKAGE: &'static str = "my.common"; + const NAME: &'static str = "Int64Range"; + const FULL_NAME: &'static str = "my.common.Int64Range"; + const TYPE_URL: &'static str = "type.googleapis.com/my.common.Int64Range"; + } + ``` ### View types for custom implementations diff --git a/docs/migration-from-prost.md b/docs/migration-from-prost.md index 247e86e..ce38c63 100644 --- a/docs/migration-from-prost.md +++ b/docs/migration-from-prost.md @@ -284,7 +284,7 @@ Features that prost supports but buffa does not (yet): | `field_attribute(path, attr)` | Not supported. | | `service_generator(...)` | Not supported. Services codegen is planned. | | `#[derive(prost::Message)]` | Not provided. Implement `Message` by hand and use `extern_path` (see [Custom types](guide.md#custom-type-implementations)). | -| `prost::Name` trait | Not supported. The generated `TYPE_URL` associated constant covers the common case (`Any` packing/unpacking). | +| `prost::Name` trait | `buffa::MessageName` — same shape (`PACKAGE`, `NAME`, plus `FULL_NAME` and `TYPE_URL`), but all four are `&'static str` consts computed at codegen time rather than runtime `format!` calls. Replace `M::full_name()` with `M::FULL_NAME` and `M::type_url()` with `M::TYPE_URL`. Implemented for both owned messages and view types. | Features that buffa has but prost does not: diff --git a/examples/logging/Cargo.lock b/examples/logging/Cargo.lock index e273801..066a87f 100644 --- a/examples/logging/Cargo.lock +++ b/examples/logging/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "buffa" -version = "0.5.0" +version = "0.5.2" dependencies = [ "bytes", "hashbrown", @@ -16,7 +16,7 @@ dependencies = [ [[package]] name = "buffa-types" -version = "0.5.0" +version = "0.5.2" dependencies = [ "buffa", "bytes", diff --git a/examples/logging/src/gen/context.v1.context.rs b/examples/logging/src/gen/context.v1.context.rs index 3077f2e..5d3b33f 100644 --- a/examples/logging/src/gen/context.v1.context.rs +++ b/examples/logging/src/gen/context.v1.context.rs @@ -54,6 +54,12 @@ impl ::buffa::DefaultInstance for RequestContext { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for RequestContext { + const PACKAGE: &'static str = "buffa.examples.context.v1"; + const NAME: &'static str = "RequestContext"; + const FULL_NAME: &'static str = "buffa.examples.context.v1.RequestContext"; + const TYPE_URL: &'static str = "type.googleapis.com/buffa.examples.context.v1.RequestContext"; +} impl ::buffa::Message for RequestContext { /// Returns the total encoded size in bytes. /// diff --git a/examples/logging/src/gen/log.v1.log.rs b/examples/logging/src/gen/log.v1.log.rs index 0366f70..40b42ff 100644 --- a/examples/logging/src/gen/log.v1.log.rs +++ b/examples/logging/src/gen/log.v1.log.rs @@ -124,6 +124,12 @@ impl ::buffa::DefaultInstance for LogEntry { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for LogEntry { + const PACKAGE: &'static str = "buffa.examples.log.v1"; + const NAME: &'static str = "LogEntry"; + const FULL_NAME: &'static str = "buffa.examples.log.v1.LogEntry"; + const TYPE_URL: &'static str = "type.googleapis.com/buffa.examples.log.v1.LogEntry"; +} impl ::buffa::Message for LogEntry { /// Returns the total encoded size in bytes. /// @@ -433,6 +439,12 @@ impl ::buffa::DefaultInstance for LogBatch { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for LogBatch { + const PACKAGE: &'static str = "buffa.examples.log.v1"; + const NAME: &'static str = "LogBatch"; + const FULL_NAME: &'static str = "buffa.examples.log.v1.LogBatch"; + const TYPE_URL: &'static str = "type.googleapis.com/buffa.examples.log.v1.LogBatch"; +} impl ::buffa::Message for LogBatch { /// Returns the total encoded size in bytes. ///