From 9d5b695e25b5f871c6669e75ec074a6aeebf2dda Mon Sep 17 00:00:00 2001 From: Ryan Brewster Date: Thu, 23 Apr 2026 19:33:17 +0000 Subject: [PATCH 1/6] codegen: namespace ancillary types under buffa_:: sentinel + per-package .mod.rs stitcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Views, oneof enums, file-level extensions, and register_types() now live under a single reserved `buffa_::` module per package instead of being interleaved with owned types. Oneof enums drop the Oneof/View suffix (tree position disambiguates); ViewNameConflict and OneofNameConflict are gone — collisions with proto names are structurally impossible. The sentinel is the only name reserved in user namespace and is checked. Each .proto emits five content files; each package emits one `.mod.rs` stitcher that authors `pub mod buffa_ { ... }` and include!s the content files. Consumers wire up only the stitcher via `buffa::include_proto!("pkg")`. register_types is now naturally one fn per package, fixing the multi-file-same-package collision (e.g. seven WKT files in google.protobuf). Regenerated WKT/bootstrap/logging-example output; migrated all in-repo consumers (buffa-test, conformance, examples, benchmarks, packaging plugin, googleapis stress). --- DESIGN.md | 46 + benchmarks/buffa/benches/protobuf.rs | 4 +- benchmarks/buffa/src/lib.rs | 6 +- benchmarks/gen-datasets/src/main.rs | 6 +- buffa-build/src/lib.rs | 25 +- buffa-codegen/src/bin/gen_wkt_types.rs | 11 +- buffa-codegen/src/context.rs | 229 ++++- buffa-codegen/src/impl_message.rs | 9 +- buffa-codegen/src/impl_text.rs | 16 +- buffa-codegen/src/lib.rs | 452 ++++++--- buffa-codegen/src/message.rs | 177 ++-- buffa-codegen/src/oneof.rs | 107 +- buffa-codegen/src/tests/comments.rs | 10 +- buffa-codegen/src/tests/custom_attributes.rs | 30 +- buffa-codegen/src/tests/generation.rs | 115 ++- buffa-codegen/src/tests/json_codegen.rs | 36 +- buffa-codegen/src/tests/mod.rs | 12 + buffa-codegen/src/tests/naming.rs | 386 ++----- buffa-codegen/src/tests/proto2.rs | 10 +- buffa-codegen/src/tests/view_codegen.rs | 20 +- buffa-codegen/src/view.rs | 214 ++-- buffa-codegen/tests/codegen_integration.rs | 34 +- .../generated/google.protobuf.compiler.mod.rs | 15 + .../google.protobuf.compiler.plugin.__ext.rs | 3 + ...google.protobuf.compiler.plugin.__oneof.rs | 3 + .../google.protobuf.compiler.plugin.__view.rs | 3 + ...e.protobuf.compiler.plugin.__view_oneof.rs | 3 + .../google.protobuf.descriptor.__ext.rs | 3 + .../google.protobuf.descriptor.__oneof.rs | 3 + .../google.protobuf.descriptor.__view.rs | 3 + ...google.protobuf.descriptor.__view_oneof.rs | 3 + .../src/generated/google.protobuf.mod.rs | 15 + buffa-descriptor/src/generated/mod.rs | 4 +- buffa-test/src/lib.rs | 44 +- buffa-test/src/tests/basic.rs | 9 +- buffa-test/src/tests/bytes_type.rs | 7 +- buffa-test/src/tests/closed_enum.rs | 13 +- buffa-test/src/tests/collision.rs | 16 +- buffa-test/src/tests/extensions.rs | 10 +- buffa-test/src/tests/extensions_json.rs | 6 +- buffa-test/src/tests/json.rs | 15 +- buffa-test/src/tests/keyword.rs | 8 +- buffa-test/src/tests/message_set.rs | 3 +- buffa-test/src/tests/nesting.rs | 109 +- buffa-test/src/tests/proto2.rs | 18 +- buffa-test/src/tests/proto3_semantics.rs | 14 +- buffa-test/src/tests/textproto.rs | 22 +- buffa-test/src/tests/utf8_validation.rs | 6 +- buffa-test/src/tests/view.rs | 15 +- buffa-test/src/tests/wkt.rs | 16 +- .../generated/google.protobuf.any.__ext.rs | 3 + .../generated/google.protobuf.any.__oneof.rs | 3 + .../generated/google.protobuf.any.__view.rs | 244 +++++ .../google.protobuf.any.__view_oneof.rs | 3 + .../src/generated/google.protobuf.any.rs | 241 ----- .../google.protobuf.duration.__ext.rs | 3 + .../google.protobuf.duration.__oneof.rs | 3 + .../google.protobuf.duration.__view.rs | 191 ++++ .../google.protobuf.duration.__view_oneof.rs | 3 + .../src/generated/google.protobuf.duration.rs | 188 ---- .../generated/google.protobuf.empty.__ext.rs | 3 + .../google.protobuf.empty.__oneof.rs | 3 + .../generated/google.protobuf.empty.__view.rs | 99 ++ .../google.protobuf.empty.__view_oneof.rs | 3 + .../src/generated/google.protobuf.empty.rs | 96 -- .../google.protobuf.field_mask.__ext.rs | 3 + .../google.protobuf.field_mask.__oneof.rs | 3 + .../google.protobuf.field_mask.__view.rs | 328 ++++++ ...google.protobuf.field_mask.__view_oneof.rs | 3 + .../generated/google.protobuf.field_mask.rs | 325 ------ .../src/generated/google.protobuf.mod.rs | 53 + .../generated/google.protobuf.struct.__ext.rs | 3 + .../google.protobuf.struct.__oneof.rs | 39 + .../google.protobuf.struct.__view.rs | 524 ++++++++++ .../google.protobuf.struct.__view_oneof.rs | 24 + .../src/generated/google.protobuf.struct.rs | 619 +----------- .../google.protobuf.timestamp.__ext.rs | 3 + .../google.protobuf.timestamp.__oneof.rs | 3 + .../google.protobuf.timestamp.__view.rs | 226 +++++ .../google.protobuf.timestamp.__view_oneof.rs | 3 + .../generated/google.protobuf.timestamp.rs | 223 ---- .../google.protobuf.wrappers.__ext.rs | 3 + .../google.protobuf.wrappers.__oneof.rs | 3 + .../google.protobuf.wrappers.__view.rs | 948 ++++++++++++++++++ .../google.protobuf.wrappers.__view_oneof.rs | 3 + .../src/generated/google.protobuf.wrappers.rs | 945 ----------------- buffa-types/src/lib.rs | 8 +- buffa-types/src/timestamp_ext.rs | 3 +- buffa-types/src/value_ext.rs | 3 +- buffa-types/tests/wkt_roundtrip.rs | 17 +- buffa/src/lib.rs | 37 + conformance/Cargo.lock | 11 +- conformance/src/main.rs | 43 +- examples/addressbook/Cargo.lock | 1 + examples/addressbook/src/main.rs | 3 +- examples/envelope/Cargo.lock | 14 +- examples/envelope/src/main.rs | 12 +- examples/logging/Cargo.lock | 5 +- .../src/gen/buffa.examples.context.v1.mod.rs | 15 + .../src/gen/buffa.examples.log.v1.mod.rs | 15 + .../src/gen/context.v1.context.__ext.rs | 3 + .../src/gen/context.v1.context.__oneof.rs | 3 + .../src/gen/context.v1.context.__view.rs | 3 + .../gen/context.v1.context.__view_oneof.rs | 3 + examples/logging/src/gen/log.v1.log.__ext.rs | 3 + .../logging/src/gen/log.v1.log.__oneof.rs | 3 + examples/logging/src/gen/log.v1.log.__view.rs | 3 + .../src/gen/log.v1.log.__view_oneof.rs | 3 + examples/logging/src/gen/log.v1.log.rs | 10 + examples/logging/src/gen/mod.rs | 4 +- protoc-gen-buffa-packaging/src/main.rs | 52 +- stress/googleapis/gen_lib_rs.py | 14 +- 112 files changed, 4362 insertions(+), 3643 deletions(-) create mode 100644 buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs create mode 100644 buffa-descriptor/src/generated/google.protobuf.mod.rs create mode 100644 buffa-types/src/generated/google.protobuf.any.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.any.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.any.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.any.__view_oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.duration.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.duration.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.duration.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.empty.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.empty.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.empty.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.field_mask.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.field_mask.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.mod.rs create mode 100644 buffa-types/src/generated/google.protobuf.struct.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.struct.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.struct.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.timestamp.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.timestamp.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.wrappers.__ext.rs create mode 100644 buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs create mode 100644 buffa-types/src/generated/google.protobuf.wrappers.__view.rs create mode 100644 buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs create mode 100644 examples/logging/src/gen/buffa.examples.context.v1.mod.rs create mode 100644 examples/logging/src/gen/buffa.examples.log.v1.mod.rs create mode 100644 examples/logging/src/gen/context.v1.context.__ext.rs create mode 100644 examples/logging/src/gen/context.v1.context.__oneof.rs create mode 100644 examples/logging/src/gen/context.v1.context.__view.rs create mode 100644 examples/logging/src/gen/context.v1.context.__view_oneof.rs create mode 100644 examples/logging/src/gen/log.v1.log.__ext.rs create mode 100644 examples/logging/src/gen/log.v1.log.__oneof.rs create mode 100644 examples/logging/src/gen/log.v1.log.__view.rs create mode 100644 examples/logging/src/gen/log.v1.log.__view_oneof.rs diff --git a/DESIGN.md b/DESIGN.md index d362e58..3d8a0b2 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -225,6 +225,52 @@ let view = OwnedView::::decode(bytes)?; println!("name: {}", view.name); // Deref, zero-copy, 'static + Send ``` +**Generated code layout — the `buffa_::` sentinel tree:** + +Ancillary generated items (views, oneof enums, file-level extensions, the per-package `register_types` fn) live under a single reserved module per package — `buffa_::` — instead of being interleaved with owned types. The sentinel is the **only** name buffa reserves in user namespace; codegen errors with `ReservedModuleName` if a proto package segment or message name would snake_case to `buffa_`. + +```text +::Foo # owned struct (unchanged) +::foo::Bar # nested owned (unchanged) +::buffa_::view::FooView<'a> # view struct +::buffa_::view::foo::BarView<'a> # nested view (mirrors owned tree) +::buffa_::view::oneof::foo::Kind<'a> # view oneof enum (no suffix) +::buffa_::oneof::foo::Kind # owned oneof enum (no suffix) +::buffa_::ext::MY_EXT # file-level extension const +::buffa_::register_types(…) # one fn per package +``` + +Oneof and view-oneof enums drop the `Oneof`/`View` suffix — the tree position disambiguates. View structs keep the `View` suffix because owned and view types are routinely co-imported (`use pkg::{Foo, buffa_::view::FooView}`). + +This makes name collisions **structurally impossible**: a oneof `kind` and a nested message `Kind` can coexist because they land in different trees. There is no suffix-escalation or rename escape hatch; codegen emits proto names verbatim. + +**File layout — five content files + one stitcher:** + +Each `.proto` emits five sibling content files into `OUT_DIR`: + +| File | Contents | +|---------------------------|-------------------------------------------| +| `.rs` | Owned structs, enums, nested extensions | +| `.__view.rs` | View structs | +| `.__oneof.rs` | Owned oneof enums | +| `.__view_oneof.rs` | View oneof enums | +| `.__ext.rs` | File-level extension consts | + +Each proto **package** additionally emits one `.mod.rs` stitcher that `include!`s the content files and authors the `pub mod buffa_ { … }` wrapper. Consumers wire up only the stitcher: + +```rust,ignore +pub mod my_pkg { + buffa::include_proto!("my.pkg"); // → include!(OUT_DIR/my.pkg.mod.rs) +} +``` + +`buffa::include_proto_relative!("dir", "my.pkg")` does the same for checked-in generated code (no `OUT_DIR`). `buffa-build`'s `_include.rs` and `protoc-gen-buffa-packaging` both emit module trees that reference only the stitchers. + +The per-proto content files mean editing one `.proto` regenerates only its five siblings (incremental friendly); the per-package stitcher means `register_types` is naturally one fn per package, so multi-file packages (e.g. seven WKT files in `google.protobuf`) no longer collide. + + + ### 3. MessageField\ — Ergonomic Optional Messages Prost uses `Option>` for optional message fields, which creates unwrapping ceremony everywhere: diff --git a/benchmarks/buffa/benches/protobuf.rs b/benchmarks/buffa/benches/protobuf.rs index 3394106..4f2693e 100644 --- a/benchmarks/buffa/benches/protobuf.rs +++ b/benchmarks/buffa/benches/protobuf.rs @@ -2,8 +2,10 @@ use buffa::{Message, MessageView}; use criterion::{criterion_group, criterion_main, Criterion, Throughput}; use serde::{de::DeserializeOwned, Serialize}; +use bench_buffa::bench::buffa_::view::*; use bench_buffa::bench::*; use bench_buffa::benchmarks::BenchmarkDataset; +use bench_buffa::proto3::buffa_::view::GoogleMessage1View; fn load_dataset(data: &[u8]) -> BenchmarkDataset { BenchmarkDataset::decode_from_slice(data).expect("failed to decode dataset") @@ -180,7 +182,7 @@ fn bench_google_message1_view(c: &mut Criterion) { group.bench_function("decode_view", |b| { b.iter(|| { for payload in &dataset.payload { - let view = bench_buffa::proto3::GoogleMessage1View::decode_view(payload).unwrap(); + let view = GoogleMessage1View::decode_view(payload).unwrap(); criterion::black_box(&view); } }); diff --git a/benchmarks/buffa/src/lib.rs b/benchmarks/buffa/src/lib.rs index eb88176..3aed0bb 100644 --- a/benchmarks/buffa/src/lib.rs +++ b/benchmarks/buffa/src/lib.rs @@ -10,7 +10,7 @@ dead_code )] pub mod bench { - include!(concat!(env!("OUT_DIR"), "/bench_messages.rs")); + buffa::include_proto!("bench"); } #[allow( @@ -23,7 +23,7 @@ pub mod bench { dead_code )] pub mod benchmarks { - include!(concat!(env!("OUT_DIR"), "/benchmarks.rs")); + buffa::include_proto!("benchmarks"); } #[allow( @@ -36,5 +36,5 @@ pub mod benchmarks { dead_code )] pub mod proto3 { - include!(concat!(env!("OUT_DIR"), "/benchmark_message1_proto3.rs")); + buffa::include_proto!("benchmarks.proto3"); } diff --git a/benchmarks/gen-datasets/src/main.rs b/benchmarks/gen-datasets/src/main.rs index c4849ff..0c5eb7f 100644 --- a/benchmarks/gen-datasets/src/main.rs +++ b/benchmarks/gen-datasets/src/main.rs @@ -18,7 +18,7 @@ use std::path::Path; dead_code )] mod proto { - include!(concat!(env!("OUT_DIR"), "/bench_messages.rs")); + buffa::include_proto!("bench"); } #[allow( clippy::derivable_impls, @@ -30,11 +30,11 @@ mod proto { dead_code )] mod dataset_proto { - include!(concat!(env!("OUT_DIR"), "/benchmarks.rs")); + buffa::include_proto!("benchmarks"); } -use proto::analytics_event::property::ValueOneof as Value; use proto::analytics_event::{Nested, Property}; +use proto::buffa_::oneof::analytics_event::property::Value; use proto::log_record::Context; use proto::*; diff --git a/buffa-build/src/lib.rs b/buffa-build/src/lib.rs index fde11e4..0597034 100644 --- a/buffa-build/src/lib.rs +++ b/buffa-build/src/lib.rs @@ -585,24 +585,14 @@ impl Config { .collect() }; - // Generate Rust source. + // Generate Rust source. Per-proto content files plus a per-package + // `.mod.rs` stitcher; only the stitchers need wiring into the + // module tree (content files are reached via `include!` from + // there). let generated = buffa_codegen::generate(&fds.file, &files_to_generate, &self.codegen_config)?; - // Build a map from generated file name to proto package for the - // module tree generator. - let file_to_package: std::collections::HashMap = fds - .file - .iter() - .map(|fd| { - let proto_name = fd.name.as_deref().unwrap_or(""); - let rs_name = buffa_codegen::proto_path_to_rust_module(proto_name); - let package = fd.package.as_deref().unwrap_or("").to_string(); - (rs_name, package) - }) - .collect(); - - // Write output files and collect (name, package) pairs. + // Write output files; collect (name, package) for PackageMod entries. let mut output_entries: Vec<(String, String)> = Vec::new(); for file in generated { let path = out_dir.join(&file.name); @@ -610,8 +600,9 @@ impl Config { std::fs::create_dir_all(parent)?; } write_if_changed(&path, file.content.as_bytes())?; - let package = file_to_package.get(&file.name).cloned().unwrap_or_default(); - output_entries.push((file.name, package)); + if file.kind == buffa_codegen::GeneratedFileKind::PackageMod { + output_entries.push((file.name, file.package)); + } } // Generate the include file if requested. diff --git a/buffa-codegen/src/bin/gen_wkt_types.rs b/buffa-codegen/src/bin/gen_wkt_types.rs index 4c81242..cc5ca0a 100644 --- a/buffa-codegen/src/bin/gen_wkt_types.rs +++ b/buffa-codegen/src/bin/gen_wkt_types.rs @@ -80,11 +80,12 @@ fn main() { // correct. `buffa/text` is zero-dep — enabled unconditionally // in buffa-types so no feature-gate wrapping is needed. // - // emit_register_fn = false All seven WKT files are `include!`d into - // one namespace — seven `register_types` fns would collide. WKTs - // register via the hand-written `register_wkt_types` in - // `any_ext.rs` anyway. Per-message `__*_TEXT_ANY` consts are - // still emitted (harmless `#[doc(hidden)] pub`). + // emit_register_fn = false Per-package output means one fn would + // be emitted (all seven WKTs share `google.protobuf`), so the + // old multi-file collision is gone — but WKTs register via the + // hand-written `register_wkt_types` in `any_ext.rs` (which knows + // the JSON-Any `is_wkt` special-casing the generic fn doesn't), + // so the generated fn would be redundant. let mut config = buffa_codegen::CodeGenConfig::default(); config.generate_views = true; config.preserve_unknown_fields = true; diff --git a/buffa-codegen/src/context.rs b/buffa-codegen/src/context.rs index 5663af0..1915fc0 100644 --- a/buffa-codegen/src/context.rs +++ b/buffa-codegen/src/context.rs @@ -7,6 +7,37 @@ use crate::generated::descriptor::{DescriptorProto, EnumDescriptorProto, FileDes use crate::oneof::to_snake_case; use crate::CodeGenConfig; +/// The single reserved module name under which all ancillary generated types +/// (views, oneof enums, extensions, `register_types`) live. +/// +/// See `DESIGN.md` → "Generated code layout" for the full layout. The name +/// is checked against proto package segments and message-module names by +/// [`crate::check_reserved_sentinel`]; a collision is a hard error. +pub const SENTINEL_MOD: &str = "buffa_"; + +/// A Rust type path split at the target-package boundary. +/// +/// Returned by [`CodeGenContext::rust_type_relative_split`]. The full owned +/// path is `to_package + within_package` (concatenated with `::`); ancillary +/// kinds insert their `buffa_::::` prefix between the two halves. +#[derive(Debug, Clone)] +pub struct SplitPath { + /// Path from the current emission scope to the **target package root**. + /// + /// One of: + /// - empty (same package, nesting 0) + /// - `"super::super"` (same package, nesting > 0) + /// - `"super::…::other_pkg"` (cross-package local) + /// - `"::extern_crate::pkg"` (extern type — absolute, nesting-independent) + pub to_package: String, + /// Path from the target package root to the type itself + /// (e.g. `"Foo"` or `"outer::Inner"`). + pub within_package: String, + /// `true` when `to_package` is an absolute (`::`/`crate::`) extern path. + /// Extern paths don't depend on the caller's nesting depth. + pub is_extern: bool, +} + /// Shared context for a code generation run. /// /// Holds the full set of file descriptors and a mapping from fully-qualified @@ -288,6 +319,125 @@ impl<'a> CodeGenContext<'a> { Some(result) } + /// Like [`rust_type_relative`](Self::rust_type_relative) but returns the + /// path split at the target-package boundary. + /// + /// Ancillary kinds (views, oneof enums) live in the `buffa_::::` + /// sub-tree of each package; callers compose the final path as + /// `to_package + "::buffa_::" + + "::" + within_package`. + /// + /// `nesting` is the **total** module depth of the caller's emission + /// scope below the current package root — i.e. message-nesting plus any + /// `buffa_::::` levels the caller is already inside (0 for owned + /// types, +2 for `buffa_::view::`, +3 for `buffa_::view::oneof::`). + pub fn rust_type_relative_split( + &self, + proto_fqn: &str, + current_package: &str, + nesting: usize, + ) -> Option { + let full_path = self.type_map.get(proto_fqn)?; + + let target_package = self + .package_of + .get(proto_fqn) + .map(|s| s.as_str()) + .unwrap_or(""); + + // Compute the type's path within its package (everything after the + // package module prefix). For extern types the prefix is the + // configured rust_module (e.g. `::buffa_types::google::protobuf`), + // not the bare dotted package, so derive it the same way `new()` + // populated the map. + let target_rust_module = if full_path.starts_with("::") || full_path.starts_with("crate::") + { + // Reconstruct the extern module prefix by stripping the + // within-package suffix length. We know the proto FQN's + // within-package portion (FQN minus package), so the full_path's + // last N segments correspond to it. + // + // Simpler: re-derive via `resolve_extern_prefix` would need the + // original extern_paths list. Instead, compute within-package + // from the proto FQN (which we know) and slice full_path. + let fqn_no_dot = proto_fqn.strip_prefix('.').unwrap_or(proto_fqn); + let within_proto = if target_package.is_empty() { + fqn_no_dot + } else { + fqn_no_dot + .strip_prefix(target_package) + .and_then(|s| s.strip_prefix('.')) + .unwrap_or(fqn_no_dot) + }; + // within_proto is dotted (e.g. "Outer.Inner"); within full_path + // it's `outer::Inner` (snake_case modules + final PascalCase). + // Count the segments and strip that many from full_path. + let within_segs = within_proto.split('.').count(); + let full_segs: Vec<&str> = full_path.split("::").collect(); + let cut = full_segs.len().saturating_sub(within_segs); + full_segs[..cut].join("::") + } else { + target_package.replace('.', "::") + }; + + let type_suffix = if target_rust_module.is_empty() { + full_path.as_str() + } else { + full_path + .strip_prefix(&format!("{}::", target_rust_module)) + .unwrap_or(full_path) + }; + + // Extern: absolute path; nesting irrelevant. + if full_path.starts_with("::") || full_path.starts_with("crate::") { + return Some(SplitPath { + to_package: target_rust_module, + within_package: type_suffix.to_string(), + is_extern: true, + }); + } + + if current_package == target_package { + let to_package = if nesting == 0 { + String::new() + } else { + (0..nesting).map(|_| "super").collect::>().join("::") + }; + return Some(SplitPath { + to_package, + within_package: type_suffix.to_string(), + is_extern: false, + }); + } + + // Cross-package local. + let current_parts: Vec<&str> = if current_package.is_empty() { + vec![] + } else { + current_package.split('.').collect() + }; + let target_parts: Vec<&str> = if target_package.is_empty() { + vec![] + } else { + target_package.split('.').collect() + }; + let common_len = current_parts + .iter() + .zip(&target_parts) + .take_while(|(a, b)| a == b) + .count(); + let up_count = (current_parts.len() - common_len) + nesting; + let down_parts = &target_parts[common_len..]; + + let mut segments: Vec<&str> = vec!["super"; up_count]; + segments.extend_from_slice(down_parts); + + Some(SplitPath { + to_package: segments.join("::"), + within_package: type_suffix.to_string(), + is_extern: false, + }) + } + /// Collect custom attributes matching a fully-qualified proto path. /// /// Returns a `TokenStream` of all `#[...]` attributes whose path prefix @@ -374,20 +524,81 @@ impl<'a> MessageScope<'a> { nesting: self.nesting + 1, } } +} - /// Return a copy of this scope with the nesting depth incremented by 1. - /// - /// Use this when generating code that will live inside the message's own - /// `pub mod` (e.g. oneof view enums) without changing the identity - /// (`proto_fqn`, `features`). - pub fn deeper(&self) -> MessageScope<'a> { - MessageScope { - nesting: self.nesting + 1, - ..*self +/// Kind of ancillary tree under the [`SENTINEL_MOD`] module. +/// +/// `path_segments()` returns the module path *inside* `buffa_::` (not +/// including the sentinel itself). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum AncillaryKind { + /// `buffa_::oneof::::` — owned oneof enums. + Oneof, + /// `buffa_::view::oneof::::` — view oneof enums. + ViewOneof, +} + +impl AncillaryKind { + fn path_segments(self) -> &'static [&'static str] { + match self { + Self::Oneof => &["oneof"], + Self::ViewOneof => &["view", "oneof"], } } } +/// Build a token-stream path prefix from an emission scope to an ancillary +/// kind's location for the **current** message (`proto_fqn`). +/// +/// Always climbs to the package root via `super::` and re-descends through +/// `buffa_::::::` — uniform regardless of where the caller +/// sits. `from_nesting` is the caller's total module depth below the +/// package root (message-nesting plus any `buffa_::::` levels the +/// caller is already inside). +/// +/// Returned tokens always end with `::` so callers append the type +/// identifier directly: `quote! { #prefix #ident }`. +pub(crate) fn ancillary_prefix( + kind: AncillaryKind, + current_package: &str, + proto_fqn: &str, + from_nesting: usize, +) -> proc_macro2::TokenStream { + use crate::idents::make_field_ident; + use quote::quote; + + let supers = "super::".repeat(from_nesting); + let supers_tokens: proc_macro2::TokenStream = if supers.is_empty() { + proc_macro2::TokenStream::new() + } else { + syn::parse_str(&supers).expect("valid super:: chain") + }; + + let sentinel = make_field_ident(SENTINEL_MOD); + let kind_segs: Vec<_> = kind + .path_segments() + .iter() + .map(|s| make_field_ident(s)) + .collect(); + + // Snake-cased message path within the package (e.g. "outer::inner::"). + let within_pkg = if current_package.is_empty() { + proto_fqn + } else { + proto_fqn + .strip_prefix(current_package) + .and_then(|s| s.strip_prefix('.')) + .unwrap_or(proto_fqn) + }; + let msg_segs: Vec<_> = within_pkg + .split('.') + .filter(|s| !s.is_empty()) + .map(|name| make_field_ident(&to_snake_case(name))) + .collect(); + + quote! { #supers_tokens #sentinel :: #(#kind_segs ::)* #(#msg_segs ::)* } +} + /// Proto-segment-aware prefix match: `prefix` matches `fqn_dotted` if /// `prefix == "."`, the two are equal, or `fqn_dotted` starts with `prefix` /// followed by a `.` boundary. Proto identifiers are ASCII, and `.` is ASCII, diff --git a/buffa-codegen/src/impl_message.rs b/buffa-codegen/src/impl_message.rs index 4e4e8a5..66d8031 100644 --- a/buffa-codegen/src/impl_message.rs +++ b/buffa-codegen/src/impl_message.rs @@ -229,6 +229,7 @@ pub fn generate_message_impl( proto_fqn: &str, features: &ResolvedFeatures, oneof_idents: &std::collections::HashMap, + oneof_prefix: &TokenStream, nesting: usize, ) -> Result { let name_ident = format_ident!("{}", rust_name); @@ -316,7 +317,6 @@ pub fn generate_message_impl( .collect::, _>>()?; // Collect oneof compute/write/merge tokens. - let mod_ident = crate::message::make_field_ident(&crate::oneof::to_snake_case(rust_name)); let mut oneof_compute_stmts: Vec = Vec::new(); let mut oneof_write_stmts: Vec = Vec::new(); let mut oneof_merge_arms: Vec = Vec::new(); @@ -326,7 +326,7 @@ pub fn generate_message_impl( enum_ident, oneof_name, fields, - &mod_ident, + oneof_prefix, proto_fqn, features, preserve_unknown_fields, @@ -2119,14 +2119,13 @@ fn generate_oneof_impls( enum_ident: &proc_macro2::Ident, oneof_name: &str, fields: &[&FieldDescriptorProto], - mod_ident: &proc_macro2::Ident, + oneof_prefix: &TokenStream, proto_fqn: &str, features: &ResolvedFeatures, preserve_unknown_fields: bool, ) -> Result<(TokenStream, TokenStream, Vec), CodeGenError> { let field_ident = make_field_ident(oneof_name); - // Module-qualified path: the oneof enum lives in the message's module. - let qualified_enum: TokenStream = quote! { #mod_ident::#enum_ident }; + let qualified_enum: TokenStream = quote! { #oneof_prefix #enum_ident }; let mut size_arms: Vec = Vec::new(); let mut write_arms: Vec = Vec::new(); diff --git a/buffa-codegen/src/impl_text.rs b/buffa-codegen/src/impl_text.rs index c942015..8a1118d 100644 --- a/buffa-codegen/src/impl_text.rs +++ b/buffa-codegen/src/impl_text.rs @@ -30,7 +30,7 @@ use crate::impl_message::{ is_supported_field_type, }; use crate::message::{is_closed_enum, is_map_field, make_field_ident}; -use crate::oneof::{is_boxed_variant, to_snake_case}; +use crate::oneof::is_boxed_variant; use crate::CodeGenError; /// Generate `impl ::buffa::text::TextFormat for #name_ident { ... }`. @@ -49,6 +49,7 @@ pub(crate) fn generate_text_impl( features: &ResolvedFeatures, has_extension_ranges: bool, oneof_idents: &std::collections::HashMap, + oneof_prefix: &TokenStream, nesting: usize, ) -> Result { if !ctx.config.generate_text { @@ -98,7 +99,6 @@ pub(crate) fn generate_text_impl( } let name_ident = format_ident!("{}", rust_name); - let mod_ident = make_field_ident(&to_snake_case(rust_name)); // ── field grouping (mirrors generate_message_impl) ────────────────────── @@ -163,7 +163,7 @@ pub(crate) fn generate_text_impl( let oneof_encode: Vec<_> = oneof_groups .iter() .map(|(name, enum_ident, fields)| { - oneof_encode_stmt(ctx, enum_ident, name, fields, &mod_ident, features) + oneof_encode_stmt(ctx, enum_ident, name, fields, oneof_prefix, features) }) .collect::>()?; let map_encode: Vec<_> = map_fields @@ -188,7 +188,7 @@ pub(crate) fn generate_text_impl( enum_ident, name, fields, - &mod_ident, + oneof_prefix, current_package, proto_fqn, features, @@ -723,11 +723,11 @@ fn oneof_encode_stmt( enum_ident: &proc_macro2::Ident, oneof_name: &str, fields: &[&FieldDescriptorProto], - mod_ident: &proc_macro2::Ident, + oneof_prefix: &TokenStream, parent_features: &ResolvedFeatures, ) -> Result { let field_ident = make_field_ident(oneof_name); - let qualified: TokenStream = quote! { #mod_ident::#enum_ident }; + let qualified: TokenStream = quote! { #oneof_prefix #enum_ident }; let mut arms: Vec = Vec::new(); for field in fields { @@ -782,14 +782,14 @@ fn oneof_merge_arms( enum_ident: &proc_macro2::Ident, oneof_name: &str, fields: &[&FieldDescriptorProto], - mod_ident: &proc_macro2::Ident, + oneof_prefix: &TokenStream, current_package: &str, proto_fqn: &str, parent_features: &ResolvedFeatures, nesting: usize, ) -> Result, CodeGenError> { let field_ident = make_field_ident(oneof_name); - let qualified: TokenStream = quote! { #mod_ident::#enum_ident }; + let qualified: TokenStream = quote! { #oneof_prefix #enum_ident }; let mut arms: Vec = Vec::new(); for field in fields { diff --git a/buffa-codegen/src/lib.rs b/buffa-codegen/src/lib.rs index b709aa9..d0dbd03 100644 --- a/buffa-codegen/src/lib.rs +++ b/buffa-codegen/src/lib.rs @@ -40,15 +40,47 @@ use crate::generated::descriptor::FileDescriptorProto; use proc_macro2::TokenStream; use quote::quote; -/// Result of generating Rust code for a single `.proto` file. +/// One generated output file. +/// +/// Each `.proto` produces five **content files** (`.rs`, +/// `.__view.rs`, `.__oneof.rs`, `.__view_oneof.rs`, +/// `.__ext.rs`) and each proto package produces one +/// `.mod.rs` **stitcher** that `include!`s the content files +/// and authors the `pub mod buffa_ { … }` ancillary tree. +/// See `DESIGN.md` → "Generated code layout". #[derive(Debug)] pub struct GeneratedFile { - /// The output file path (e.g., "my_package.rs"). + /// The output file path (e.g., `"my.pkg.foo.rs"` or `"my.pkg.mod.rs"`). pub name: String, + /// The proto package this file belongs to. + pub package: String, + /// What this file contains. Build integrations only need to wire up + /// [`GeneratedFileKind::PackageMod`] files; everything else is reached + /// via `include!` from there. + pub kind: GeneratedFileKind, /// The generated Rust source code. pub content: String, } +/// Kind of [`GeneratedFile`]. The five content kinds are 1:1 with input +/// `.proto` files; `PackageMod` is 1:1 with packages. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GeneratedFileKind { + /// Owned message structs and enums (`.rs`). + Owned, + /// View structs (`.__view.rs`). + View, + /// Owned oneof enums (`.__oneof.rs`). + Oneof, + /// View oneof enums (`.__view_oneof.rs`). + ViewOneof, + /// File-level extension consts (`.__ext.rs`). + Ext, + /// Per-package stitcher (`.mod.rs`). The only file build + /// systems need to wire up directly. + PackageMod, +} + /// Configuration for code generation. #[derive(Debug, Clone)] #[non_exhaustive] @@ -236,6 +268,10 @@ pub(crate) fn effective_extern_paths( /// (matching `CodeGeneratorRequest.file_to_generate`). Descriptors for /// dependencies may be present in `file_descriptors` but won't produce output /// files unless they appear in `files_to_generate`. +/// +/// Each `.proto` emits five content files; each distinct package emits one +/// `.mod.rs` stitcher. Packages are processed in sorted order for +/// deterministic output. pub fn generate( file_descriptors: &[FileDescriptorProto], files_to_generate: &[String], @@ -243,31 +279,34 @@ pub fn generate( ) -> Result, CodeGenError> { let ctx = context::CodeGenContext::for_generate(file_descriptors, files_to_generate, config); - let mut output = Vec::new(); + // Group requested files by package. BTreeMap → deterministic output order. + let mut by_package: std::collections::BTreeMap> = + std::collections::BTreeMap::new(); for file_name in files_to_generate { let file_desc = file_descriptors .iter() .find(|f| f.name.as_deref() == Some(file_name.as_str())) .ok_or_else(|| CodeGenError::FileNotFound(file_name.clone()))?; + let pkg = file_desc.package.as_deref().unwrap_or("").to_string(); + by_package.entry(pkg).or_default().push(file_desc); + } - let content = generate_file(&ctx, file_desc)?; - let rust_filename = proto_path_to_rust_module(file_name); - output.push(GeneratedFile { - name: rust_filename, - content, - }); + let mut output = Vec::new(); + for (package, files) in by_package { + generate_package(&ctx, &package, &files, &mut output)?; } Ok(output) } -/// Generate a module tree that assembles generated `.rs` files into +/// Generate a module tree that assembles per-package `.mod.rs` files into /// nested `pub mod` blocks matching the protobuf package hierarchy. /// -/// Each entry is a `(file_name, package)` pair where `package` is the -/// dot-separated protobuf package name (e.g., `"google.api"`). The module -/// tree is built from the **package** hierarchy so that `super::`-based -/// cross-package references resolve correctly. +/// Each entry is a `(mod_file_name, package)` pair where `package` is the +/// dot-separated protobuf package name (e.g., `"google.api"`) and +/// `mod_file_name` is the corresponding `.mod.rs` (only +/// [`GeneratedFileKind::PackageMod`] outputs need wiring; per-proto +/// content files are reached via `include!` from the stitcher). /// /// `include_prefix` is prepended to file names in `include!` directives. /// Use `""` for relative paths or `concat!(env!("OUT_DIR"), "/")` style @@ -424,65 +463,81 @@ fn check_module_name_conflicts(file: &FileDescriptorProto) -> Result<(), CodeGen check_siblings(&file.message_type, package) } -/// Check that no message named `FooView` collides with the generated view -/// type for a sibling message `Foo`. -fn check_view_name_conflicts(file: &FileDescriptorProto) -> Result<(), CodeGenError> { - use std::collections::HashSet; - - fn check_siblings( +/// Check that no proto package segment or message-module name equals the +/// reserved [`SENTINEL_MOD`](context::SENTINEL_MOD). +/// +/// Ancillary types live under `pkg::buffa_::…`; a proto element that would +/// emit `pub mod buffa_` at any level (a package segment literally named +/// `buffa_`, or a message whose snake_case module name is `buffa_`) would +/// produce E0428. This is the **only** name buffa reserves in user +/// namespace, so the check is one place to look at when adding kinds. +fn check_reserved_sentinel(file: &FileDescriptorProto) -> Result<(), CodeGenError> { + let sentinel = context::SENTINEL_MOD; + let package = file.package.as_deref().unwrap_or(""); + if package.split('.').any(|seg| seg == sentinel) { + return Err(CodeGenError::ReservedModuleName { + name: sentinel.to_string(), + location: format!("package '{package}'"), + }); + } + fn check_messages( messages: &[crate::generated::descriptor::DescriptorProto], scope: &str, + sentinel: &str, ) -> Result<(), CodeGenError> { - // Collect all message names at this level. - let names: HashSet<&str> = messages.iter().filter_map(|m| m.name.as_deref()).collect(); - - // For each message Foo, check if FooView also exists. for msg in messages { let name = msg.name.as_deref().unwrap_or(""); - let view_name = format!("{}View", name); - if names.contains(view_name.as_str()) { - return Err(CodeGenError::ViewNameConflict { - scope: scope.to_string(), - owned_msg: name.to_string(), - view_msg: view_name, + if crate::oneof::to_snake_case(name) == sentinel { + return Err(CodeGenError::ReservedModuleName { + name: sentinel.to_string(), + location: format!("message '{scope}.{name}'"), }); } - } - - // Recurse into nested messages. - for msg in messages { - let name = msg.name.as_deref().unwrap_or(""); let child_scope = if scope.is_empty() { name.to_string() } else { format!("{}.{}", scope, name) }; - check_siblings(&msg.nested_type, &child_scope)?; + check_messages(&msg.nested_type, &child_scope, sentinel)?; } - Ok(()) } + check_messages(&file.message_type, package, sentinel) +} - let package = file.package.as_deref().unwrap_or(""); - check_siblings(&file.message_type, package) +/// Per-proto content streams plus the file stem, ready to be formatted. +struct ProtoContent { + stem: String, + owned: TokenStream, + view: TokenStream, + oneof: TokenStream, + view_oneof: TokenStream, + ext: TokenStream, } -/// Generate Rust source for a single `.proto` file. -fn generate_file( +/// Generate the five per-`.proto` content files for one input file. +fn generate_proto_content( ctx: &context::CodeGenContext, + current_package: &str, file: &FileDescriptorProto, -) -> Result { - // Validate descriptors before generating code. + reg: &mut message::RegistryPaths, +) -> Result { + use crate::idents::make_field_ident; + use crate::message::MessageOutput; + check_reserved_field_names(file)?; check_module_name_conflicts(file)?; - if ctx.config.generate_views { - check_view_name_conflicts(file)?; - } + check_reserved_sentinel(file)?; let resolver = imports::ImportResolver::for_file(file); - let mut tokens = resolver.generate_use_block(); - let current_package = file.package.as_deref().unwrap_or(""); let features = crate::features::for_file(file); + + let mut owned = resolver.generate_use_block(); + let mut view = TokenStream::new(); + let mut oneof = TokenStream::new(); + let mut view_oneof = TokenStream::new(); + let mut ext = TokenStream::new(); + for enum_type in &file.enum_type { let enum_rust_name = enum_type.name.as_deref().unwrap_or(""); let enum_fqn = if current_package.is_empty() { @@ -490,7 +545,7 @@ fn generate_file( } else { format!("{}.{}", current_package, enum_rust_name) }; - tokens.extend(enumeration::generate_enum( + owned.extend(enumeration::generate_enum( ctx, enum_type, enum_rust_name, @@ -499,11 +554,6 @@ fn generate_file( &resolver, )?); } - // Collect paths to registry consts (both file-level and nested-in-message) - // for the optional `register_types` fn below. JSON/text are tracked - // separately so each registration line is emitted only under its - // corresponding `generate_*` flag. - let mut reg = message::RegistryPaths::default(); for message_type in &file.message_type { let top_level_name = message_type.name.as_deref().unwrap_or(""); @@ -512,7 +562,14 @@ fn generate_file( } else { format!("{}.{}", current_package, top_level_name) }; - let (msg_top, msg_mod, msg_reg) = message::generate_message( + let MessageOutput { + owned_top, + owned_mod, + oneof_tree: msg_oneof, + view_tree: msg_view, + view_oneof_tree: msg_view_oneof, + reg: msg_reg, + } = message::generate_message( ctx, message_type, current_package, @@ -521,114 +578,236 @@ fn generate_file( &features, &resolver, )?; - tokens.extend(msg_top); - // Nested extension const paths are relative to the message's module - // scope; prefix with `::` for the package-level view. - let mod_name = crate::oneof::to_snake_case(top_level_name); - let mod_ident = crate::message::make_field_ident(&mod_name); + owned.extend(owned_top); + let mod_ident = make_field_ident(&crate::oneof::to_snake_case(top_level_name)); for p in msg_reg.json_ext { reg.json_ext.push(quote! { #mod_ident :: #p }); } for p in msg_reg.text_ext { reg.text_ext.push(quote! { #mod_ident :: #p }); } - // Any-entry paths are already relative to the struct's scope - // (= file scope for top-level messages) — no prefix needed. reg.json_any.extend(msg_reg.json_any); reg.text_any.extend(msg_reg.text_any); - let view_mod = if ctx.config.generate_views { - let (view_top, view_mod) = view::generate_view( - ctx, - message_type, - current_package, - top_level_name, - &proto_fqn, - &features, - )?; - tokens.extend(view_top); - view_mod - } else { - TokenStream::new() - }; - - // Combine message and view module items into a single `pub mod`. - if !msg_mod.is_empty() || !view_mod.is_empty() { - tokens.extend(quote! { + if !owned_mod.is_empty() { + owned.extend(quote! { pub mod #mod_ident { #[allow(unused_imports)] use super::*; - #msg_mod - #view_mod + #owned_mod } }); } + oneof.extend(msg_oneof); + view.extend(msg_view); + view_oneof.extend(msg_view_oneof); } + // File-level `extend` declarations → `buffa_::ext::` (depth 2). let (file_ext_tokens, file_ext_json, file_ext_text) = extension::generate_extensions( ctx, &file.extension, current_package, - 0, + 2, &features, current_package, )?; - tokens.extend(file_ext_tokens); + ext.extend(file_ext_tokens); + let sentinel = make_field_ident(context::SENTINEL_MOD); for id in file_ext_json { - reg.json_ext.push(quote! { #id }); + reg.json_ext.push(quote! { #sentinel :: ext :: #id }); } for id in file_ext_text { - reg.text_ext.push(quote! { #id }); + reg.text_ext.push(quote! { #sentinel :: ext :: #id }); } - // `register_types(&mut TypeRegistry)` — one call per entry, split by - // format. Only emitted when at least one entry exists. Lines are - // gated at codegen time by `generate_json` / `generate_text`; the - // corresponding `register_*` methods on `TypeRegistry` are feature-gated - // in buffa, so a flag/feature mismatch surfaces as a compile error. + Ok(ProtoContent { + stem: proto_path_to_stem(file.name.as_deref().unwrap_or("")), + owned, + view, + oneof, + view_oneof, + ext, + }) +} + +/// Generate all output files for one proto package: five content files per +/// `.proto` plus one `.mod.rs` stitcher. +fn generate_package( + ctx: &context::CodeGenContext, + current_package: &str, + files: &[&FileDescriptorProto], + out: &mut Vec, +) -> Result<(), CodeGenError> { + // Registry paths are package-root-relative; `register_types` lives at + // `buffa_::register_types` (one level deep), so each path gets a + // single `super::` prefix when emitted into the fn body. + let mut reg = message::RegistryPaths::default(); + let mut stems: Vec = Vec::new(); + + for file in files { + let pc = generate_proto_content(ctx, current_package, file, &mut reg)?; + let source = file.name.as_deref().unwrap_or(""); + let push = |out: &mut Vec, + suffix: &str, + kind: GeneratedFileKind, + tokens: TokenStream| + -> Result<(), CodeGenError> { + out.push(GeneratedFile { + name: format!("{}{suffix}.rs", pc.stem), + package: current_package.to_string(), + kind, + content: format_tokens(tokens, source)?, + }); + Ok(()) + }; + push(out, "", GeneratedFileKind::Owned, pc.owned)?; + push(out, ".__view", GeneratedFileKind::View, pc.view)?; + push(out, ".__oneof", GeneratedFileKind::Oneof, pc.oneof)?; + push( + out, + ".__view_oneof", + GeneratedFileKind::ViewOneof, + pc.view_oneof, + )?; + push(out, ".__ext", GeneratedFileKind::Ext, pc.ext)?; + stems.push(pc.stem); + } + + out.push(GeneratedFile { + name: package_to_mod_filename(current_package), + package: current_package.to_string(), + kind: GeneratedFileKind::PackageMod, + content: generate_package_mod(ctx, &stems, ®), + }); + + Ok(()) +} + +/// Render the per-package `.mod.rs` stitcher. +/// +/// `include!` paths are bare-sibling (no `OUT_DIR` prefix) so the same +/// stitcher works for both `OUT_DIR` builds (where the consumer's +/// `include_proto!` already prepended `OUT_DIR`) and checked-in code. +fn generate_package_mod( + ctx: &context::CodeGenContext, + stems: &[String], + reg: &message::RegistryPaths, +) -> String { + use std::fmt::Write as _; + + let mut s = String::new(); + writeln!(s, "// @generated by protoc-gen-buffa. DO NOT EDIT.").unwrap(); + writeln!(s).unwrap(); + let owned_includes = |s: &mut String, suffix: &str| { + for stem in stems { + writeln!(s, r#"include!("{stem}{suffix}.rs");"#).unwrap(); + } + }; + owned_includes(&mut s, ""); + writeln!( + s, + "#[allow(non_camel_case_types, dead_code, unused_imports, \ + clippy::derivable_impls, clippy::match_single_binding)]" + ) + .unwrap(); + writeln!(s, "pub mod {} {{", context::SENTINEL_MOD).unwrap(); + writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); + if ctx.config.generate_views { + writeln!(s, " pub mod view {{").unwrap(); + writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); + for stem in stems { + writeln!(s, r#" include!("{stem}.__view.rs");"#).unwrap(); + } + writeln!(s, " pub mod oneof {{").unwrap(); + writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); + for stem in stems { + writeln!(s, r#" include!("{stem}.__view_oneof.rs");"#).unwrap(); + } + writeln!(s, " }}").unwrap(); + writeln!(s, " }}").unwrap(); + } + writeln!(s, " pub mod oneof {{").unwrap(); + writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); + for stem in stems { + writeln!(s, r#" include!("{stem}.__oneof.rs");"#).unwrap(); + } + writeln!(s, " }}").unwrap(); + writeln!(s, " pub mod ext {{").unwrap(); + writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); + for stem in stems { + writeln!(s, r#" include!("{stem}.__ext.rs");"#).unwrap(); + } + writeln!(s, " }}").unwrap(); + if ctx.config.emit_register_fn && !reg.is_empty() { - let json_any = ®.json_any; - let json_ext = ®.json_ext; - let text_any = ®.text_any; - let text_ext = ®.text_ext; - tokens.extend(quote! { - /// Register this file's `Any` type entries and extension entries - /// (JSON and/or text, per codegen config) with the given registry. - pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry) { - #( reg.register_json_any(#json_any); )* - #( reg.register_json_ext(#json_ext); )* - #( reg.register_text_any(#text_any); )* - #( reg.register_text_ext(#text_ext); )* - } - }); + writeln!( + s, + " /// Register this package's `Any` type entries and extension entries." + ) + .unwrap(); + writeln!( + s, + " pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry) {{" + ) + .unwrap(); + // TokenStream::Display inserts inter-token spaces; collapse them so + // the output is `super::foo::__BAR` not `super::foo :: __BAR`. + let path = |p: &TokenStream| p.to_string().replace(' ', ""); + for p in ®.json_any { + writeln!(s, " reg.register_json_any(super::{});", path(p)).unwrap(); + } + for p in ®.json_ext { + writeln!(s, " reg.register_json_ext(super::{});", path(p)).unwrap(); + } + for p in ®.text_any { + writeln!(s, " reg.register_text_any(super::{});", path(p)).unwrap(); + } + for p in ®.text_ext { + writeln!(s, " reg.register_text_ext(super::{});", path(p)).unwrap(); + } + writeln!(s, " }}").unwrap(); } + writeln!(s, "}}").unwrap(); + s +} - // Parse the token stream into a syn::File and format with prettyplease. - // Regular `//` comments cannot appear inside quote! blocks, so the file - // header is prepended as a raw string after formatting. +/// Format a token stream into a generated-file string with the standard +/// header comment. +fn format_tokens(tokens: TokenStream, source: &str) -> Result { let syntax_tree = syn::parse2::(tokens).map_err(|e| CodeGenError::InvalidSyntax(e.to_string()))?; let formatted = prettyplease::unparse(&syntax_tree); - - let source_line = file - .name - .as_ref() - .map_or(String::new(), |n| format!("// source: {n}\n")); - + let source_line = if source.is_empty() { + String::new() + } else { + format!("// source: {source}\n") + }; Ok(format!( "// @generated by protoc-gen-buffa. DO NOT EDIT.\n{source_line}\n{formatted}" )) } -/// Convert a `.proto` file path to a Rust module file name. +/// Convert a proto package name to its `.mod.rs` stitcher filename. /// -/// e.g., "google/protobuf/timestamp.proto" → "google.protobuf.timestamp.rs" -/// Convert a proto file path to a generated Rust file name. +/// e.g., `"google.protobuf"` → `"google.protobuf.mod.rs"`; the unnamed +/// package → `"_.mod.rs"`. +pub fn package_to_mod_filename(package: &str) -> String { + if package.is_empty() { + "_.mod.rs".to_string() + } else { + format!("{package}.mod.rs") + } +} + +/// Convert a `.proto` file path to its content-file stem. /// -/// e.g., `"google/protobuf/timestamp.proto"` → `"google.protobuf.timestamp.rs"` -pub fn proto_path_to_rust_module(proto_path: &str) -> String { +/// e.g., `"google/protobuf/timestamp.proto"` → `"google.protobuf.timestamp"`. +/// The five content files append `""`, `".__view"`, `".__oneof"`, +/// `".__view_oneof"`, `".__ext"` plus `".rs"`. +pub fn proto_path_to_stem(proto_path: &str) -> String { let without_ext = proto_path.strip_suffix(".proto").unwrap_or(proto_path); - format!("{}.rs", without_ext.replace('/', ".")) + without_ext.replace('/', ".") } /// Code generation error. @@ -677,32 +856,17 @@ pub enum CodeGenError { name_b: String, module_name: String, }, - /// The `{Name}Oneof` identifier buffa would emit for a oneof collides - /// with another name in the parent message's Rust module (a nested - /// message, a nested enum, or — when view generation is enabled — a - /// `{Name}OneofView`-equivalent sibling). Resolve by renaming the - /// oneof or the colliding nested type in the `.proto`. - #[error( - "name conflict in '{scope}': oneof '{oneof_name}' would emit as \ - '{attempted}', but that name already names another item in the \ - enclosing scope" - )] - OneofNameConflict { - scope: String, - oneof_name: String, - attempted: String, - }, - /// A message named `FooView` collides with the generated view type for - /// message `Foo`. + /// A proto package segment or message name would emit a Rust module + /// matching the reserved sentinel `buffa_`. + /// + /// This is the only name buffa reserves in user namespace. Resolve by + /// renaming the proto element. #[error( - "name conflict in '{scope}': message '{view_msg}' collides with \ - the generated view type for message '{owned_msg}'" + "reserved module name '{name}' at {location}: this name is reserved \ + for buffa's generated ancillary types (views, oneof enums, \ + extensions). Rename the proto element." )] - ViewNameConflict { - scope: String, - owned_msg: String, - view_msg: String, - }, + ReservedModuleName { name: String, location: String }, /// The input contains a message with `option message_set_wire_format = true` /// but [`CodeGenConfig::allow_message_set`] was not set. #[error( diff --git a/buffa-codegen/src/message.rs b/buffa-codegen/src/message.rs index 9feb806..9df609f 100644 --- a/buffa-codegen/src/message.rs +++ b/buffa-codegen/src/message.rs @@ -5,7 +5,7 @@ use crate::generated::descriptor::DescriptorProto; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use crate::context::{CodeGenContext, MessageScope}; +use crate::context::{ancillary_prefix, AncillaryKind, CodeGenContext, MessageScope}; use crate::defaults::parse_default_value; use crate::features::ResolvedFeatures; use crate::impl_message::{is_explicit_presence_scalar, is_real_oneof_member}; @@ -36,6 +36,34 @@ impl RegistryPaths { } } +/// Separated output streams for a single message (and its nested messages, +/// already wrapped in `pub mod {nested_name} {}` blocks at each level). +/// +/// Each `*_tree` stream mirrors the message-nesting structure: a top-level +/// message `Foo` with nested `Bar` produces an `oneof_tree` containing +/// `pub mod foo { /* Foo's oneofs */ pub mod bar { /* Bar's oneofs */ } }`. +/// The package-level assembler in `lib.rs` places each tree under its +/// `buffa_::::` root. +#[derive(Default)] +pub(crate) struct MessageOutput { + /// Owned struct + impls — emitted at the message's owned-tree position. + pub owned_top: TokenStream, + /// Nested types (enums, nested-message structs, nested extensions) — + /// emitted inside the message's `pub mod {name} {}` in the owned tree. + pub owned_mod: TokenStream, + /// Oneof enum definitions, wrapped in `pub mod {msg_name} { … }`. + /// Destined for `buffa_::oneof::`. + pub oneof_tree: TokenStream, + /// View struct + impls, wrapped per-message-level. Destined for + /// `buffa_::view::`. + pub view_tree: TokenStream, + /// Oneof view enum definitions, wrapped per-message-level. Destined + /// for `buffa_::view::oneof::`. + pub view_oneof_tree: TokenStream, + /// Registry const paths (relative to the package root). + pub reg: RegistryPaths, +} + /// Generate Rust code for a message type (and its nested types). /// /// `current_package` is the proto package of the file being generated. @@ -49,14 +77,9 @@ impl RegistryPaths { /// `proto_fqn` is the fully-qualified proto type name without a leading dot /// (e.g. `google.protobuf.Timestamp`, `my.package.Outer.Inner`). It is used /// to emit the `TYPE_URL` constant. -/// Returns `(top_level_items, module_items, registry_paths)` where -/// `top_level_items` contains the struct, its impls, and the custom -/// deserialize; `module_items` contains nested types and oneof enums to be -/// placed in `pub mod `; and `registry_paths` collects qualified paths -/// to the per-message `__*_JSON_ANY` / `__*_TEXT_ANY` consts (relative to -/// the struct's scope) and per-extension `__*_JSON_EXT` / `__*_TEXT_EXT` -/// consts (relative to the `module_items` scope) for `register_types`. -pub fn generate_message( +/// Returns a [`MessageOutput`] bundling the separated owned / oneof / +/// view / view-oneof token streams plus registry-const paths. +pub(crate) fn generate_message( ctx: &CodeGenContext, msg: &DescriptorProto, current_package: &str, @@ -64,7 +87,7 @@ pub fn generate_message( proto_fqn: &str, features: &ResolvedFeatures, resolver: &crate::imports::ImportResolver, -) -> Result<(TokenStream, TokenStream, RegistryPaths), CodeGenError> { +) -> Result { let scope = MessageScope { ctx, current_package, @@ -80,7 +103,7 @@ fn generate_message_with_nesting( msg: &DescriptorProto, rust_name: &str, resolver: &crate::imports::ImportResolver, -) -> Result<(TokenStream, TokenStream, RegistryPaths), CodeGenError> { +) -> Result { let MessageScope { ctx, current_package, @@ -170,14 +193,14 @@ fn generate_message_with_nesting( let mod_ident = make_field_ident(&mod_name_str); // Compute oneof enum identifiers for all non-synthetic oneofs up front. - // Sequential allocation prevents sibling oneofs from claiming the same - // suffixed name (see `resolve_oneof_idents`). - let oneof_idents = - crate::oneof::resolve_oneof_idents(msg, proto_fqn, ctx.config.generate_views)?; + let oneof_idents = crate::oneof::resolve_oneof_idents(msg); + + // Path prefix from this struct's emission scope to its oneof enums at + // `buffa_::oneof::::`. The owned struct sits at `nesting` + // levels below the package root. + let oneof_prefix = ancillary_prefix(AncillaryKind::Oneof, current_package, proto_fqn, nesting); // One `Option` field in the struct per non-synthetic oneof. - // Oneof enums live inside the message's module, so the type path is - // `mod_name::EnumName`. let oneof_serde_attr = if ctx.config.generate_json { quote! { #[serde(flatten)] } } else { @@ -194,7 +217,7 @@ fn generate_message_with_nesting( let opt = resolver.option(); let tokens = quote! { #oneof_serde_attr - pub #field_ident: #opt<#mod_ident::#enum_ident>, + pub #field_ident: #opt<#oneof_prefix #enum_ident>, }; Some((tokens, field_ident)) }) @@ -334,6 +357,7 @@ fn generate_message_with_nesting( proto_fqn, features, &oneof_idents, + &oneof_prefix, nesting, )?; @@ -346,6 +370,7 @@ fn generate_message_with_nesting( features, has_extension_ranges, &oneof_idents, + &oneof_prefix, nesting, )?; @@ -426,7 +451,7 @@ fn generate_message_with_nesting( scope, msg, &name_ident, - &mod_ident, + &oneof_prefix, resolver, has_extension_ranges, &oneof_idents, @@ -476,12 +501,16 @@ fn generate_message_with_nesting( // Build module items from nested messages. Each nested message contributes: // - Its struct + impls (top_level) go directly into our module - // - Its nested types (mod_items) + view types go into a sub-module + // - Its nested types (owned_mod) go into a sub-module in the owned tree + // - Its ancillary trees nest under `pub mod {nested_name}` in each tree // - Its registry const paths bubble up, prefixed appropriately let mut nested_items = TokenStream::new(); + let mut nested_oneof_tree = TokenStream::new(); + let mut nested_view_tree = TokenStream::new(); + let mut nested_view_oneof_tree = TokenStream::new(); // Any-entry paths are relative to THIS struct's scope (top_level). // Our own consts land alongside our struct; nested messages' consts land - // in our mod_items, which the caller wraps in `pub mod #mod_ident`, so + // in our owned_mod, which the caller wraps in `pub mod #mod_ident`, so // their returned paths get prefixed with `#mod_ident::`. // Extension-entry paths are relative to the message's MODULE scope. let mut reg_paths = RegistryPaths::default(); @@ -501,58 +530,42 @@ fn generate_message_with_nesting( .unwrap_or(false) }) .collect(); - for (nested_desc, (top, mod_items, nested_reg)) in non_map_nested.iter().zip(nested_msgs) { - nested_items.extend(top); + for (nested_desc, nested_out) in non_map_nested.iter().zip(nested_msgs) { + nested_items.extend(nested_out.owned_top); let nested_name = nested_desc.name.as_deref().unwrap_or(""); let nested_mod = make_field_ident(&crate::oneof::to_snake_case(nested_name)); // Extension paths: nested's module-scope → our module-scope = prefix // with the nested message's own module ident. - for p in nested_reg.json_ext { + for p in nested_out.reg.json_ext { reg_paths.json_ext.push(quote! { #nested_mod :: #p }); } - for p in nested_reg.text_ext { + for p in nested_out.reg.text_ext { reg_paths.text_ext.push(quote! { #nested_mod :: #p }); } // Any paths: nested's struct-scope → our struct-scope = prefix - // with our own module ident (where nested's top_level lands). - for p in nested_reg.json_any { + // with our own module ident (where nested's owned_top lands). + for p in nested_out.reg.json_any { reg_paths.json_any.push(quote! { #mod_ident :: #p }); } - for p in nested_reg.text_any { + for p in nested_out.reg.text_any { reg_paths.text_any.push(quote! { #mod_ident :: #p }); } - // Also generate views for nested messages if enabled. - // view_top (struct + impls) goes alongside the owned struct in the - // parent module; view_mod (oneof view enums) goes in the sub-module. - let view_mod_items = if ctx.config.generate_views { - let nested_name = nested_desc.name.as_deref().unwrap_or(""); - let nested_fqn = format!("{}.{}", proto_fqn, nested_name); - let (view_top, view_mod) = crate::view::generate_view_with_nesting( - MessageScope { - proto_fqn: &nested_fqn, - nesting: nesting + 1, - ..scope - }, - nested_desc, - nested_name, - )?; - nested_items.extend(view_top); - view_mod - } else { - quote! {} - }; - - if !mod_items.is_empty() || !view_mod_items.is_empty() { + if !nested_out.owned_mod.is_empty() { + let inner = nested_out.owned_mod; nested_items.extend(quote! { pub mod #nested_mod { #[allow(unused_imports)] use super::*; - #mod_items - #view_mod_items + #inner } }); } + // Ancillary trees: each nested message's tree is already wrapped in + // its own `pub mod {nested_name}`; we collect them as siblings. + nested_oneof_tree.extend(nested_out.oneof_tree); + nested_view_tree.extend(nested_out.view_tree); + nested_view_oneof_tree.extend(nested_out.view_oneof_tree); } // `extend` declarations nested inside this message. The consts land in @@ -578,15 +591,46 @@ fn generate_message_with_nesting( reg_paths.text_ext.push(quote! { #id }); } - // Module items: nested enums, nested message structs + sub-modules, - // and oneof enums. - let mod_items = quote! { + // Owned-module items: nested enums, nested message structs + sub-modules, + // and message-nested extensions. Oneof enums move out to `oneof_tree`. + let owned_mod = quote! { #(#nested_enums)* #nested_items - #(#oneof_enums)* #nested_extensions }; + // This message's view (struct + view-oneof enums), emitted with + // `nesting` = msg-nesting; view.rs adds the +2/+3 kind-depth offsets. + let (own_view_top, own_view_oneofs) = if ctx.config.generate_views { + crate::view::generate_view_with_nesting(scope, msg, rust_name)? + } else { + (TokenStream::new(), TokenStream::new()) + }; + + // Wrap ancillary streams in this message's `pub mod {snake_name}`. + // View structs sit *beside* their message's module (so `Foo`'s view is + // at `view::FooView`, `Foo.Bar`'s at `view::foo::BarView`); oneof and + // view-oneof enums sit *inside* it (so `Foo`'s oneof `kind` is at + // `oneof::foo::Kind`). + let wrap = |body: TokenStream| -> TokenStream { + if body.is_empty() { + return TokenStream::new(); + } + quote! { + pub mod #mod_ident { + #[allow(unused_imports)] + use super::*; + #body + } + } + }; + let oneof_tree = wrap(quote! { #(#oneof_enums)* #nested_oneof_tree }); + let view_oneof_tree = wrap(quote! { #own_view_oneofs #nested_view_oneof_tree }); + let view_tree = { + let nested_wrapped = wrap(nested_view_tree); + quote! { #own_view_top #nested_wrapped } + }; + // Generate a manual Debug impl that excludes internal __buffa_ fields. let struct_name_str = name_ident.to_string(); let debug_field_names: Vec = @@ -645,7 +689,14 @@ fn generate_message_with_nesting( #text_any_const }; - Ok((top_level, mod_items, reg_paths)) + Ok(MessageOutput { + owned_top: top_level, + owned_mod, + oneof_tree, + view_tree, + view_oneof_tree, + reg: reg_paths, + }) } // ── Custom Deserialize for messages with oneofs ────────────────────────────── @@ -666,7 +717,7 @@ fn generate_custom_deserialize( scope: MessageScope<'_>, msg: &DescriptorProto, name_ident: &proc_macro2::Ident, - mod_ident: &proc_macro2::Ident, + oneof_prefix: &TokenStream, resolver: &crate::imports::ImportResolver, has_extension_ranges: bool, oneof_idents: &std::collections::HashMap, @@ -703,7 +754,7 @@ fn generate_custom_deserialize( oneof, current_package, proto_fqn, - mod_ident, + oneof_prefix, features, resolver, oneof_idents, @@ -901,7 +952,7 @@ fn custom_deser_oneof_group( oneof: &crate::generated::descriptor::OneofDescriptorProto, current_package: &str, proto_fqn: &str, - mod_ident: &proc_macro2::Ident, + oneof_prefix: &TokenStream, features: &ResolvedFeatures, resolver: &crate::imports::ImportResolver, oneof_idents: &std::collections::HashMap, @@ -920,9 +971,8 @@ fn custom_deser_oneof_group( let var_ident = format_ident!("__oneof_{}", oneof_name); let field_ident = make_field_ident(oneof_name); - // Oneof enum lives in the message's module. let var_decl = - quote! { let mut #var_ident: ::core::option::Option<#mod_ident::#enum_ident> = None; }; + quote! { let mut #var_ident: ::core::option::Option<#oneof_prefix #enum_ident> = None; }; let mut arms = Vec::new(); for field in &msg.field { @@ -948,8 +998,7 @@ fn custom_deser_oneof_group( scalar_or_message_type_nested(ctx, field, current_package, nesting, features, resolver)? }; - // Module-qualified path for the oneof enum (lives in the message's module). - let qualified_enum: TokenStream = quote! { #mod_ident::#enum_ident }; + let qualified_enum: TokenStream = quote! { #oneof_prefix #enum_ident }; let arm = crate::oneof::oneof_variant_deser_arm(&crate::oneof::OneofVariantDeserInput { variant_ident: &variant_ident, variant_type: &variant_type, diff --git a/buffa-codegen/src/oneof.rs b/buffa-codegen/src/oneof.rs index 35f68db..5d0f0c8 100644 --- a/buffa-codegen/src/oneof.rs +++ b/buffa-codegen/src/oneof.rs @@ -106,6 +106,11 @@ fn collect_variant_info( // without codegen changes; only decode and JSON-deser need an // explicit Vec→Bytes conversion (see oneof_merge_arm and // oneof_variant_deser_arm). + // Oneof enums live at `buffa_::oneof::::`, which is + // `2 + (msg_nesting + 1)` levels below the package root + // (sentinel + `oneof` + one snake-case segment per message in + // the FQN path). `nesting` here is the owning message's + // msg_nesting, so the enum body sits at `nesting + 3`. let rust_type = if field_type == Type::TYPE_BYTES && field_uses_bytes(ctx, proto_fqn, proto_name) { quote! { ::bytes::Bytes } @@ -114,7 +119,7 @@ fn collect_variant_info( ctx, field, current_package, - nesting + 1, + nesting + 3, features, resolver, )? @@ -479,92 +484,26 @@ pub(crate) fn oneof_variant_deser_arm(input: &OneofVariantDeserInput<'_>) -> Tok } } -/// Collect the names already claimed in a message's Rust module that a -/// oneof enum must not collide with: nested message names, nested enum -/// names, and — when view generation is enabled — each nested message's -/// `{name}View` struct (emitted in the same module). -fn reserved_names_for_msg( - msg: &DescriptorProto, - generate_views: bool, -) -> std::collections::HashSet { - let mut reserved = std::collections::HashSet::new(); - for nested in &msg.nested_type { - if let Some(name) = &nested.name { - reserved.insert(name.clone()); - if generate_views { - reserved.insert(format!("{name}View")); - } - } - } - for nested_enum in &msg.enum_type { - if let Some(name) = &nested_enum.name { - reserved.insert(name.clone()); - } - } - reserved -} - -/// Build the Rust identifier for a oneof enum. -/// -/// With module-based nesting the enum lives inside the owning message's -/// module (`pub mod msg_name { pub enum FooOneof { ... } }`), so no -/// message prefix is needed. The enum name is always -/// `{PascalCase(oneof_name)}Oneof` regardless of whether siblings would -/// collide — uniform naming makes the generated type discoverable from -/// the `.proto` alone and prevents source-breaking renames when nested -/// types are added later. -/// -/// # Errors +/// Build the Rust identifier for a oneof enum: `{PascalCase(oneof_name)}`. /// -/// Returns [`CodeGenError::OneofNameConflict`] when a nested type or a -/// prior oneof in the same message already claims the suffixed name -/// (e.g. a nested message literally named `FooOneof` alongside -/// `oneof foo`). Users resolve these by renaming in the `.proto`. -fn oneof_enum_ident( - oneof_name: &str, - reserved: &std::collections::HashSet, - views_enabled: bool, - scope: &str, -) -> Result { - let pascal = to_pascal_case(oneof_name); - let name = format!("{pascal}Oneof"); - if reserved.contains(&name) || (views_enabled && reserved.contains(&format!("{name}View"))) { - return Err(CodeGenError::OneofNameConflict { - scope: scope.to_string(), - oneof_name: oneof_name.to_string(), - attempted: name, - }); - } - Ok(format_ident!("{}", name)) +/// No suffix and no collision check — oneof enums live in the dedicated +/// `buffa_::oneof::::` tree where they cannot collide with nested +/// types, nested enums, or view structs. Two sibling oneofs would only +/// produce the same ident if they share a proto name, which protoc +/// rejects at parse time. +fn oneof_enum_ident(oneof_name: &str) -> proc_macro2::Ident { + format_ident!("{}", to_pascal_case(oneof_name)) } /// Compute oneof enum identifiers for all non-synthetic oneofs in a message. /// -/// Every oneof enum is named `{PascalCase(oneof_name)}Oneof`; the reserved -/// set is grown after each allocation so two sibling oneofs cannot both -/// claim the same name (which could happen if the user declared e.g. -/// `oneof foo` alongside `oneof foo` — disallowed by protoc — or via a -/// hand-crafted descriptor). -/// -/// `scope` is the parent message's fully-qualified proto name, used only -/// in error diagnostics. `generate_views` must match -/// [`CodeGenContext::config.generate_views`](crate::context::CodeGenContext); -/// when true, nested `{n}View` names are added to the reserved set so the -/// view-side oneof enum (`{Name}OneofView`) also avoids collisions. -/// /// Returns a map from oneof declaration index to its Rust enum `Ident`. -/// Synthetic oneofs (proto3 `optional`) are omitted. -/// -/// # Errors -/// -/// Propagates [`CodeGenError::OneofNameConflict`] from -/// [`oneof_enum_ident`]. +/// Synthetic oneofs (proto3 `optional`) are omitted. Infallible: oneof +/// enums live in the `buffa_::oneof::` tree where collisions with +/// nested types are structurally impossible. pub(crate) fn resolve_oneof_idents( msg: &DescriptorProto, - scope: &str, - generate_views: bool, -) -> Result, CodeGenError> { - let mut reserved = reserved_names_for_msg(msg, generate_views); +) -> std::collections::HashMap { let mut result = std::collections::HashMap::new(); for (idx, oneof) in msg.oneof_decl.iter().enumerate() { let has_real_fields = msg.field.iter().any(|f| { @@ -574,16 +513,10 @@ pub(crate) fn resolve_oneof_idents( continue; } if let Some(oneof_name) = &oneof.name { - let ident = oneof_enum_ident(oneof_name, &reserved, generate_views, scope)?; - let owned = ident.to_string(); - if generate_views { - reserved.insert(format!("{owned}View")); - } - reserved.insert(owned); - result.insert(idx, ident); + result.insert(idx, oneof_enum_ident(oneof_name)); } } - Ok(result) + result } /// Build the Rust variant identifier for a oneof field. diff --git a/buffa-codegen/src/tests/comments.rs b/buffa-codegen/src/tests/comments.rs index d469c8c..3d4d6c9 100644 --- a/buffa-codegen/src/tests/comments.rs +++ b/buffa-codegen/src/tests/comments.rs @@ -39,7 +39,7 @@ fn test_message_comment_in_generated_code() { ) .expect("generation should succeed"); - let content = &result[0].content; + let content = &joined(&result); assert!( content.contains("Represents a person in the system."), "message doc comment should appear in generated code, got:\n{content}" @@ -74,7 +74,7 @@ fn test_field_comment_in_generated_code() { ) .expect("generation should succeed"); - let content = &result[0].content; + let content = &joined(&result); assert!( content.contains("The user's email address."), "field doc comment should appear in generated code, got:\n{content}" @@ -105,7 +105,7 @@ fn test_enum_comment_in_generated_code() { ) .expect("generation should succeed"); - let content = &result[0].content; + let content = &joined(&result); assert!( content.contains("Available colors."), "enum doc comment should appear, got:\n{content}" @@ -154,7 +154,7 @@ fn test_oneof_comment_in_generated_code() { ) .expect("generation should succeed"); - let content = &result[0].content; + let content = &joined(&result); assert!( content.contains("The event payload variant."), "oneof doc comment should appear, got:\n{content}" @@ -204,7 +204,7 @@ fn test_view_gets_same_comment_as_message() { let result = generate(&[file], &["view_comment.proto".to_string()], &config) .expect("generation should succeed"); - let content = &result[0].content; + let content = &joined(&result); // The comment should appear on both the owned struct and the view struct let count = content.matches("A greeter message.").count(); assert!( diff --git a/buffa-codegen/src/tests/custom_attributes.rs b/buffa-codegen/src/tests/custom_attributes.rs index 09786ea..ef5ee41 100644 --- a/buffa-codegen/src/tests/custom_attributes.rs +++ b/buffa-codegen/src/tests/custom_attributes.rs @@ -50,7 +50,7 @@ fn test_type_attribute_on_message() { }); let config = attr_config(vec![(".", "#[derive(Hash)]")], vec![], vec![]); let files = generate(&[file], &["msg.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("derive(Hash)"), "type_attribute should appear on struct: {content}" @@ -68,7 +68,7 @@ fn test_type_attribute_on_enum() { // Use an attribute not in the default enum derive set. let config = attr_config(vec![(".", "#[derive(serde::Serialize)]")], vec![], vec![]); let files = generate(&[file], &["color.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("derive(serde::Serialize)"), "type_attribute should appear on enum: {content}" @@ -95,7 +95,7 @@ fn test_type_attribute_scoped_to_specific_type() { vec![], ); let files = generate(&[file], &["multi.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Attribute should only appear in the Targeted region, not near Other. let targeted_pos = content .find("pub struct Targeted") @@ -129,7 +129,7 @@ fn test_message_attribute_on_struct_not_enum() { }); let config = attr_config(vec![], vec![], vec![(".", "#[serde(default)]")]); let files = generate(&[file], &["mixed.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Exactly one occurrence: on the struct, not the enum. let total = content.matches("serde(default)").count(); assert_eq!( @@ -168,7 +168,7 @@ fn test_enum_attribute_on_enum_not_struct() { let file = mixed_msg_enum_file(); let config = attr_config_full(vec![], vec![], vec![], vec![(".", "#[derive(Hash)]")]); let files = generate(&[file], &["mixed.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Hash already appears in the enum's built-in derive, so we use the // expanded `,` separator inside the user-supplied derive to avoid a // false-positive substring match. enum_attribute injects a *separate* @@ -209,18 +209,18 @@ fn test_enum_attribute_scoped_to_specific_enum() { vec![], vec![], vec![], - vec![(".Targeted", "#[allow(non_camel_case_types)]")], + vec![(".Targeted", "#[derive(Ord, PartialOrd)]")], ); let files = generate(&[file], &["two_enums.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; - let count = content.matches("non_camel_case_types").count(); + let content = &joined(&files); + let count = content.matches("derive(Ord, PartialOrd)").count(); assert_eq!( count, 1, "attribute should land on Targeted only, found {count} matches: {content}" ); // Verify the single match is associated with `Targeted`, not `Untouched`. - let attr_pos = content.find("non_camel_case_types").unwrap(); + let attr_pos = content.find("derive(Ord, PartialOrd)").unwrap(); let targeted_pos = content.find("pub enum Targeted").expect("Targeted enum"); let untouched_pos = content.find("pub enum Untouched").expect("Untouched enum"); assert!( @@ -244,7 +244,7 @@ fn test_enum_attribute_does_not_apply_to_struct() { vec![(".", "#[doc = \"enum_only_marker\"]")], ); let files = generate(&[file], &["mixed.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); let total = content.matches("enum_only_marker").count(); assert_eq!( total, 1, @@ -278,7 +278,7 @@ fn test_field_attribute_on_specific_field() { vec![], ); let files = generate(&[file], &["fields.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Exactly one occurrence, and it must be near secret_key not public_name. let total = content.matches("serde(skip)").count(); assert_eq!( @@ -309,7 +309,7 @@ fn test_field_attribute_catchall() { let config = attr_config(vec![], vec![(".", "#[doc = \"custom\"]")], vec![]); let files = generate(&[file], &["allfields.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Both fields should have the attribute. let count = content.matches("custom").count(); assert!( @@ -351,7 +351,7 @@ fn test_type_attribute_reaches_oneof_enum() { vec![], ); let files = generate(&[file], &["oo.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("#[derive(Hash)]"), "type_attribute should reach oneof enum: {content}" @@ -371,7 +371,7 @@ fn test_field_attribute_reaches_oneof_variant() { vec![], ); let files = generate(&[file], &["oo.proto".to_string()], &config).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("only_a"), "field_attribute should reach oneof variant: {content}" @@ -423,7 +423,7 @@ fn test_no_custom_attributes_by_default() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // No custom derives beyond the standard set. assert!( !content.contains("serde"), diff --git a/buffa-codegen/src/tests/generation.rs b/buffa-codegen/src/tests/generation.rs index c2b02f7..2e35f69 100644 --- a/buffa-codegen/src/tests/generation.rs +++ b/buffa-codegen/src/tests/generation.rs @@ -55,22 +55,69 @@ fn test_empty_file() { &CodeGenConfig::default(), ); let files = result.expect("empty file should generate without error"); - assert_eq!(files.len(), 1); - assert_eq!(files[0].name, "empty.rs"); + // 5 content files + 1 .mod.rs. + assert_eq!(files.len(), 6); + let stitcher = files + .iter() + .find(|f| f.kind == GeneratedFileKind::PackageMod) + .expect("stitcher present"); + assert_eq!(stitcher.name, "_.mod.rs"); assert!( - files[0].content.contains("@generated by protoc-gen-buffa"), + stitcher.content.contains("@generated"), "missing header comment" ); } #[test] -fn test_proto_path_to_rust_module() { +fn test_package_to_mod_filename() { + assert_eq!( + package_to_mod_filename("google.protobuf"), + "google.protobuf.mod.rs" + ); + assert_eq!(package_to_mod_filename("foo"), "foo.mod.rs"); + assert_eq!(package_to_mod_filename(""), "_.mod.rs"); assert_eq!( - proto_path_to_rust_module("google/protobuf/timestamp.proto"), - "google.protobuf.timestamp.rs" + proto_path_to_stem("google/protobuf/timestamp.proto"), + "google.protobuf.timestamp" ); - assert_eq!(proto_path_to_rust_module("foo.proto"), "foo.rs"); - assert_eq!(proto_path_to_rust_module("no_extension"), "no_extension.rs"); +} + +#[test] +fn test_multi_file_same_package_merged() { + // Two `.proto` files in the same package → one stitcher. + let mut a = proto3_file("a.proto"); + a.package = Some("shared.pkg".to_string()); + a.message_type.push(DescriptorProto { + name: Some("A".to_string()), + ..Default::default() + }); + let mut b = proto3_file("b.proto"); + b.package = Some("shared.pkg".to_string()); + b.message_type.push(DescriptorProto { + name: Some("B".to_string()), + ..Default::default() + }); + let files = generate( + &[a, b], + &["a.proto".to_string(), "b.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect("multi-file package should merge"); + // 2 protos × 5 content files + 1 stitcher = 11. + assert_eq!(files.len(), 11); + let stitcher = files + .iter() + .find(|f| f.kind == GeneratedFileKind::PackageMod) + .expect("stitcher present"); + assert_eq!(stitcher.name, "shared.pkg.mod.rs"); + let content = &joined(&files); + assert!(content.contains("pub struct A")); + assert!(content.contains("pub struct B")); + // Exactly one `pub mod buffa_` (in the stitcher), and both content + // files referenced from inside it. + assert_eq!(stitcher.content.matches("pub mod buffa_ {").count(), 1); + assert!(stitcher.content.contains(r#"include!("a.__view.rs");"#)); + assert!(stitcher.content.contains(r#"include!("b.__view.rs");"#)); } #[test] @@ -92,7 +139,7 @@ fn test_simple_enum() { &CodeGenConfig::default(), ) .expect("simple enum should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub enum Status"), "missing enum: {content}" @@ -140,7 +187,7 @@ fn test_enum_with_alias() { &CodeGenConfig::default(), ) .expect("aliased enum should generate"); - let content = &files[0].content; + let content = &joined(&files); // OK is a primary variant; SUCCESS is a const alias. assert!(content.contains("OK = 0"), "missing primary: {content}"); assert!( @@ -172,7 +219,7 @@ fn test_enum_values_emits_static_slice_in_declaration_order() { &CodeGenConfig::default(), ) .expect("enum should generate"); - let content = &files[0].content; + let content = &joined(&files); // Generated impl includes a `values()` returning a static slice in // proto declaration order. The generated body collapses to a single // line so we match against that exact form. @@ -206,7 +253,7 @@ fn test_enum_values_skips_aliases() { &CodeGenConfig::default(), ) .expect("aliased enum should generate"); - let content = &files[0].content; + let content = &joined(&files); // values() lists only primary variants — aliases are `pub const` items, // not enum variants, so they don't belong in the slice. assert!( @@ -248,7 +295,7 @@ fn test_type_url_top_level_with_package() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains(r#"TYPE_URL: &'static str = "type.googleapis.com/my.company.Person""#), "wrong or missing TYPE_URL: {content}" @@ -269,7 +316,7 @@ fn test_type_url_top_level_no_package() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains(r#"TYPE_URL: &'static str = "type.googleapis.com/Root""#), "wrong or missing TYPE_URL for no-package message: {content}" @@ -295,7 +342,7 @@ fn test_type_url_nested_message() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains(r#"TYPE_URL: &'static str = "type.googleapis.com/acme.Outer""#), "wrong Outer TYPE_URL: {content}" @@ -325,7 +372,7 @@ fn test_type_url_nested_no_package() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains(r#"TYPE_URL: &'static str = "type.googleapis.com/Outer""#), "wrong Outer TYPE_URL: {content}" @@ -360,7 +407,7 @@ fn test_type_url_doubly_nested() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains(r#"TYPE_URL: &'static str = "type.googleapis.com/pkg.Outer""#), "wrong Outer TYPE_URL: {content}" @@ -395,7 +442,7 @@ fn test_message_scalar_fields() { &CodeGenConfig::default(), ) .expect("scalar fields message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct Scalars"), "missing struct: {content}" @@ -456,7 +503,7 @@ fn test_message_nested_message_field() { &CodeGenConfig::default(), ) .expect("nested message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct Outer"), "missing Outer: {content}" @@ -517,7 +564,7 @@ fn test_message_map_field() { &CodeGenConfig::default(), ) .expect("map field message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct WithMap"), "missing struct: {content}" @@ -568,7 +615,7 @@ fn test_message_oneof() { &CodeGenConfig::default(), ) .expect("oneof message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct WithOneof"), "missing struct: {content}" @@ -623,7 +670,7 @@ fn test_message_proto3_optional() { &CodeGenConfig::default(), ) .expect("proto3 optional message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct WithOptional"), "missing struct: {content}" @@ -670,7 +717,7 @@ fn test_message_proto3_optional_string() { &CodeGenConfig::default(), ) .expect("proto3 optional string should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub label: Option<::buffa::alloc::string::String>"), "missing optional string field: {content}" @@ -718,7 +765,7 @@ fn test_message_proto3_optional_enum() { &CodeGenConfig::default(), ) .expect("proto3 optional enum should generate"); - let content = &files[0].content; + let content = &joined(&files); // Enum optional must resolve to EnumValue, not () assert!( content.contains("Option<::buffa::EnumValue>"), @@ -774,7 +821,7 @@ fn test_message_proto3_optional_bytes_and_bool() { &CodeGenConfig::default(), ) .expect("proto3 optional bytes/bool should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("Option<::buffa::alloc::vec::Vec>"), "missing optional bytes field: {content}" @@ -813,7 +860,7 @@ fn test_message_string_and_bytes_fields() { &CodeGenConfig::default(), ) .expect("string/bytes message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub name: ::buffa::alloc::string::String"), "missing string field: {content}" @@ -876,7 +923,7 @@ fn test_message_enum_field() { &CodeGenConfig::default(), ) .expect("enum field message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub status: ::buffa::EnumValue"), "missing enum field: {content}" @@ -914,7 +961,7 @@ fn test_repeated_packed_scalar() { &CodeGenConfig::default(), ) .expect("repeated scalar message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub ids: ::buffa::alloc::vec::Vec"), "missing ids field: {content}" @@ -967,7 +1014,7 @@ fn test_repeated_unpacked_string() { &CodeGenConfig::default(), ) .expect("repeated string message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub tags: ::buffa::alloc::vec::Vec<::buffa::alloc::string::String>"), "missing tags field: {content}" @@ -1013,7 +1060,7 @@ fn test_repeated_message_field() { &CodeGenConfig::default(), ) .expect("repeated message should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub items: ::buffa::alloc::vec::Vec"), "missing items field: {content}" @@ -1056,7 +1103,7 @@ fn test_repeated_enum_field() { &CodeGenConfig::default(), ) .expect("repeated enum should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub statuses: ::buffa::alloc::vec::Vec<::buffa::EnumValue>"), "missing statuses field: {content}" @@ -1212,7 +1259,7 @@ fn editions_delimited_message_encoding() { &CodeGenConfig::default(), ) .expect("generate"); - let content = &files[0].content; + let content = &joined(&files); // Field 3 (delim_child): inherits DELIMITED → StartGroup/EndGroup. assert!( @@ -1314,7 +1361,7 @@ fn nested_message_cross_package_reference_uses_correct_nesting() { ) .expect("codegen should succeed"); - let content = &files[0].content; + let content = &joined(&files); // Filter (nesting=1) must emit 3 supers to reach the common ancestor: // super (svc) → super (v1) → super (admin) → v1::biz::Status @@ -1429,7 +1476,7 @@ fn doubly_nested_message_paths_use_correct_nesting() { }; let files = generate(&[file_admin, file_biz], &["admin.proto".into()], &config) .expect("codegen should succeed"); - let content = &files[0].content; + let content = &joined(&files); // Inner is at nesting=3 (inside svc::outer::inner), so every cross- // package reference must emit 4 supers. diff --git a/buffa-codegen/src/tests/json_codegen.rs b/buffa-codegen/src/tests/json_codegen.rs index 0b038c9..be76311 100644 --- a/buffa-codegen/src/tests/json_codegen.rs +++ b/buffa-codegen/src/tests/json_codegen.rs @@ -27,7 +27,7 @@ fn test_json_enum_has_custom_impls_and_from_proto_name() { }); let files = generate(&[file], &["color.proto".to_string()], &json_config()).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Custom Serialize impl uses proto_name assert!( content.contains("impl ::serde::Serialize for Color"), @@ -67,7 +67,7 @@ fn test_json_enum_alias_in_from_proto_name() { }); let files = generate(&[file], &["status.proto".to_string()], &json_config()).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Primary name must be in from_proto_name assert!( content.contains(r#""STARTED" => ::core::option::Option::Some(Self::STARTED)"#), @@ -124,7 +124,7 @@ fn test_json_message_has_derive_and_field_attrs() { let files = generate(&[file], &["scalars_json.proto".to_string()], &json_config()) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Struct gets serde derive and default assert!( content.contains("derive(::serde::Serialize, ::serde::Deserialize)"), @@ -200,7 +200,7 @@ fn test_json_oneof_field_is_flattened() { let files = generate(&[file], &["oneof_json.proto".to_string()], &json_config()) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // The oneof field uses flatten so its variants appear as top-level JSON fields. assert!( content.contains("serde(flatten)"), @@ -247,7 +247,7 @@ fn test_json_oneof_deserialize_null_and_duplicate_handling() { let files = generate(&[file], &["oneof_deser.proto".to_string()], &json_config()) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Null handling: each arm wraps with NullableDeserializeSeed assert!( @@ -332,7 +332,7 @@ fn test_json_oneof_value_variant_forwards_null() { &json_config(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // The `meta` (Value) arm should use DefaultDeserializeSeed directly // (forward null), not NullableDeserializeSeed (intercept null). // Look for the meta match arm pattern: it should NOT be nullable. @@ -364,7 +364,7 @@ fn test_no_serde_attrs_without_generate_json_flag() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( !content.contains("serde"), "serde attrs must be absent without generate_json: {content}" @@ -383,7 +383,7 @@ fn test_json_any_const_emitted_per_message() { }); let files = generate(&[file], &["any_entry.proto".to_string()], &json_config()) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub const __WIDGET_JSON_ANY: ::buffa::type_registry::JsonAnyEntry"), "missing JSON Any const: {content}" @@ -426,17 +426,17 @@ fn test_register_types_emitted_with_json_any_only() { }); let files = generate(&[file], &["reg.proto".to_string()], &json_config()).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry)"), "missing register_types fn: {content}" ); assert!( - content.contains("reg.register_json_any(__FOO_JSON_ANY)"), + content.contains("reg.register_json_any(super::__FOO_JSON_ANY)"), "missing Foo JSON Any registration: {content}" ); assert!( - content.contains("reg.register_json_any(__BAR_JSON_ANY)"), + content.contains("reg.register_json_any(super::__BAR_JSON_ANY)"), "missing Bar JSON Any registration: {content}" ); // No generate_text → no register_text_* calls in the body. @@ -461,13 +461,13 @@ fn test_register_types_includes_nested_message_any_entries() { }); let files = generate(&[file], &["nested_any.proto".to_string()], &json_config()) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( - content.contains("reg.register_json_any(__OUTER_JSON_ANY)"), + content.contains("reg.register_json_any(super::__OUTER_JSON_ANY)"), "missing top-level Outer: {content}" ); assert!( - content.contains("reg.register_json_any(outer::__INNER_JSON_ANY)"), + content.contains("reg.register_json_any(super::outer::__INNER_JSON_ANY)"), "missing nested Inner path: {content}" ); } @@ -485,7 +485,7 @@ fn test_any_entry_not_emitted_without_generate_json_or_text() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( !content.contains("_JSON_ANY") && !content.contains("_TEXT_ANY"), "Any consts must be absent: {content}" @@ -511,7 +511,7 @@ fn test_text_any_emitted_independent_of_json() { ..Default::default() }; let files = generate(&[file], &["textonly.proto".to_string()], &cfg).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub const __MSG_TEXT_ANY: ::buffa::type_registry::TextAnyEntry"), "missing TEXT_ANY const: {content}" @@ -525,7 +525,7 @@ fn test_text_any_emitted_independent_of_json() { "JSON_ANY must be absent with generate_json off: {content}" ); assert!( - content.contains("reg.register_text_any(__MSG_TEXT_ANY)"), + content.contains("reg.register_text_any(super::__MSG_TEXT_ANY)"), "missing register_text_any call: {content}" ); assert!( @@ -562,7 +562,7 @@ fn message_named_result_does_not_shadow_std_result_in_serde() { let files = generate(&[file], &["job.proto".to_string()], &json_config()).expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // The custom Deserialize impl for Result must use ::core::result::Result, // not bare `Result` which would resolve to the proto message type. diff --git a/buffa-codegen/src/tests/mod.rs b/buffa-codegen/src/tests/mod.rs index 340cb45..0f2143e 100644 --- a/buffa-codegen/src/tests/mod.rs +++ b/buffa-codegen/src/tests/mod.rs @@ -36,6 +36,18 @@ pub(super) fn make_field(name: &str, number: i32, label: Label, ty: Type) -> Fie } } +/// Concatenate all generated-file contents for snapshot-style assertions. +/// +/// Each proto now emits 5 content files + 1 `.mod.rs`; tests that assert +/// "the output contains substring X" don't care which file it lands in. +pub(super) fn joined(files: &[GeneratedFile]) -> String { + files + .iter() + .map(|f| f.content.as_str()) + .collect::>() + .join("\n") +} + mod comments; mod custom_attributes; mod generation; diff --git a/buffa-codegen/src/tests/naming.rs b/buffa-codegen/src/tests/naming.rs index 0724a76..d876e46 100644 --- a/buffa-codegen/src/tests/naming.rs +++ b/buffa-codegen/src/tests/naming.rs @@ -140,10 +140,10 @@ fn test_different_snake_case_names_no_conflict() { } #[test] -fn test_nested_type_oneof_coexists_with_suffix() { - // Nested message "MyField" and oneof "my_field" coexist: the oneof - // enum is always named "MyFieldOneof" under the uniform-suffix rule, - // which happens to be collision-free against the nested struct. +fn test_nested_type_oneof_coexist_in_separate_trees() { + // Nested message "MyField" and oneof "my_field" coexist structurally: + // the oneof enum lives at `buffa_::oneof::parent::MyField`, the nested + // struct at `parent::MyField`. let msg = DescriptorProto { name: Some("Parent".to_string()), nested_type: vec![DescriptorProto { @@ -168,11 +168,11 @@ fn test_nested_type_oneof_coexists_with_suffix() { let config = CodeGenConfig::default(); let result = generate(&[file], &["test.proto".to_string()], &config); - let files = result.expect("nested type + oneof name collision should resolve, not error"); - let content = &files[0].content; + let files = result.expect("nested type + oneof same-name should coexist"); + let content = &joined(&files); assert!( - content.contains("MyFieldOneof"), - "oneof enum should be suffixed with Oneof: {content}" + content.contains("pub enum MyField {"), + "oneof enum should drop Oneof suffix: {content}" ); assert!( content.contains("pub struct MyField"), @@ -239,105 +239,22 @@ fn test_nested_enum_oneof_coexists_with_suffix() { let config = CodeGenConfig::default(); let result = generate(&[file], &["test.proto".to_string()], &config); - let files = result.expect("nested enum + oneof name collision should resolve, not error"); - let content = &files[0].content; - assert!( - content.contains("RegionCodesOneof"), - "oneof enum should be suffixed with Oneof: {content}" - ); - assert!( - content.contains("pub enum RegionCodes"), - "nested enum should keep its original name: {content}" - ); -} - -#[test] -fn test_nested_type_oneof_view_uses_suffix() { - // When view generation is on, the view enum uses the uniform - // suffixed name (MyFieldOneofView) alongside its owned counterpart. - let msg = DescriptorProto { - name: Some("Parent".to_string()), - nested_type: vec![DescriptorProto { - name: Some("MyField".to_string()), - ..Default::default() - }], - oneof_decl: vec![OneofDescriptorProto { - name: Some("my_field".to_string()), - ..Default::default() - }], - field: vec![{ - let mut f = make_field("val", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING); - f.oneof_index = Some(0); - f - }], - ..Default::default() - }; - let mut file = proto3_file("test.proto"); - file.package = Some("pkg".to_string()); - file.message_type = vec![msg]; - - let config = CodeGenConfig::default(); // views enabled by default - let result = generate(&[file], &["test.proto".to_string()], &config); - let files = result.expect("view codegen should handle oneof rename"); - let content = &files[0].content; - assert!( - content.contains("MyFieldOneofView"), - "view enum should use suffixed name: {content}" - ); -} - -#[test] -fn test_oneof_coexists_with_nested_view_struct_name() { - // Nested message `MyFieldView` + oneof `my_field` with views enabled: - // under the uniform-suffix rule the oneof enum is `MyFieldOneof` and - // its view is `MyFieldOneofView`; neither name collides with the - // nested message's view struct (also `MyFieldView`). - let msg = DescriptorProto { - name: Some("Parent".to_string()), - nested_type: vec![DescriptorProto { - name: Some("MyFieldView".to_string()), - ..Default::default() - }], - oneof_decl: vec![OneofDescriptorProto { - name: Some("my_field".to_string()), - ..Default::default() - }], - field: vec![{ - let mut f = make_field("val", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING); - f.oneof_index = Some(0); - f - }], - ..Default::default() - }; - let mut file = proto3_file("test.proto"); - file.package = Some("pkg".to_string()); - file.message_type = vec![msg]; - - let config = CodeGenConfig::default(); - let files = generate(&[file], &["test.proto".to_string()], &config) - .expect("uniform suffix keeps the oneof clear of nested view name"); - let content = &files[0].content; - assert!( - content.contains("pub enum MyFieldOneof {"), - "owned oneof enum should be MyFieldOneof: {content}" - ); - assert!( - content.contains("pub enum MyFieldOneofView<"), - "view oneof enum should be MyFieldOneofView<'a>: {content}" - ); - // The nested message's own view struct remains unchanged. - assert!( - content.contains("pub struct MyFieldView"), - "nested message view struct must be preserved: {content}" + let files = result.expect("nested enum + oneof same-name should coexist"); + let content = &joined(&files); + // Both `pub enum RegionCodes` declarations exist — one in the owned + // tree (the proto enum), one in `buffa_::oneof::` (the oneof enum). + assert_eq!( + content.matches("pub enum RegionCodes {").count(), + 2, + "expected two RegionCodes enums (proto + oneof): {content}" ); } #[test] fn test_sibling_oneof_view_names_do_not_collide() { - // Two sibling oneofs `my_field` and `my_field_view`. Under the - // uniform-suffix rule they become `MyFieldOneof`/`MyFieldOneofView` - // and `MyFieldViewOneof`/`MyFieldViewOneofView` — never collide with - // each other or with their own view counterparts. + // Two sibling oneofs `my_field` and `my_field_view`. Both live in + // `buffa_::oneof::parent::{MyField, MyFieldView}` — distinct because + // protoc rejects duplicate oneof names. let msg = DescriptorProto { name: Some("Parent".to_string()), oneof_decl: vec![ @@ -374,212 +291,119 @@ fn test_sibling_oneof_view_names_do_not_collide() { &CodeGenConfig::default(), ) .expect("sibling oneof names must resolve without collision"); - let content = &files[0].content; + let content = &joined(&files); assert!( - content.contains("pub enum MyFieldOneof {"), - "first oneof owned enum should be MyFieldOneof: {content}" + content.contains("pub enum MyField {"), + "first oneof owned enum: {content}" ); assert!( - content.contains("pub enum MyFieldOneofView<"), - "first oneof view enum should be MyFieldOneofView<'a>: {content}" - ); - assert!( - content.contains("pub enum MyFieldViewOneof {"), - "second oneof owned enum should be MyFieldViewOneof: {content}" - ); - assert!( - content.contains("pub enum MyFieldViewOneofView<"), - "second oneof view enum should be MyFieldViewOneofView<'a>: {content}" + content.contains("pub enum MyFieldView {"), + "second oneof owned enum: {content}" ); } #[test] -fn test_oneof_suffix_conflict_error_includes_scope() { - // Verify the diagnostic carries the parent message's FQN so users can - // locate which message triggered the error in a large descriptor set. - let msg = DescriptorProto { - name: Some("Parent".to_string()), - nested_type: vec![ - DescriptorProto { - name: Some("MyField".to_string()), - ..Default::default() - }, - DescriptorProto { - name: Some("MyFieldOneof".to_string()), - ..Default::default() - }, - ], - oneof_decl: vec![OneofDescriptorProto { - name: Some("my_field".to_string()), - ..Default::default() - }], - field: vec![{ - let mut f = make_field("val", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING); - f.oneof_index = Some(0); - f - }], - ..Default::default() - }; +fn test_foo_and_fooview_siblings_coexist() { + // Messages "Foo" and "FooView" — Foo's view (`buffa_::view::FooView`) + // and the owned `FooView` struct (`pkg::FooView`) live in different + // trees. Previously rejected via ViewNameConflict. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); - file.message_type = vec![msg]; - - let err = generate( - &[file], - &["test.proto".to_string()], - &CodeGenConfig::default(), - ) - .expect_err("double collision must error"); - match err { - CodeGenError::OneofNameConflict { - scope, - oneof_name, - attempted, - } => { - assert_eq!(scope, "pkg.Parent"); - assert_eq!(oneof_name, "my_field"); - assert_eq!(attempted, "MyFieldOneof"); - } - other => panic!("expected OneofNameConflict, got {other:?}"), - } -} - -#[test] -fn test_oneof_name_conflict_errors() { - // A nested type literally named "MyFieldOneof" alongside oneof - // "my_field" leaves the uniform-suffix name with nowhere to go — - // users must rename one side in the `.proto`. - let msg = DescriptorProto { - name: Some("Parent".to_string()), - nested_type: vec![DescriptorProto { - name: Some("MyFieldOneof".to_string()), + file.message_type = vec![ + DescriptorProto { + name: Some("Foo".to_string()), ..Default::default() - }], - oneof_decl: vec![OneofDescriptorProto { - name: Some("my_field".to_string()), + }, + DescriptorProto { + name: Some("FooView".to_string()), ..Default::default() - }], - field: vec![{ - let mut f = make_field("val", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING); - f.oneof_index = Some(0); - f - }], - ..Default::default() - }; - let mut file = proto3_file("test.proto"); - file.package = Some("pkg".to_string()); - file.message_type = vec![msg]; + }, + ]; let config = CodeGenConfig::default(); let result = generate(&[file], &["test.proto".to_string()], &config); - assert!(result.is_err()); - let err = result.unwrap_err().to_string(); - assert!( - err.contains("MyFieldOneof"), - "error should mention the attempted name: {err}" - ); + let files = result.expect("Foo + FooView siblings should coexist"); + let content = &joined(&files); + assert!(content.contains("pub struct Foo {")); + // pkg::FooView (owned) and buffa_::view::FooView<'a> (Foo's view). + assert!(content.contains("pub struct FooView {")); + assert!(content.contains("pub struct FooView<'a>")); } #[test] -fn test_sibling_oneofs_get_distinct_names() { - // Two oneofs `my_field` and `my_field_oneof` — both want - // `MyFieldOneof` as their Rust name. Sequential allocation must - // assign distinct names, e.g. `MyFieldOneof` and `MyFieldOneofOneof`. - let msg = DescriptorProto { - name: Some("Parent".to_string()), - oneof_decl: vec![ - OneofDescriptorProto { - name: Some("my_field".to_string()), - ..Default::default() - }, - OneofDescriptorProto { - name: Some("my_field_oneof".to_string()), - ..Default::default() - }, - ], - field: vec![ - { - let mut f = make_field("a", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING); - f.oneof_index = Some(0); - f - }, - { - let mut f = make_field("b", 2, Label::LABEL_OPTIONAL, Type::TYPE_STRING); - f.oneof_index = Some(1); - f - }, - ], - ..Default::default() - }; +fn test_top_level_message_named_view_compiles() { + // Regression vs PR #54's bug: a top-level `message View { Inner }` + // emits `pub mod view {}` (its nested-type module). Ancillary types + // live under `buffa_::view::`, NOT a bare `pub mod view {}`, so no + // E0428. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); - file.message_type = vec![msg]; - - let config = CodeGenConfig { - generate_views: false, + file.message_type = vec![DescriptorProto { + name: Some("View".to_string()), + nested_type: vec![DescriptorProto { + name: Some("Inner".to_string()), + ..Default::default() + }], ..Default::default() - }; - let result = generate(&[file], &["test.proto".to_string()], &config); - let files = result.expect("sibling oneofs should get distinct names"); - let content = &files[0].content; - assert!( - content.contains("MyFieldOneof"), - "first oneof should be suffixed: {content}" - ); - assert!( - content.contains("MyFieldOneofOneof"), - "second oneof should be double-suffixed: {content}" + }]; + + let result = generate( + &[file], + &["test.proto".to_string()], + &CodeGenConfig::default(), ); + let files = result.expect("top-level `message View` must compile"); + // Each content file must parse individually. + for f in files + .iter() + .filter(|f| f.kind != GeneratedFileKind::PackageMod) + { + syn::parse_str::(&f.content).expect("generated content must parse"); + } + let content = joined(&files); + // The sentinel wraps the ancillary tree; the message's own + // `pub mod view` (its nested-type module) is in the owned content. + assert!(content.contains("pub mod buffa_ {")); } #[test] -fn test_view_name_conflict_detected() { - // Messages "Foo" and "FooView" — Foo's view type collides with FooView struct. +fn test_reserved_sentinel_package_segment_rejected() { let mut file = proto3_file("test.proto"); - file.package = Some("pkg".to_string()); - file.message_type = vec![ - DescriptorProto { - name: Some("Foo".to_string()), - ..Default::default() - }, - DescriptorProto { - name: Some("FooView".to_string()), - ..Default::default() - }, - ]; - - let config = CodeGenConfig::default(); // views enabled by default - let result = generate(&[file], &["test.proto".to_string()], &config); - assert!(result.is_err()); - let err = result.unwrap_err().to_string(); - assert!(err.contains("Foo"), "should mention owned message: {err}"); + file.package = Some("foo.buffa_".to_string()); + file.message_type = vec![DescriptorProto { + name: Some("X".to_string()), + ..Default::default() + }]; + let err = generate( + &[file], + &["test.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect_err("buffa_ package segment must be rejected"); assert!( - err.contains("FooView"), - "should mention view collision: {err}" + matches!(err, CodeGenError::ReservedModuleName { .. }), + "expected ReservedModuleName, got {err:?}" ); } #[test] -fn test_view_name_conflict_not_checked_when_views_disabled() { +fn test_reserved_sentinel_message_name_rejected() { + // Message name `Buffa_` snake_cases to `buffa_`. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); - file.message_type = vec![ - DescriptorProto { - name: Some("Foo".to_string()), - ..Default::default() - }, - DescriptorProto { - name: Some("FooView".to_string()), - ..Default::default() - }, - ]; - - let config = CodeGenConfig { - generate_views: false, + file.message_type = vec![DescriptorProto { + name: Some("Buffa_".to_string()), ..Default::default() - }; - let result = generate(&[file], &["test.proto".to_string()], &config); - assert!(result.is_ok(), "no conflict when views are disabled"); + }]; + let err = generate( + &[file], + &["test.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect_err("Buffa_ message name must be rejected"); + let msg = err.to_string(); + assert!(msg.contains("buffa_"), "error should name sentinel: {msg}"); + assert!(msg.contains("pkg.Buffa_"), "error should locate it: {msg}"); } #[test] @@ -667,7 +491,7 @@ fn test_nested_message_named_option_does_not_shadow_prelude() { }; let result = generate(&[file], &["option_shadow.proto".to_string()], &config); let files = result.expect("nested Option message should not break codegen"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct Option"), "nested Option struct must exist: {content}" @@ -717,7 +541,7 @@ fn test_top_level_message_named_option_qualifies_option() { }; let result = generate(&[file], &["option_top.proto".to_string()], &config); let files = result.expect("top-level Option should not break codegen"); - let content = &files[0].content; + let content = &joined(&files); // The Wrapper struct must use qualified Option for its optional field. assert!( content.contains("::core::option::Option<"), @@ -786,7 +610,7 @@ fn test_nested_option_blocked_propagates_through_sibling_subtree() { }; let files = generate(&[file], &["option_deep.proto".to_string()], &config) .expect("nested Option sibling should not break codegen"); - let content = &files[0].content; + let content = &joined(&files); // `Middle.note` lives in `mod outer` (Option in scope); `Inner.x` lives // in `mod outer::middle` (Option in scope via `use super::*`). Both must // be qualified. @@ -834,7 +658,7 @@ fn test_message_named_type_with_nested() { }; let result = generate(&[file], &["type_test.proto".to_string()], &config); let files = result.expect("message named Type should generate valid code"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct Type"), "missing struct Type: {content}" @@ -888,7 +712,7 @@ fn test_message_with_oneof_field_named_type() { }; let result = generate(&[file], &["checked.proto".to_string()], &config); let files = result.expect("Type message with oneof 'type' field should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub struct Type"), "missing struct Type: {content}" @@ -937,7 +761,7 @@ fn test_oneof_variant_named_self_escapes_to_self_underscore() { &CodeGenConfig::default(), ) .expect("oneof with `self` variant must compile"); - let content = &files[0].content; + let content = &joined(&files); // The reserved `Self` is suffixed to `Self_` by `make_field_ident`; // the bare `Manager` variant is unaffected. assert!( diff --git a/buffa-codegen/src/tests/proto2.rs b/buffa-codegen/src/tests/proto2.rs index a088166..9322cdd 100644 --- a/buffa-codegen/src/tests/proto2.rs +++ b/buffa-codegen/src/tests/proto2.rs @@ -32,7 +32,7 @@ fn test_proto2_optional_scalar_is_option() { &CodeGenConfig::default(), ) .expect("proto2 optional scalar should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub count: Option"), "proto2 optional int32 must be Option: {content}" @@ -58,7 +58,7 @@ fn test_proto2_required_scalar_is_bare_type_and_always_encoded() { &CodeGenConfig::default(), ) .expect("proto2 required scalar should generate"); - let content = &files[0].content; + let content = &joined(&files); // Required fields use the bare type, not Option. assert!( content.contains("pub count: i32"), @@ -91,7 +91,7 @@ fn test_proto2_repeated_scalar_is_unpacked_by_default() { &CodeGenConfig::default(), ) .expect("proto2 repeated scalar should generate"); - let content = &files[0].content; + let content = &joined(&files); // Unpacked write_to: no packed-payload size accumulation. // (The view decode arm uses `let payload = borrow_bytes(...)` for its // lenient packed-accept path, so we look for the typed accumulator @@ -133,7 +133,7 @@ fn test_proto2_optional_enum_is_option_enum_value() { &CodeGenConfig::default(), ) .expect("proto2 optional enum should generate"); - let content = &files[0].content; + let content = &joined(&files); assert!( content.contains("pub color: Option"), "proto2 optional enum must be Option (closed enum): {content}" @@ -161,7 +161,7 @@ fn test_proto2_enum_default_is_first_declared_variant() { &CodeGenConfig::default(), ) .expect("proto2 enum default should generate"); - let content = &files[0].content; + let content = &joined(&files); // Default impl must use HIGH (first declared), not NONE (zero-valued). assert!( content.contains("impl ::core::default::Default for Priority"), diff --git a/buffa-codegen/src/tests/view_codegen.rs b/buffa-codegen/src/tests/view_codegen.rs index d785dc1..6e640f8 100644 --- a/buffa-codegen/src/tests/view_codegen.rs +++ b/buffa-codegen/src/tests/view_codegen.rs @@ -33,7 +33,7 @@ fn test_view_explicit_presence_scalar_is_option() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // View struct field should be Option. assert!( content.contains("pub value: Option"), @@ -78,7 +78,7 @@ fn test_view_repeated_message_field() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; + let content = &joined(&files); // Both Item and Container views should be generated. assert!( content.contains("pub struct ItemView"), @@ -146,20 +146,22 @@ fn test_view_oneof_with_message_variant() { &CodeGenConfig::default(), ) .expect("should generate"); - let content = &files[0].content; - // View struct must have an optional PayloadOneofView field. + let content = &joined(&files); + // View struct must reference its view-oneof enum at the sentinel path. + // (Prettyplease may wrap the path across lines, so check the + // tail segment.) assert!( - content.contains("pub payload: ::core::option::Option: {content}" + content.contains("buffa_::view::oneof::request::Payload"), + "RequestView must reference buffa_::view::oneof::request::Payload: {content}" ); // The oneof view enum must have both variants. assert!( content.contains("Count(i32)"), - "PayloadView must have Count(i32): {content}" + "Payload view must have Count(i32): {content}" ); assert!( - content.contains("Body(::buffa::alloc::boxed::Box Result<(TokenStream, TokenStream), CodeGenError> { - let scope = MessageScope { - ctx, - current_package, - proto_fqn, - features, - nesting: 0, - }; - generate_view_with_nesting(scope, msg, rust_name) -} - +/// `scope.nesting` is the **message-nesting** of the owning message (0 for +/// top-level). View structs are emitted into `buffa_::view::::`, +/// so the view body's total depth below the package root is +/// `scope.nesting + 2`; view-oneof enums go to +/// `buffa_::view::oneof::::`, depth `scope.nesting + 4`. pub(crate) fn generate_view_with_nesting( scope: MessageScope<'_>, msg: &DescriptorProto, @@ -91,40 +76,55 @@ pub(crate) fn generate_view_with_nesting( ) -> Result<(TokenStream, TokenStream), CodeGenError> { let MessageScope { ctx, + current_package, proto_fqn, features, - .. + nesting, } = scope; - let proto_name = msg.name.as_deref().unwrap_or(rust_name); - let mod_name_str = crate::oneof::to_snake_case(proto_name); - let mod_ident = make_field_ident(&mod_name_str); // Note: nested views are generated by generate_message, not here. // This function only generates the view for the current message. - let oneof_idents = - crate::oneof::resolve_oneof_idents(msg, proto_fqn, ctx.config.generate_views)?; + let oneof_idents = crate::oneof::resolve_oneof_idents(msg); let view_ident = format_ident!("{}View", rust_name); let owned_ident = format_ident!("{}", rust_name); + // Total module depth of the view-struct body below the package root. + // All field-type / decode-arm / to-owned helpers below resolve paths + // relative to this depth, so pass `view_scope` (not `scope`). + let view_depth = nesting + 2; + let view_scope = MessageScope { + nesting: view_depth, + ..scope + }; + // Path prefixes from the view struct's scope to its ancillary enums. + let view_oneof_prefix = ancillary_prefix( + AncillaryKind::ViewOneof, + current_package, + proto_fqn, + view_depth, + ); + let owned_oneof_prefix = + ancillary_prefix(AncillaryKind::Oneof, current_package, proto_fqn, view_depth); + // View struct fields (excludes real-oneof members, map fields, and // unsupported types like groups). let direct_fields = msg .field .iter() .filter(|f| is_supported_field_type(f.r#type.unwrap_or_default())) - .map(|f| view_struct_field(scope, msg, f)) + .map(|f| view_struct_field(view_scope, msg, f)) .collect::, _>>()? .into_iter() .flatten() .collect::>(); - // One `Option>` per non-synthetic oneof (module-qualified). + // One `Option>` per non-synthetic oneof. let oneof_struct_fields = - oneof_view_struct_fields(ctx, msg, &mod_ident, features, &oneof_idents)?; + oneof_view_struct_fields(ctx, msg, &view_oneof_prefix, features, &oneof_idents)?; - // Oneof view enum definitions (go inside the module). + // Oneof view enum definitions (go into `buffa_::view::oneof::::`). let oneof_view_enums = msg .oneof_decl .iter() @@ -134,10 +134,16 @@ pub(crate) fn generate_view_with_nesting( // decode_view match arms. let (scalar_arms, repeated_arms, oneof_arms) = - build_decode_arms(scope, msg, &mod_ident, &oneof_idents)?; + build_decode_arms(view_scope, msg, &view_oneof_prefix, &oneof_idents)?; // to_owned_message field initialisers. - let owned_fields = build_to_owned_fields(scope, msg, &mod_ident, &oneof_idents)?; + let owned_fields = build_to_owned_fields( + view_scope, + msg, + &view_oneof_prefix, + &owned_oneof_prefix, + &oneof_idents, + )?; let unknown_fields_field = if ctx.config.preserve_unknown_fields { quote! { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } @@ -176,6 +182,17 @@ pub(crate) fn generate_view_with_nesting( #(#oneof_view_enums)* }; + // Path from the view-struct scope (depth `nesting + 2`) to its owned + // counterpart at the mirrored owned-tree position. Same package by + // construction; `rust_type_relative` returns `super^(n+2)::`. + let owned_path: TokenStream = { + let dotted = format!(".{proto_fqn}"); + let p = ctx + .rust_type_relative(&dotted, current_package, view_depth) + .unwrap_or_else(|| owned_ident.to_string()); + rust_path_to_tokens(&p) + }; + let view_doc = crate::comments::doc_attrs(ctx.comment(proto_fqn)); let top_level = quote! { @@ -244,7 +261,7 @@ pub(crate) fn generate_view_with_nesting( } impl<'a> ::buffa::MessageView<'a> for #view_ident<'a> { - type Owned = #owned_ident; + type Owned = #owned_path; fn decode_view( buf: &'a [u8], @@ -268,10 +285,10 @@ pub(crate) fn generate_view_with_nesting( // unify the `UnknownFields` (no-wrapper) and `__ExtJson` // (generate_json wrapper) cases; no-op in the former. #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> #owned_ident { + fn to_owned_message(&self) -> #owned_path { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; - #owned_ident { + #owned_path { #(#owned_fields)* ..::core::default::Default::default() } @@ -560,13 +577,13 @@ fn message_view_has_borrowing_field( fn oneof_view_struct_fields( ctx: &CodeGenContext, msg: &DescriptorProto, - mod_ident: &proc_macro2::Ident, + view_oneof_prefix: &TokenStream, features: &ResolvedFeatures, oneof_idents: &std::collections::HashMap, ) -> Result, CodeGenError> { let mut out = Vec::new(); for (idx, oneof) in msg.oneof_decl.iter().enumerate() { - let base_ident = match oneof_idents.get(&idx) { + let enum_ident = match oneof_idents.get(&idx) { Some(id) => id, None => continue, }; @@ -583,14 +600,13 @@ fn oneof_view_struct_fields( .as_deref() .ok_or(CodeGenError::MissingField("oneof.name"))?; let field_ident = make_field_ident(oneof_name); - let view_enum = format_ident!("{}View", base_ident); let generics = if oneof_view_needs_lifetime(ctx, &fields, features) { quote! { <'a> } } else { quote! {} }; out.push(quote! { - pub #field_ident: ::core::option::Option<#mod_ident::#view_enum #generics>, + pub #field_ident: ::core::option::Option<#view_oneof_prefix #enum_ident #generics>, }); } Ok(out) @@ -623,7 +639,14 @@ fn generate_oneof_view_enum( return Ok(TokenStream::new()); } - let view_enum = format_ident!("{}View", base_ident); + // View-oneof enums share the owned oneof's identifier (no `View` suffix) + // — the `buffa_::view::oneof::` tree position disambiguates. They live + // at depth `msg_nesting + 4` (sentinel + view + oneof + msg_path). + let enum_body_depth = scope.nesting + 4; + let body_scope = MessageScope { + nesting: enum_body_depth, + ..scope + }; let variants = fields .iter() @@ -639,11 +662,11 @@ fn generate_oneof_view_enum( Type::TYPE_STRING => quote! { &'a str }, Type::TYPE_BYTES => quote! { &'a [u8] }, Type::TYPE_MESSAGE | Type::TYPE_GROUP => { - let view_ty = resolve_view_ty_tokens(scope.deeper(), f)?; + let view_ty = resolve_view_ty_tokens(body_scope, f)?; quote! { ::buffa::alloc::boxed::Box<#view_ty> } } Type::TYPE_ENUM => { - let et = resolve_enum_ty(scope.deeper(), f)?; + let et = resolve_enum_ty(body_scope, f)?; if is_closed_enum(&f_features) { quote! { #et } } else { @@ -664,7 +687,7 @@ fn generate_oneof_view_enum( Ok(quote! { #[derive(Clone, Debug)] - pub enum #view_enum #generics { + pub enum #base_ident #generics { #(#variants,)* } }) @@ -678,7 +701,7 @@ fn generate_oneof_view_enum( fn build_decode_arms( scope: MessageScope<'_>, msg: &DescriptorProto, - mod_ident: &proc_macro2::Ident, + view_oneof_prefix: &TokenStream, oneof_idents: &std::collections::HashMap, ) -> Result<(Vec, Vec, Vec), CodeGenError> { let scalar_fields: Vec<_> = msg @@ -739,7 +762,11 @@ fn build_decode_arms( .filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32)) .collect(); oneof_arms.extend(oneof_decode_arms( - scope, base_ident, oneof_name, &fields, mod_ident, + scope, + base_ident, + oneof_name, + &fields, + view_oneof_prefix, )?); } @@ -1101,13 +1128,12 @@ fn oneof_decode_arms( base_ident: &proc_macro2::Ident, oneof_name: &str, fields: &[&FieldDescriptorProto], - mod_ident: &proc_macro2::Ident, + view_oneof_prefix: &TokenStream, ) -> Result, CodeGenError> { let MessageScope { ctx, features, .. } = scope; let preserve_unknown_fields = ctx.config.preserve_unknown_fields; let field_ident = make_field_ident(oneof_name); - let view_enum_simple = format_ident!("{}View", base_ident); - let view_enum: TokenStream = quote! { #mod_ident::#view_enum_simple }; + let view_enum: TokenStream = quote! { #view_oneof_prefix #base_ident }; fields .iter() @@ -1214,7 +1240,8 @@ fn oneof_decode_arms( fn build_to_owned_fields( scope: MessageScope<'_>, msg: &DescriptorProto, - mod_ident: &proc_macro2::Ident, + view_oneof_prefix: &TokenStream, + owned_oneof_prefix: &TokenStream, oneof_idents: &std::collections::HashMap, ) -> Result, CodeGenError> { let MessageScope { ctx, features, .. } = scope; @@ -1265,9 +1292,8 @@ fn build_to_owned_fields( continue; } let field_ident = make_field_ident(oneof_name); - let view_enum_simple = format_ident!("{}View", base_ident); - let view_enum: TokenStream = quote! { #mod_ident::#view_enum_simple }; - let owned_enum: TokenStream = quote! { #mod_ident::#base_ident }; + let view_enum: TokenStream = quote! { #view_oneof_prefix #base_ident }; + let owned_enum: TokenStream = quote! { #owned_oneof_prefix #base_ident }; let match_arms = group .iter() @@ -1450,23 +1476,61 @@ fn resolve_enum_ty( } /// Resolve the view type tokens for a message field -/// (e.g. `"Address"` → `AddressView<'a>`). +/// (e.g. `".pkg.Address"` → `super^n::buffa_::view::AddressView<'a>`). +/// +/// `scope.nesting` must be the **total** depth of the caller below the +/// package root (msg-nesting + kind-depth offset already applied by the +/// caller — `+2` for view-struct bodies, `+4` for view-oneof-enum bodies). fn resolve_view_ty_tokens( scope: MessageScope<'_>, field: &FieldDescriptorProto, ) -> Result { - let owned = resolve_owned_path(scope, field)?; - Ok(owned_to_view_ty_tokens(&owned)) + let path = resolve_view_path(scope, field)?; + Ok(quote! { #path <'a> }) } -/// Resolve the view type tokens used for `decode_view` calls -/// (e.g. `"Address"` → `AddressView`). +/// Resolve the view type tokens used for `decode_view` calls (no lifetime). fn resolve_view_decode_tokens( scope: MessageScope<'_>, field: &FieldDescriptorProto, ) -> Result { - let owned = resolve_owned_path(scope, field)?; - Ok(owned_to_view_decode_tokens(&owned)) + resolve_view_path(scope, field) +} + +/// Compute the path to a message field's **view struct** from `scope`. +/// +/// Splits the resolved owned-type path at the target-package boundary and +/// inserts `buffa_::view::` between the halves, appending `View` to the +/// final identifier. +fn resolve_view_path( + scope: MessageScope<'_>, + field: &FieldDescriptorProto, +) -> Result { + let type_name = field + .type_name + .as_deref() + .ok_or(CodeGenError::MissingField("field.type_name"))?; + let split = scope + .ctx + .rust_type_relative_split(type_name, scope.current_package, scope.nesting) + .ok_or_else(|| CodeGenError::Other(format!("message type '{type_name}' not found")))?; + + let to_pkg = if split.to_package.is_empty() { + TokenStream::new() + } else { + let p = rust_path_to_tokens(&split.to_package); + quote! { #p :: } + }; + let sentinel = make_field_ident(SENTINEL_MOD); + let (within_prefix, last) = match split.within_package.rsplit_once("::") { + Some((prefix, last)) => { + let p = rust_path_to_tokens(prefix); + (quote! { #p :: }, last.to_string()) + } + None => (TokenStream::new(), split.within_package.clone()), + }; + let view_ident = make_field_ident(&format!("{last}View")); + Ok(quote! { #to_pkg #sentinel :: view :: #within_prefix #view_ident }) } fn resolve_owned_path( @@ -1482,33 +1546,3 @@ fn resolve_owned_path( .rust_type_relative(type_name, scope.current_package, scope.nesting) .ok_or_else(|| CodeGenError::Other(format!("message type '{type_name}' not found"))) } - -/// Convert an owned type path string to view type tokens with a lifetime. -/// -/// `"Address"` → `AddressView<'a>`, `"pkg::Foo"` → `pkg::FooView<'a>`. -fn owned_to_view_ty_tokens(owned: &str) -> TokenStream { - let (prefix_tokens, last_name) = split_path_last(owned); - let view_ident = make_field_ident(&format!("{last_name}View")); - quote! { #prefix_tokens #view_ident<'a> } -} - -/// Convert an owned type path string to view decode path tokens (no lifetime). -/// -/// `"Address"` → `AddressView`, `"pkg::Foo"` → `pkg::FooView`. -fn owned_to_view_decode_tokens(owned: &str) -> TokenStream { - let (prefix_tokens, last_name) = split_path_last(owned); - let view_ident = make_field_ident(&format!("{last_name}View")); - quote! { #prefix_tokens #view_ident } -} - -/// Split `"a::b::Foo"` into (tokens for `a::b::`, `"Foo"`). -/// For `"Foo"` returns (empty tokens, `"Foo"`). -fn split_path_last(path: &str) -> (TokenStream, &str) { - match path.rsplit_once("::") { - Some((prefix, last)) => { - let prefix_tokens = rust_path_to_tokens(prefix); - (quote! { #prefix_tokens :: }, last) - } - None => (TokenStream::new(), path), - } -} diff --git a/buffa-codegen/tests/codegen_integration.rs b/buffa-codegen/tests/codegen_integration.rs index 33b173f..91be3a5 100644 --- a/buffa-codegen/tests/codegen_integration.rs +++ b/buffa-codegen/tests/codegen_integration.rs @@ -88,12 +88,12 @@ fn generate_proto(proto: &str, config: &CodeGenConfig) -> String { let files = buffa_codegen::generate(&fds.file, &["test.proto".into()], config) .unwrap_or_else(|e| panic!("codegen failed: {e}\n\nProto:\n{proto}")); - assert_eq!( - files.len(), - 1, - "generate_proto expects single-file output; use compile_protos directly for multi-file" - ); - files.into_iter().next().unwrap().content + // 5 content files + 1 stitcher per package; concat for substring asserts. + files + .into_iter() + .map(|f| f.content) + .collect::>() + .join("\n") } /// Helper: run codegen on a proto file from buffa-test/protos/. @@ -129,10 +129,11 @@ fn codegen_basic() { #[test] fn codegen_basic_views_vs_no_views() { + let total = |files: &[GeneratedFile]| files.iter().map(|f| f.content.len()).sum::(); let with_views = generate_for("basic.proto", &CodeGenConfig::default()); let without_views = generate_for("basic.proto", &no_views()); assert!( - without_views[0].content.len() < with_views[0].content.len(), + total(&without_views) < total(&with_views), "disabling views should produce shorter output" ); } @@ -363,8 +364,8 @@ fn inline_oneof() { "#, &no_views(), ); - assert!(content.contains("pub info: Option")); - assert!(content.contains("pub enum InfoOneof")); + assert!(content.contains("pub info: Option")); + assert!(content.contains("pub enum Info")); assert!(content.contains("Email(")); assert!(content.contains("Phone(")); } @@ -512,10 +513,11 @@ fn inline_oneof_duplicate_message_type_no_from_collision() { "#, &no_views(), ); - // Box on both message variants. + // Box on both message variants. Oneof body now sits at depth 3 + // (`buffa_::oneof::t::`), so 3× super. assert_eq!( content - .matches("::buffa::alloc::boxed::Box") + .matches("::buffa::alloc::boxed::Box") .count(), 2, "both Placeholder variants should be boxed: {content}" @@ -523,13 +525,15 @@ fn inline_oneof_duplicate_message_type_no_from_collision() { // Only ONE From impl (for T, which appears once), not two for Placeholder. assert_eq!( content - .matches("impl From for Kind") + .matches("impl From for Kind") .count(), 0, "duplicate-type From impls must be skipped: {content}" ); assert_eq!( - content.matches("impl From for Kind").count(), + content + .matches("impl From for Kind") + .count(), 1, "unique-type From impl must still be generated: {content}" ); @@ -704,8 +708,8 @@ fn inline_view_keyword_package_path() { .expect("codegen failed for keyword package with views"); let marker = files .iter() - .find(|f| f.name.contains("marker")) - .expect("marker.rs not generated"); + .find(|f| f.package == "google.maps") + .expect("google.maps.rs not generated"); // Must emit r#type (raw ident), not plain `type`. assert!( marker.content.contains("r#type"), diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs new file mode 100644 index 0000000..53dc95e --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs @@ -0,0 +1,15 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. + +include!("google.protobuf.compiler.plugin.rs"); +#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +pub mod buffa_ { + #[allow(unused_imports)] use super::*; + pub mod oneof { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.compiler.plugin.__oneof.rs"); + } + pub mod ext { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.compiler.plugin.__ext.rs"); + } +} diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs new file mode 100644 index 0000000..488122e --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/compiler/plugin.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs new file mode 100644 index 0000000..488122e --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/compiler/plugin.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs new file mode 100644 index 0000000..488122e --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/compiler/plugin.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs new file mode 100644 index 0000000..488122e --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/compiler/plugin.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs new file mode 100644 index 0000000..0794f60 --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/descriptor.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs new file mode 100644 index 0000000..0794f60 --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/descriptor.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs new file mode 100644 index 0000000..0794f60 --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/descriptor.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs new file mode 100644 index 0000000..0794f60 --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/descriptor.proto + diff --git a/buffa-descriptor/src/generated/google.protobuf.mod.rs b/buffa-descriptor/src/generated/google.protobuf.mod.rs new file mode 100644 index 0000000..8b68cde --- /dev/null +++ b/buffa-descriptor/src/generated/google.protobuf.mod.rs @@ -0,0 +1,15 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. + +include!("google.protobuf.descriptor.rs"); +#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +pub mod buffa_ { + #[allow(unused_imports)] use super::*; + pub mod oneof { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.descriptor.__oneof.rs"); + } + pub mod ext { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.descriptor.__ext.rs"); + } +} diff --git a/buffa-descriptor/src/generated/mod.rs b/buffa-descriptor/src/generated/mod.rs index bab2dfe..c344681 100644 --- a/buffa-descriptor/src/generated/mod.rs +++ b/buffa-descriptor/src/generated/mod.rs @@ -19,7 +19,7 @@ pub mod descriptor { // Re-export the buffa crate so `::buffa::` paths in generated code resolve. use buffa; - include!("google.protobuf.descriptor.rs"); + include!("google.protobuf.mod.rs"); } // Re-export the specific descriptor types referenced via `super::` from the @@ -42,5 +42,5 @@ pub mod compiler { pub use crate::generated::descriptor::GeneratedCodeInfo; use buffa; - include!("google.protobuf.compiler.plugin.rs"); + include!("google.protobuf.compiler.mod.rs"); } diff --git a/buffa-test/src/lib.rs b/buffa-test/src/lib.rs index aa2a4d9..a9ae647 100644 --- a/buffa-test/src/lib.rs +++ b/buffa-test/src/lib.rs @@ -6,7 +6,7 @@ // - match_single_binding: empty messages generate a single-arm wildcard merge match #[allow(clippy::derivable_impls, clippy::match_single_binding)] pub mod basic { - include!(concat!(env!("OUT_DIR"), "/basic.rs")); + buffa::include_proto!("basic"); } #[allow( @@ -15,7 +15,7 @@ pub mod basic { non_camel_case_types )] pub mod proto3sem { - include!(concat!(env!("OUT_DIR"), "/proto3_semantics.rs")); + buffa::include_proto!("test.proto3sem"); } #[allow( @@ -25,37 +25,37 @@ pub mod proto3sem { dead_code )] pub mod keywords { - include!(concat!(env!("OUT_DIR"), "/keywords.rs")); + buffa::include_proto!("test.keywords"); } #[allow(clippy::derivable_impls, clippy::match_single_binding)] pub mod nested { - include!(concat!(env!("OUT_DIR"), "/nested_deep.rs")); + buffa::include_proto!("test.nested"); } #[allow(clippy::derivable_impls, clippy::match_single_binding)] pub mod wkt { - include!(concat!(env!("OUT_DIR"), "/wkt_usage.rs")); + buffa::include_proto!("test.wkt"); } #[allow(clippy::derivable_impls, clippy::match_single_binding)] pub mod cross { - include!(concat!(env!("OUT_DIR"), "/cross_package.rs")); + buffa::include_proto!("test.cross"); } #[allow(clippy::derivable_impls, clippy::match_single_binding)] pub mod cross_syntax { - include!(concat!(env!("OUT_DIR"), "/cross_syntax.rs")); + buffa::include_proto!("test.cross_syntax"); } #[allow(clippy::derivable_impls, clippy::match_single_binding)] pub mod collisions { - include!(concat!(env!("OUT_DIR"), "/name_collisions.rs")); + buffa::include_proto!("test.collisions"); } #[allow(clippy::derivable_impls, clippy::match_single_binding, dead_code)] pub mod prelude_shadow { - include!(concat!(env!("OUT_DIR"), "/prelude_shadow.rs")); + buffa::include_proto!("test.prelude_shadow"); } #[allow( @@ -64,7 +64,7 @@ pub mod prelude_shadow { non_camel_case_types )] pub mod proto2 { - include!(concat!(env!("OUT_DIR"), "/proto2_defaults.rs")); + buffa::include_proto!("test.proto2"); } #[allow( @@ -74,7 +74,7 @@ pub mod proto2 { dead_code )] pub mod json_types { - include!(concat!(env!("OUT_DIR"), "/json_types.rs")); + buffa::include_proto!("test.json"); } #[allow( @@ -83,7 +83,7 @@ pub mod json_types { non_camel_case_types )] pub mod p2json { - include!(concat!(env!("OUT_DIR"), "/proto2_json.rs")); + buffa::include_proto!("test.p2json"); } #[allow( @@ -92,7 +92,7 @@ pub mod p2json { non_camel_case_types )] pub mod utf8test { - include!(concat!(env!("OUT_DIR"), "/utf8_validation.rs")); + buffa::include_proto!("utf8test"); } #[allow( @@ -103,7 +103,7 @@ pub mod utf8test { dead_code )] pub mod edenumjson { - include!(concat!(env!("OUT_DIR"), "/editions_enum_json.rs")); + buffa::include_proto!("test.edenumjson"); } #[allow( @@ -113,7 +113,7 @@ pub mod edenumjson { dead_code )] pub mod edge { - include!(concat!(env!("OUT_DIR"), "/edge_cases.rs")); + buffa::include_proto!("test.edge"); } #[allow( @@ -123,7 +123,7 @@ pub mod edge { dead_code )] pub mod custopts { - include!(concat!(env!("OUT_DIR"), "/custom_options.rs")); + buffa::include_proto!("buffa.test.options"); } #[allow( @@ -133,7 +133,7 @@ pub mod custopts { dead_code )] pub mod extjson { - include!(concat!(env!("OUT_DIR"), "/ext_json.rs")); + buffa::include_proto!("buffa.test.extjson"); } #[allow( @@ -143,7 +143,7 @@ pub mod extjson { dead_code )] pub mod groupext { - include!(concat!(env!("OUT_DIR"), "/group_ext.rs")); + buffa::include_proto!("buffa.test.groupext"); } #[allow( @@ -153,7 +153,7 @@ pub mod groupext { dead_code )] pub mod msgset { - include!(concat!(env!("OUT_DIR"), "/messageset.rs")); + buffa::include_proto!("buffa.test.messageset"); } #[cfg(has_edition_2024)] @@ -164,7 +164,7 @@ pub mod msgset { dead_code )] pub mod ed2024 { - include!(concat!(env!("OUT_DIR"), "/editions_2024.rs")); + buffa::include_proto!("test.ed2024"); } // Regression: use_bytes_type() previously produced uncompilable decode code. @@ -177,7 +177,7 @@ pub mod ed2024 { dead_code )] pub mod basic_bytes { - include!(concat!(env!("OUT_DIR"), "/bytes_variant/basic.rs")); + include!(concat!(env!("OUT_DIR"), "/bytes_variant/basic.mod.rs")); } // Views + preserve_unknown_fields=false: covers the else-branches in view @@ -189,7 +189,7 @@ pub mod basic_bytes { dead_code )] pub mod basic_no_uf { - include!(concat!(env!("OUT_DIR"), "/no_unknown_views/basic.rs")); + include!(concat!(env!("OUT_DIR"), "/no_unknown_views/basic.mod.rs")); } // These tests intentionally use the field-assignment style diff --git a/buffa-test/src/tests/basic.rs b/buffa-test/src/tests/basic.rs index 35b155d..851ceef 100644 --- a/buffa-test/src/tests/basic.rs +++ b/buffa-test/src/tests/basic.rs @@ -1,6 +1,7 @@ //! Basic round-trips: Empty, Person, Address, unknown-field preservation. use super::round_trip; +use crate::basic::buffa_::oneof; use crate::basic::*; use buffa::Message; @@ -191,19 +192,19 @@ fn test_map_empty_round_trip() { fn test_oneof_round_trip() { // Set the email variant. let mut msg = Person::default(); - msg.contact = Some(person::ContactOneof::Email("alice@example.com".into())); + msg.contact = Some(oneof::person::Contact::Email("alice@example.com".into())); let decoded = round_trip(&msg); assert_eq!( decoded.contact, - Some(person::ContactOneof::Email("alice@example.com".into())) + Some(oneof::person::Contact::Email("alice@example.com".into())) ); // Overwrite with phone variant — last write wins. - msg.contact = Some(person::ContactOneof::Phone("+1-555-1234".into())); + msg.contact = Some(oneof::person::Contact::Phone("+1-555-1234".into())); let decoded = round_trip(&msg); assert_eq!( decoded.contact, - Some(person::ContactOneof::Phone("+1-555-1234".into())) + Some(oneof::person::Contact::Phone("+1-555-1234".into())) ); // Unset. diff --git a/buffa-test/src/tests/bytes_type.rs b/buffa-test/src/tests/bytes_type.rs index 44cddd4..443cfc6 100644 --- a/buffa-test/src/tests/bytes_type.rs +++ b/buffa-test/src/tests/bytes_type.rs @@ -49,7 +49,7 @@ fn test_bytes_type_view_to_owned() { // Views borrow &[u8]; to_owned_message must produce Bytes (not Vec) // when use_bytes_type() is active. Previously this emitted .to_vec() // unconditionally, failing to compile. - use crate::basic_bytes::PersonView; + use crate::basic_bytes::buffa_::view::PersonView; use buffa::MessageView; let msg = Person { id: 7, @@ -82,8 +82,9 @@ fn test_bytes_type_view_to_owned() { // The bytes_variant build block compiles BytesContexts with use_bytes_type() // + generate_views=true; compilation alone is the primary assertion. -use crate::basic_bytes::bytes_contexts::ChoiceOneof; -use crate::basic_bytes::{BytesContexts, BytesContextsView}; +use crate::basic_bytes::buffa_::oneof::bytes_contexts::Choice as ChoiceOneof; +use crate::basic_bytes::buffa_::view::BytesContextsView; +use crate::basic_bytes::BytesContexts; #[test] fn test_bytes_type_repeated_view_to_owned() { diff --git a/buffa-test/src/tests/closed_enum.rs b/buffa-test/src/tests/closed_enum.rs index 1e00287..4005aba 100644 --- a/buffa-test/src/tests/closed_enum.rs +++ b/buffa-test/src/tests/closed_enum.rs @@ -182,7 +182,7 @@ fn test_closed_enum_negative_unknown_value_sign_extension() { #[test] fn test_view_closed_enum_optional_unknown_to_unknown_fields() { - use crate::proto2::ClosedEnumContextsView; + use crate::proto2::buffa_::view::ClosedEnumContextsView; use buffa::MessageView; let wire = varint_field(1, 99); let view = ClosedEnumContextsView::decode_view(&wire).unwrap(); @@ -195,7 +195,8 @@ fn test_view_closed_enum_optional_unknown_to_unknown_fields() { #[test] fn test_view_closed_enum_repeated_unpacked_unknown_preserved() { - use crate::proto2::{ClosedEnumContextsView, Priority}; + use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::Priority; use buffa::MessageView; // Field 2 (unpacked): [LOW=0, 99, HIGH=2] let mut wire = Vec::new(); @@ -219,7 +220,7 @@ fn test_view_closed_enum_repeated_unpacked_unknown_preserved() { #[test] fn test_view_closed_enum_oneof_unknown_to_unknown_fields() { - use crate::proto2::ClosedEnumContextsView; + use crate::proto2::buffa_::view::ClosedEnumContextsView; use buffa::MessageView; let wire = varint_field(4, 99); let view = ClosedEnumContextsView::decode_view(&wire).unwrap(); @@ -231,7 +232,8 @@ fn test_view_closed_enum_oneof_unknown_to_unknown_fields() { #[test] fn test_view_closed_enum_known_not_routed() { - use crate::proto2::{ClosedEnumContextsView, Priority}; + use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::Priority; use buffa::MessageView; let wire = varint_field(1, 2); // HIGH = 2 let view = ClosedEnumContextsView::decode_view(&wire).unwrap(); @@ -243,7 +245,8 @@ fn test_view_closed_enum_known_not_routed() { fn test_view_owned_parity_for_closed_enum_unknowns() { // Whatever the owned decoder produces, the view path must produce // byte-identical output after to_owned_message().encode_to_vec(). - use crate::proto2::{ClosedEnumContexts, ClosedEnumContextsView}; + use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::ClosedEnumContexts; use buffa::{Message, MessageView}; let mut wire = Vec::new(); wire.extend(varint_field(1, 99)); // optional unknown diff --git a/buffa-test/src/tests/collision.rs b/buffa-test/src/tests/collision.rs index c757fca..8abcc1b 100644 --- a/buffa-test/src/tests/collision.rs +++ b/buffa-test/src/tests/collision.rs @@ -81,23 +81,27 @@ fn test_oneof_name_matching_parent_message() { use crate::collisions; let msg = collisions::Status { - status: Some(collisions::status::StatusOneof::Code(42)), + status: Some(collisions::buffa_::oneof::status::Status::Code(42)), ..core::default::Default::default() }; let decoded = round_trip(&msg); assert_eq!( decoded.status, - Some(collisions::status::StatusOneof::Code(42)) + Some(collisions::buffa_::oneof::status::Status::Code(42)) ); let msg2 = collisions::Status { - status: Some(collisions::status::StatusOneof::Message("error".into())), + status: Some(collisions::buffa_::oneof::status::Status::Message( + "error".into(), + )), ..core::default::Default::default() }; let decoded = round_trip(&msg2); assert_eq!( decoded.status, - Some(collisions::status::StatusOneof::Message("error".into())) + Some(collisions::buffa_::oneof::status::Status::Message( + "error".into() + )) ); } @@ -115,7 +119,7 @@ fn test_container_references_collision_types() { ..core::default::Default::default() }), status: buffa::MessageField::some(collisions::Status { - status: Some(collisions::status::StatusOneof::Code(1)), + status: Some(collisions::buffa_::oneof::status::Status::Code(1)), ..core::default::Default::default() }), ..core::default::Default::default() @@ -135,7 +139,7 @@ fn test_nested_option_message_round_trip() { let msg = prelude_shadow::Picker { options: vec![picker::Option { title: Some("a".into()), - value: Some(picker::option::ValueOneof::IntValue(7)), + value: Some(prelude_shadow::buffa_::oneof::picker::option::Value::IntValue(7)), ..core::default::Default::default() }], label: Some("L".into()), diff --git a/buffa-test/src/tests/extensions.rs b/buffa-test/src/tests/extensions.rs index 6525389..dbb0d34 100644 --- a/buffa-test/src/tests/extensions.rs +++ b/buffa-test/src/tests/extensions.rs @@ -1,9 +1,10 @@ //! Integration tests for `extend` codegen and the `ExtensionSet` runtime API. -use crate::custopts::{ - carrier, Annotation, Carrier, ACTIVE, ANN, C_ACTIVE, C_ANN, C_FLAG, C_LABEL, C_MARKER, - C_PRIORITY, C_TAGS, C_WEIGHT, IS_INTERNAL, LABEL, PRIORITY, TAGS, WEIGHT, +use crate::custopts::buffa_::ext::{ + ACTIVE, ANN, C_ACTIVE, C_ANN, C_FLAG, C_LABEL, C_MARKER, C_PRIORITY, C_TAGS, C_WEIGHT, + IS_INTERNAL, LABEL, PRIORITY, TAGS, WEIGHT, }; +use crate::custopts::{carrier, Annotation, Carrier}; use buffa::{Extension, ExtensionSet, Message}; /// Sanity: field numbers, extendees, and codec types match the proto source. @@ -272,7 +273,8 @@ fn proto2_default_after_roundtrip() { // Group-encoded extensions (editions DELIMITED) // ──────────────────────────────────────────────────────────────────────────── -use crate::groupext::{Carrier as GroupCarrier, Inner, DELIM_INNER, DELIM_REPEATED}; +use crate::groupext::buffa_::ext::{DELIM_INNER, DELIM_REPEATED}; +use crate::groupext::{Carrier as GroupCarrier, Inner}; use buffa::extension::codecs::{GroupCodec, Repeated}; /// Codec type check: DELIMITED extension gets `GroupCodec`, not `MessageCodec`. diff --git a/buffa-test/src/tests/extensions_json.rs b/buffa-test/src/tests/extensions_json.rs index 542d8fc..ba715cd 100644 --- a/buffa-test/src/tests/extensions_json.rs +++ b/buffa-test/src/tests/extensions_json.rs @@ -2,9 +2,9 @@ //! round-trip through `serde_json` via the generated `register_types` + //! the runtime's `#[serde(flatten)]` wrapper. -use crate::extjson::{ - register_types, Ann, Carrier, Color, ANN, ANNS, BIGS, COLOR, COLORS, NUMS, WEIGHT, -}; +use crate::extjson::buffa_::ext::{ANN, ANNS, BIGS, COLOR, COLORS, NUMS, WEIGHT}; +use crate::extjson::buffa_::register_types; +use crate::extjson::{Ann, Carrier, Color}; use buffa::type_registry::{set_type_registry, TypeRegistry}; use buffa::{Enumeration, ExtensionSet}; diff --git a/buffa-test/src/tests/json.rs b/buffa-test/src/tests/json.rs index b842d6a..a09e93f 100644 --- a/buffa-test/src/tests/json.rs +++ b/buffa-test/src/tests/json.rs @@ -51,7 +51,7 @@ fn test_json_oneof_round_trip() { use crate::json_types::WithOneof; let msg = WithOneof { - value: Some(crate::json_types::with_oneof::ValueOneof::Text( + value: Some(crate::json_types::buffa_::oneof::with_oneof::Value::Text( "hello".into(), )), ..Default::default() @@ -66,7 +66,7 @@ fn test_json_oneof_all_scalar_types_round_trip() { // Exercises serde_helper_path dispatch for all proto3-JSON-special // scalar types in oneof position, and the corresponding runtime // json_helpers::{int64, uint32, uint64, float, double, bytes} paths. - use crate::json_types::with_oneof_types::KindOneof; + use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; #[rustfmt::skip] @@ -106,7 +106,7 @@ fn test_json_oneof_all_scalar_types_round_trip() { #[test] fn test_json_oneof_float_special_values() { // NaN/Infinity/-Infinity serialize as string tokens per proto3-JSON spec. - use crate::json_types::with_oneof_types::KindOneof; + use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; #[rustfmt::skip] @@ -151,7 +151,7 @@ fn test_json_oneof_float_special_values() { fn test_json_oneof_null_value() { // google.protobuf.NullValue in a oneof serializes as JSON null. // On deserialize, JSON null populates the NullValue variant (not unset). - use crate::json_types::with_oneof_types::KindOneof; + use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; use buffa_types::google::protobuf::NullValue; @@ -174,7 +174,7 @@ fn test_json_oneof_null_value() { fn test_json_oneof_float_deserialize_from_integer() { // proto3-JSON: float/double fields accept integer JSON values. // Exercises json_helpers::float::visit_i64/visit_u64. - use crate::json_types::with_oneof_types::KindOneof; + use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; let decoded: WithOneofTypes = serde_json::from_str(r#"{"f32": 42}"#).unwrap(); @@ -437,7 +437,7 @@ fn test_json_optional_open_enum_integer_deserialize() { #[test] fn test_json_mixed_oneof_and_fields_round_trip() { - use crate::json_types::mixed_oneof_and_fields::ChoiceOneof; + use crate::json_types::buffa_::oneof::mixed_oneof_and_fields::Choice as ChoiceOneof; use crate::json_types::{MixedOneofAndFields, Scalar}; let msg = MixedOneofAndFields { @@ -490,7 +490,8 @@ fn test_json_mixed_value_field_null_forwarding() { // not "field absent". The custom Deserialize must forward null to // Value's own Deserialize rather than skipping the field. use crate::json_types::MixedOneofAndFields; - use buffa_types::google::protobuf::{value::KindOneof, NullValue}; + use buffa_types::google::protobuf::buffa_::oneof::value::Kind as KindOneof; + use buffa_types::google::protobuf::NullValue; let decoded: MixedOneofAndFields = serde_json::from_str(r#"{"dynamic": null}"#).unwrap(); assert!(decoded.dynamic.is_set(), "null should set the Value field"); diff --git a/buffa-test/src/tests/keyword.rs b/buffa-test/src/tests/keyword.rs index 2e6440a..1e8f4bf 100644 --- a/buffa-test/src/tests/keyword.rs +++ b/buffa-test/src/tests/keyword.rs @@ -46,13 +46,17 @@ fn test_keyword_expression_with_oneof() { ..Default::default() }), match_mode: buffa::EnumValue::Known(keywords::Match::MATCH_EXACT), - value: Some(keywords::expression::ValueOneof::Literal("42".into())), + value: Some(keywords::buffa_::oneof::expression::Value::Literal( + "42".into(), + )), ..Default::default() }; let decoded = round_trip(&msg); assert_eq!(decoded.result_type.name, "bool"); assert_eq!( decoded.value, - Some(keywords::expression::ValueOneof::Literal("42".into())) + Some(keywords::buffa_::oneof::expression::Value::Literal( + "42".into() + )) ); } diff --git a/buffa-test/src/tests/message_set.rs b/buffa-test/src/tests/message_set.rs index 495181a..29762d5 100644 --- a/buffa-test/src/tests/message_set.rs +++ b/buffa-test/src/tests/message_set.rs @@ -8,7 +8,8 @@ //! `{number: type_id, data: LengthDelimited(payload)}`. Decode unwraps the //! group; encode rewraps it. -use crate::msgset::{Container, Marker, Payload, MARKER_EXT, PAYLOAD_EXT}; +use crate::msgset::buffa_::ext::{MARKER_EXT, PAYLOAD_EXT}; +use crate::msgset::{Container, Marker, Payload}; use buffa::{ExtensionSet, Message}; #[test] diff --git a/buffa-test/src/tests/nesting.rs b/buffa-test/src/tests/nesting.rs index b8efe57..8cbc7bd 100644 --- a/buffa-test/src/tests/nesting.rs +++ b/buffa-test/src/tests/nesting.rs @@ -19,7 +19,7 @@ fn test_deep_nesting_round_trip() { }), ..Default::default() }), - content: Some(nested::outer::ContentOneof::Text("hello".into())), + content: Some(nested::buffa_::oneof::outer::Content::Text("hello".into())), ..Default::default() }; let decoded = round_trip(&msg); @@ -64,43 +64,47 @@ fn test_multi_oneof_variants() { // Test each variant type round-trips correctly. let cases: Vec = vec![ MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::IntVal(42)), + value: Some(nested::buffa_::oneof::multi_oneof::Value::IntVal(42)), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::LongVal(i64::MAX)), + value: Some(nested::buffa_::oneof::multi_oneof::Value::LongVal(i64::MAX)), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::FloatVal(1.5)), + value: Some(nested::buffa_::oneof::multi_oneof::Value::FloatVal(1.5)), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::DoubleVal( + value: Some(nested::buffa_::oneof::multi_oneof::Value::DoubleVal( std::f64::consts::PI, )), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::BoolVal(true)), + value: Some(nested::buffa_::oneof::multi_oneof::Value::BoolVal(true)), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::StringVal("hello".into())), + value: Some(nested::buffa_::oneof::multi_oneof::Value::StringVal( + "hello".into(), + )), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::BytesVal(vec![0xFF, 0x00])), + value: Some(nested::buffa_::oneof::multi_oneof::Value::BytesVal(vec![ + 0xFF, 0x00, + ])), ..Default::default() }, MultiOneof { - value: Some(nested::multi_oneof::ValueOneof::MessageVal(Box::new( - nested::outer::middle::Inner { + value: Some(nested::buffa_::oneof::multi_oneof::Value::MessageVal( + Box::new(nested::outer::middle::Inner { data: vec![1, 2, 3], active: true, ..Default::default() - }, - ))), + }), + )), ..Default::default() }, ]; @@ -116,21 +120,22 @@ fn test_recursive_oneof_direct() { // Expr { kind { Expr negated = 3; } } is directly self-recursive // through the oneof. Message/group variants are always boxed to // break the infinite-size cycle. - use crate::nested::{expr, Expr}; + use crate::nested::buffa_::oneof::expr; + use crate::nested::Expr; let inner = Expr { - kind: Some(expr::KindOneof::IntLiteral(42)), + kind: Some(expr::Kind::IntLiteral(42)), ..Default::default() }; let outer = Expr { - kind: Some(expr::KindOneof::Negated(Box::new(inner))), + kind: Some(expr::Kind::Negated(Box::new(inner))), ..Default::default() }; let decoded = round_trip(&outer); assert_eq!(decoded, outer); // Verify deref through Box works transparently in pattern matching. match &decoded.kind { - Some(expr::KindOneof::Negated(e)) => match &e.kind { - Some(expr::KindOneof::IntLiteral(n)) => assert_eq!(*n, 42), + Some(expr::Kind::Negated(e)) => match &e.kind { + Some(expr::Kind::IntLiteral(n)) => assert_eq!(*n, 42), other => panic!("expected IntLiteral, got {other:?}"), }, other => panic!("expected Negated, got {other:?}"), @@ -142,13 +147,14 @@ fn test_recursive_oneof_mutual() { // Expr -> BinaryOp -> Expr mutual recursion. BinaryOp fields use // MessageField (already boxed); the Expr.kind.binary variant is // the boxed side of the cycle. - use crate::nested::{expr, BinaryOp, Expr}; + use crate::nested::buffa_::oneof::expr; + use crate::nested::{BinaryOp, Expr}; let lhs = Expr { - kind: Some(expr::KindOneof::IntLiteral(1)), + kind: Some(expr::Kind::IntLiteral(1)), ..Default::default() }; let rhs = Expr { - kind: Some(expr::KindOneof::IntLiteral(2)), + kind: Some(expr::Kind::IntLiteral(2)), ..Default::default() }; let op = BinaryOp { @@ -159,7 +165,7 @@ fn test_recursive_oneof_mutual() { }; // Use the generated From impl instead of manual Box::new. let expr = Expr { - kind: Some(expr::KindOneof::from(op)), + kind: Some(expr::Kind::from(op)), ..Default::default() }; let decoded = round_trip(&expr); @@ -170,7 +176,8 @@ fn test_recursive_oneof_mutual() { fn test_from_msg_for_option_oneof() { // `From for Option` lets struct-literal construction skip both // the explicit `Some(...)` and `Box::new(...)` for message-typed variants. - use crate::nested::{expr, BinaryOp, Expr}; + use crate::nested::buffa_::oneof::expr; + use crate::nested::{BinaryOp, Expr}; let op = BinaryOp { op: "*".into(), ..Default::default() @@ -182,7 +189,7 @@ fn test_from_msg_for_option_oneof() { ..Default::default() }; let explicit = Expr { - kind: Some(expr::KindOneof::Binary(Box::new(op))), + kind: Some(expr::Kind::Binary(Box::new(op))), ..Default::default() }; assert_eq!(terse, explicit); @@ -190,7 +197,7 @@ fn test_from_msg_for_option_oneof() { // Round-trip sanity. let decoded = round_trip(&terse); match decoded.kind { - Some(expr::KindOneof::Binary(b)) => assert_eq!(b.op, "*"), + Some(expr::Kind::Binary(b)) => assert_eq!(b.op, "*"), other => panic!("expected Binary, got {other:?}"), } @@ -206,12 +213,13 @@ fn test_from_msg_for_option_oneof() { fn test_recursive_oneof_merge_semantics() { // When the same message-typed oneof variant appears twice on the // wire, the second occurrence merges into the first (proto3 spec). - use crate::nested::{expr, BinaryOp, Expr}; + use crate::nested::buffa_::oneof::expr; + use crate::nested::{BinaryOp, Expr}; let first = Expr { - kind: Some(expr::KindOneof::from(BinaryOp { + kind: Some(expr::Kind::from(BinaryOp { op: "+".into(), lhs: buffa::MessageField::some(Expr { - kind: Some(expr::KindOneof::IntLiteral(1)), + kind: Some(expr::Kind::IntLiteral(1)), ..Default::default() }), ..Default::default() @@ -219,9 +227,9 @@ fn test_recursive_oneof_merge_semantics() { ..Default::default() }; let second = Expr { - kind: Some(expr::KindOneof::from(BinaryOp { + kind: Some(expr::Kind::from(BinaryOp { rhs: buffa::MessageField::some(Expr { - kind: Some(expr::KindOneof::IntLiteral(2)), + kind: Some(expr::Kind::IntLiteral(2)), ..Default::default() }), ..Default::default() @@ -233,7 +241,7 @@ fn test_recursive_oneof_merge_semantics() { let merged = Expr::decode(&mut bytes.as_slice()).expect("decode"); // Both lhs (from first) and rhs (from second) should be present. match &merged.kind { - Some(expr::KindOneof::Binary(b)) => { + Some(expr::Kind::Binary(b)) => { assert_eq!(b.op, "+"); assert!(b.lhs.is_set(), "lhs from first merge lost"); assert!(b.rhs.is_set(), "rhs from second merge lost"); @@ -246,22 +254,26 @@ fn test_recursive_oneof_merge_semantics() { fn test_view_oneof_boxed_message_variant() { // View oneof enums box message/group variants for the same reason // as owned enums. The Box holds a lifetime-bound view struct. - use crate::nested::{expr, Expr, ExprView}; + use crate::nested::buffa_::oneof::expr; + use crate::nested::buffa_::view::ExprView; + use crate::nested::Expr; use buffa::MessageView; let inner = Expr { - kind: Some(expr::KindOneof::IntLiteral(42)), + kind: Some(expr::Kind::IntLiteral(42)), ..Default::default() }; let outer = Expr { - kind: Some(expr::KindOneof::Negated(Box::new(inner))), + kind: Some(expr::Kind::Negated(Box::new(inner))), ..Default::default() }; let bytes = outer.encode_to_vec(); let view = ExprView::decode_view(&bytes).expect("decode_view"); // Pattern-matched binding auto-derefs through Box>. match &view.kind { - Some(expr::KindOneofView::Negated(v)) => match &v.kind { - Some(expr::KindOneofView::IntLiteral(n)) => assert_eq!(*n, 42), + Some(crate::nested::buffa_::view::oneof::expr::Kind::Negated(v)) => match &v.kind { + Some(crate::nested::buffa_::view::oneof::expr::Kind::IntLiteral(n)) => { + assert_eq!(*n, 42) + } other => panic!("expected IntLiteral, got {other:?}"), }, other => panic!("expected Negated, got {other:?}"), @@ -274,10 +286,11 @@ fn test_view_oneof_boxed_message_variant() { #[test] fn test_view_oneof_message_variant_to_owned() { // Non-recursive message variant: Middle in Outer.content.structured. - use crate::nested::{self, Outer, OuterView}; + use crate::nested::buffa_::view::OuterView; + use crate::nested::{self, Outer}; use buffa::MessageView; let msg = Outer { - content: Some(nested::outer::ContentOneof::Structured(Box::new( + content: Some(nested::buffa_::oneof::outer::Content::Structured(Box::new( nested::outer::Middle { value: 7, ..Default::default() @@ -288,7 +301,7 @@ fn test_view_oneof_message_variant_to_owned() { let bytes = msg.encode_to_vec(); let view = OuterView::decode_view(&bytes).expect("decode_view"); match &view.content { - Some(nested::outer::ContentOneofView::Structured(m)) => assert_eq!(m.value, 7), + Some(nested::buffa_::view::oneof::outer::Content::Structured(m)) => assert_eq!(m.value, 7), other => panic!("expected Structured, got {other:?}"), } assert_eq!(view.to_owned_message(), msg); @@ -323,7 +336,8 @@ fn test_recursive_singular_message_field() { fn test_view_recursive_singular_message_field() { // View path through the same cycle. MessageFieldView boxes internally, // Deref returns &V transparently. - use crate::nested::{corecursive, Corecursive, CorecursiveView}; + use crate::nested::buffa_::view::CorecursiveView; + use crate::nested::{corecursive, Corecursive}; use buffa::MessageView; let msg = Corecursive { name: "root".into(), @@ -352,7 +366,8 @@ fn test_view_message_field_merge_semantics() { // When a singular message field appears twice on the wire, the // second occurrence merges into the first field-by-field (proto // spec). The view decoder must do this, not replace. - use crate::nested::{corecursive, Corecursive, CorecursiveView}; + use crate::nested::buffa_::view::CorecursiveView; + use crate::nested::{corecursive, Corecursive}; use buffa::MessageView; // First: nested.value = 1, nested.back.name = "from_first" let first = Corecursive { @@ -394,14 +409,16 @@ fn test_view_message_field_merge_semantics() { #[test] fn test_view_oneof_message_variant_merge_semantics() { // Same merge semantics for message-typed oneof variants. - use crate::nested::{expr, BinaryOp, Expr, ExprView}; + use crate::nested::buffa_::oneof::expr; + use crate::nested::buffa_::view::ExprView; + use crate::nested::{BinaryOp, Expr}; use buffa::MessageView; // First: binary with lhs set let first = Expr { - kind: Some(expr::KindOneof::from(BinaryOp { + kind: Some(expr::Kind::from(BinaryOp { op: "+".into(), lhs: buffa::MessageField::some(Expr { - kind: Some(expr::KindOneof::IntLiteral(1)), + kind: Some(expr::Kind::IntLiteral(1)), ..Default::default() }), ..Default::default() @@ -410,9 +427,9 @@ fn test_view_oneof_message_variant_merge_semantics() { }; // Second: binary with rhs set (no op, no lhs) let second = Expr { - kind: Some(expr::KindOneof::from(BinaryOp { + kind: Some(expr::Kind::from(BinaryOp { rhs: buffa::MessageField::some(Expr { - kind: Some(expr::KindOneof::IntLiteral(2)), + kind: Some(expr::Kind::IntLiteral(2)), ..Default::default() }), ..Default::default() @@ -424,7 +441,7 @@ fn test_view_oneof_message_variant_merge_semantics() { let view = ExprView::decode_view(&wire).unwrap(); match &view.kind { - Some(expr::KindOneofView::Binary(b)) => { + Some(crate::nested::buffa_::view::oneof::expr::Kind::Binary(b)) => { assert_eq!(b.op, "+", "op from first (second didn't set it)"); assert!(b.lhs.is_set(), "lhs from first must survive merge"); assert!(b.rhs.is_set(), "rhs from second"); diff --git a/buffa-test/src/tests/proto2.rs b/buffa-test/src/tests/proto2.rs index c5dc937..2196b54 100644 --- a/buffa-test/src/tests/proto2.rs +++ b/buffa-test/src/tests/proto2.rs @@ -261,7 +261,8 @@ fn test_proto2_group_wire_format() { #[test] fn test_view_coverage_owned_round_trip() { - use crate::proto2::view_coverage::{ChoiceOneof, Payload}; + use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::view_coverage::Payload; use crate::proto2::{Priority, ViewCoverage}; let mut by_id = std::collections::HashMap::new(); @@ -304,8 +305,10 @@ fn test_view_coverage_via_view() { // View-decode → to_owned_message → encode round-trip. // Exercises: singular closed-enum view type, MapView, // MapView<&str, ClosedEnum>, group-in-oneof view decode + merge. - use crate::proto2::view_coverage::{ChoiceOneof, Payload}; - use crate::proto2::{Priority, ViewCoverage, ViewCoverageView}; + use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::buffa_::view::ViewCoverageView; + use crate::proto2::view_coverage::Payload; + use crate::proto2::{Priority, ViewCoverage}; use buffa::MessageView; let mut by_id = std::collections::HashMap::new(); @@ -359,7 +362,8 @@ fn test_view_coverage_via_view() { fn test_view_coverage_required_enum_default() { // Required closed-enum field defaults to the first enum value (LOW=0). // View decode of empty buffer should also produce the default. - use crate::proto2::{Priority, ViewCoverage, ViewCoverageView}; + use crate::proto2::buffa_::view::ViewCoverageView; + use crate::proto2::{Priority, ViewCoverage}; use buffa::MessageView; let d = ViewCoverage::default(); @@ -373,8 +377,10 @@ fn test_view_coverage_required_enum_default() { fn test_view_coverage_group_in_oneof_merge() { // Proto spec: same oneof field on the wire twice → merge (for messages/ // groups). Exercises the `_merge_into_view` branch for group-in-oneof. - use crate::proto2::view_coverage::{ChoiceOneof, Payload}; - use crate::proto2::{Priority, ViewCoverage, ViewCoverageView}; + use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::buffa_::view::ViewCoverageView; + use crate::proto2::view_coverage::Payload; + use crate::proto2::{Priority, ViewCoverage}; use buffa::MessageView; // First occurrence: only x set. diff --git a/buffa-test/src/tests/proto3_semantics.rs b/buffa-test/src/tests/proto3_semantics.rs index 13d5b0b..9dba2f5 100644 --- a/buffa-test/src/tests/proto3_semantics.rs +++ b/buffa-test/src/tests/proto3_semantics.rs @@ -365,13 +365,17 @@ fn enum_unknown_value_preserved_map() { #[test] fn enum_unknown_value_preserved_oneof() { let msg = EnumContexts { - choice: Some(enum_contexts::ChoiceOneof::Picked(EnumValue::Unknown(77))), + choice: Some( + crate::proto3sem::buffa_::oneof::enum_contexts::Choice::Picked(EnumValue::Unknown(77)), + ), ..Default::default() }; let decoded = round_trip(&msg); assert_eq!( decoded.choice, - Some(enum_contexts::ChoiceOneof::Picked(EnumValue::Unknown(77))) + Some( + crate::proto3sem::buffa_::oneof::enum_contexts::Choice::Picked(EnumValue::Unknown(77)) + ) ); } @@ -566,7 +570,7 @@ fn view_implicit_presence_matches_owned() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = ImplicitScalarsView::decode_view(&bytes).unwrap(); + let view = buffa_::view::ImplicitScalarsView::decode_view(&bytes).unwrap(); assert_eq!(view.i32, 42); assert_eq!(view.s, "view"); assert_eq!(view.by, &[0xAA, 0xBB]); @@ -587,7 +591,7 @@ fn view_optional_some_zero_matches_owned() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = OptionalAllTypesView::decode_view(&bytes).unwrap(); + let view = buffa_::view::OptionalAllTypesView::decode_view(&bytes).unwrap(); assert_eq!(view.i32, Some(0)); assert_eq!(view.s, Some("")); assert_eq!(view.b, Some(false)); @@ -604,7 +608,7 @@ fn view_open_enum_unknown_preserved() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = EnumContextsView::decode_view(&bytes).unwrap(); + let view = buffa_::view::EnumContextsView::decode_view(&bytes).unwrap(); assert_eq!(view.singular, EnumValue::Unknown(55)); let rep_collected: Vec<_> = view.rep.iter().copied().collect(); assert_eq!( diff --git a/buffa-test/src/tests/textproto.rs b/buffa-test/src/tests/textproto.rs index 9970528..d43fb93 100644 --- a/buffa-test/src/tests/textproto.rs +++ b/buffa-test/src/tests/textproto.rs @@ -96,7 +96,9 @@ fn person_roundtrip() { ..Default::default() }]; p.maybe_age = Some(30); - p.contact = Some(person::ContactOneof::Email("alice@example.com".into())); + p.contact = Some(crate::basic::buffa_::oneof::person::Contact::Email( + "alice@example.com".into(), + )); let text = encode_to_string(&p); let back: Person = decode_from_str(&text).unwrap(); @@ -155,18 +157,27 @@ fn closed_enum_encode_decode() { #[test] fn oneof_variants() { let mut p = Person::default(); - p.contact = Some(person::ContactOneof::Phone("555-1234".into())); + p.contact = Some(crate::basic::buffa_::oneof::person::Contact::Phone( + "555-1234".into(), + )); assert_eq!(encode_to_string(&p), r#"phone: "555-1234""#); let p: Person = decode_from_str(r#"email: "x@y.com""#).unwrap(); assert_eq!( p.contact, - Some(person::ContactOneof::Email("x@y.com".into())) + Some(crate::basic::buffa_::oneof::person::Contact::Email( + "x@y.com".into() + )) ); // Last-wins when both variants appear (textproto merge semantics). let p: Person = decode_from_str(r#"email: "a" phone: "b""#).unwrap(); - assert_eq!(p.contact, Some(person::ContactOneof::Phone("b".into()))); + assert_eq!( + p.contact, + Some(crate::basic::buffa_::oneof::person::Contact::Phone( + "b".into() + )) + ); } // ── repeated ──────────────────────────────────────────────────────────────── @@ -339,7 +350,8 @@ fn group_decode_accepts_both_names() { #[test] fn group_in_oneof_uses_type_name() { - use crate::proto2::view_coverage::{ChoiceOneof, Payload}; + use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::view_coverage::Payload; use crate::proto2::ViewCoverage; let mut v = ViewCoverage::default(); diff --git a/buffa-test/src/tests/utf8_validation.rs b/buffa-test/src/tests/utf8_validation.rs index 1243a4e..901e325 100644 --- a/buffa-test/src/tests/utf8_validation.rs +++ b/buffa-test/src/tests/utf8_validation.rs @@ -46,7 +46,7 @@ fn view_none_fields_are_byte_slices() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = StringNoValidationView::decode_view(&bytes).unwrap(); + let view = buffa_::view::StringNoValidationView::decode_view(&bytes).unwrap(); // raw_name is Option<&[u8]>, validated_name is Option<&str>. let raw: Option<&[u8]> = view.raw_name; let validated: Option<&str> = view.validated_name; @@ -57,13 +57,13 @@ fn view_none_fields_are_byte_slices() { #[test] fn view_none_accepts_invalid_utf8() { let wire = [0x0A, 0x02, 0xFF, 0xFE]; - let view = StringNoValidationView::decode_view(&wire).unwrap(); + let view = buffa_::view::StringNoValidationView::decode_view(&wire).unwrap(); assert_eq!(view.raw_name, Some(&[0xFF, 0xFE][..])); } #[test] fn oneof_none_variant_is_vec_u8() { - use oneof_no_validation::ContentOneof; + use crate::utf8test::buffa_::oneof::oneof_no_validation::Content as ContentOneof; let msg = OneofNoValidation { content: Some(ContentOneof::RawText(b"bytes".to_vec())), ..Default::default() diff --git a/buffa-test/src/tests/view.rs b/buffa-test/src/tests/view.rs index 06fd2ed..d5b8c79 100644 --- a/buffa-test/src/tests/view.rs +++ b/buffa-test/src/tests/view.rs @@ -1,6 +1,8 @@ //! View type tests: decode_view, MessageFieldView Deref, to_owned_message, //! MapView iteration, oneof views, unknown-field preservation, recursion limit. +use crate::basic::buffa_::oneof; +use crate::basic::buffa_::view::*; use crate::basic::*; use buffa::{Message, MessageView}; @@ -96,11 +98,13 @@ fn test_view_proto3_optional_unset_is_none() { #[test] fn test_view_decodes_oneof() { let mut msg = Person::default(); - msg.contact = Some(person::ContactOneof::Email("bob@example.com".into())); + msg.contact = Some(oneof::person::Contact::Email("bob@example.com".into())); let bytes = msg.encode_to_vec(); let view = PersonView::decode_view(&bytes).expect("decode_view"); match view.contact { - Some(person::ContactOneofView::Email(s)) => assert_eq!(s, "bob@example.com"), + Some(crate::basic::buffa_::view::oneof::person::Contact::Email(s)) => { + assert_eq!(s, "bob@example.com") + } other => panic!("expected Email, got {other:?}"), } } @@ -112,7 +116,7 @@ fn test_view_to_owned_roundtrip() { msg.name = "Carol".into(); msg.tags = vec!["x".into(), "y".into()]; msg.maybe_age = Some(30); - msg.contact = Some(person::ContactOneof::Phone("+1-555-0000".into())); + msg.contact = Some(oneof::person::Contact::Phone("+1-555-0000".into())); let bytes = msg.encode_to_vec(); let view = PersonView::decode_view(&bytes).expect("decode_view"); let owned = view.to_owned_message(); @@ -122,7 +126,7 @@ fn test_view_to_owned_roundtrip() { assert_eq!(owned.maybe_age, Some(30)); assert_eq!( owned.contact, - Some(person::ContactOneof::Phone("+1-555-0000".into())) + Some(oneof::person::Contact::Phone("+1-555-0000".into())) ); } @@ -316,7 +320,8 @@ fn test_view_map_with_open_enum_value() { #[test] fn test_view_no_unknown_fields_all_scalar_compiles() { - use crate::basic_no_uf::{AllScalars, AllScalarsView, Empty, EmptyView}; + use crate::basic_no_uf::buffa_::view::{AllScalarsView, EmptyView}; + use crate::basic_no_uf::{AllScalars, Empty}; // EmptyView<'a> has NO fields; AllScalarsView<'a> has only scalars. // Both now carry a PhantomData marker. let e = Empty::default(); diff --git a/buffa-test/src/tests/wkt.rs b/buffa-test/src/tests/wkt.rs index ad8b609..e8f5502 100644 --- a/buffa-test/src/tests/wkt.rs +++ b/buffa-test/src/tests/wkt.rs @@ -13,7 +13,8 @@ fn test_wkt_in_oneof_from_impls() { // // The fact that this test compiles IS the test: wkt_usage.proto has // Envelope.content with Any/Timestamp (extern) + Event (local) variants. - use crate::wkt::{envelope, Envelope, Event}; + use crate::wkt::buffa_::oneof::envelope; + use crate::wkt::{Envelope, Event}; use buffa_types::google::protobuf::Any; // Local variant: both From impls exist. @@ -23,27 +24,27 @@ fn test_wkt_in_oneof_from_impls() { }; assert!(matches!( env.content, - Some(envelope::ContentOneof::EventContent(_)) + Some(envelope::Content::EventContent(_)) )); // Extern variant: only From for Content exists — Some() is explicit. let env = Envelope { - content: Some(envelope::ContentOneof::from(Any::default())), + content: Some(envelope::Content::from(Any::default())), ..Default::default() }; assert!(matches!( env.content, - Some(envelope::ContentOneof::AnyContent(_)) + Some(envelope::Content::AnyContent(_)) )); // The From for Option impl for extern T does NOT exist. // The following would not compile (uncomment to verify): - // let _: Option = Any::default().into(); + // let _: Option = Any::default().into(); let decoded = round_trip(&env); assert!(matches!( decoded.content, - Some(envelope::ContentOneof::AnyContent(_)) + Some(envelope::Content::AnyContent(_)) )); } @@ -85,7 +86,8 @@ fn test_wkt_view_with_extern_path() { // appends "View" to the last path segment: crate::wkt::Timestamp // → crate::wkt::TimestampView (which is re-exported from buffa-types' // generated code). - use crate::wkt::{Event, EventView}; + use crate::wkt::buffa_::view::EventView; + use crate::wkt::Event; use buffa::MessageView; let msg = Event { created_at: buffa::MessageField::some(buffa_types::google::protobuf::Timestamp { diff --git a/buffa-types/src/generated/google.protobuf.any.__ext.rs b/buffa-types/src/generated/google.protobuf.any.__ext.rs new file mode 100644 index 0000000..415a4fc --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.any.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/any.proto + diff --git a/buffa-types/src/generated/google.protobuf.any.__oneof.rs b/buffa-types/src/generated/google.protobuf.any.__oneof.rs new file mode 100644 index 0000000..415a4fc --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.any.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/any.proto + diff --git a/buffa-types/src/generated/google.protobuf.any.__view.rs b/buffa-types/src/generated/google.protobuf.any.__view.rs new file mode 100644 index 0000000..6fbeb1c --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.any.__view.rs @@ -0,0 +1,244 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/any.proto + +/// `Any` contains an arbitrary serialized protocol buffer message along with a +/// URL that describes the type of the serialized message. +/// +/// Protobuf library provides support to pack/unpack Any values in the form +/// of utility functions or additional generated methods of the Any type. +/// +/// Example 1: Pack and unpack a message in C++. +/// +/// ```text +/// Foo foo = ...; +/// Any any; +/// any.PackFrom(foo); +/// ... +/// if (any.UnpackTo(&foo)) { +/// ... +/// } +/// ``` +/// +/// Example 2: Pack and unpack a message in Java. +/// +/// ```text +/// Foo foo = ...; +/// Any any = Any.pack(foo); +/// ... +/// if (any.is(Foo.class)) { +/// foo = any.unpack(Foo.class); +/// } +/// // or ... +/// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +/// foo = any.unpack(Foo.getDefaultInstance()); +/// } +/// ``` +/// +/// Example 3: Pack and unpack a message in Python. +/// +/// ```text +/// foo = Foo(...) +/// any = Any() +/// any.Pack(foo) +/// ... +/// if any.Is(Foo.DESCRIPTOR): +/// any.Unpack(foo) +/// ... +/// ``` +/// +/// Example 4: Pack and unpack a message in Go +/// +/// ```text +/// foo := &pb.Foo{...} +/// any, err := anypb.New(foo) +/// if err != nil { +/// ... +/// } +/// ... +/// foo := &pb.Foo{} +/// if err := any.UnmarshalTo(foo); err != nil { +/// ... +/// } +/// ``` +/// +/// The pack methods provided by protobuf library will by default use +/// 'type.googleapis.com/full.type.name' as the type URL and the unpack +/// methods only use the fully qualified type name after the last '/' +/// in the type URL, for example "foo.bar.com/x/y.z" will yield type +/// name "y.z". +/// +/// JSON +/// ==== +/// The JSON representation of an `Any` value uses the regular +/// representation of the deserialized, embedded message, with an +/// additional field `@type` which contains the type URL. Example: +/// +/// ```text +/// package google.profile; +/// message Person { +/// string first_name = 1; +/// string last_name = 2; +/// } +/// +/// { +/// "@type": "type.googleapis.com/google.profile.Person", +/// "firstName": , +/// "lastName": +/// } +/// ``` +/// +/// If the embedded message type is well-known and has a custom JSON +/// representation, that representation will be embedded adding a field +/// `value` which holds the custom JSON in addition to the `@type` +/// field. Example (for message \[google.protobuf.Duration\]\[\]): +/// +/// ```text +/// { +/// "@type": "type.googleapis.com/google.protobuf.Duration", +/// "value": "1.212s" +/// } +/// ``` +#[derive(Clone, Debug, Default)] +pub struct AnyView<'a> { + /// A URL/resource name that uniquely identifies the type of the serialized + /// protocol buffer message. This string must contain at least + /// one "/" character. The last segment of the URL's path must represent + /// the fully qualified name of the type (as in + /// `path/google.protobuf.Duration`). The name should be in a canonical form + /// (e.g., leading "." is not accepted). + /// + /// In practice, teams usually precompile into the binary all types that they + /// expect it to use in the context of Any. However, for URLs which use the + /// scheme `http`, `https`, or no scheme, one can optionally set up a type + /// server that maps type URLs to message definitions as follows: + /// + /// * If no scheme is provided, `https` is assumed. + /// * An HTTP GET on the URL must yield a \[google.protobuf.Type\]\[\] + /// value in binary format, or produce an error. + /// * Applications are allowed to cache lookup results based on the + /// URL, or have them precompiled into a binary to avoid any + /// lookup. Therefore, binary compatibility needs to be preserved + /// on changes to types. (Use versioned type names to manage + /// breaking changes.) + /// + /// Note: this functionality is not currently available in the official + /// protobuf release, and it is not used for type URLs beginning with + /// type.googleapis.com. As of May 2023, there are no widely used type server + /// implementations and no plans to implement one. + /// + /// Schemes other than `http`, `https` (or the empty scheme) might be + /// used with implementation specific semantics. + /// + /// Field 1: `type_url` + pub type_url: &'a str, + /// Must be a valid serialized protocol buffer of the above specified type. + /// + /// Field 2: `value` + pub value: &'a [u8], + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> AnyView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.type_url = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::borrow_bytes(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for AnyView<'a> { + type Owned = super::super::Any; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Any { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Any { + type_url: self.type_url.to_string(), + value: ::bytes::Bytes::copy_from_slice(self.value), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for AnyView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for AnyView<'a> { + type Static = AnyView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs new file mode 100644 index 0000000..415a4fc --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/any.proto + diff --git a/buffa-types/src/generated/google.protobuf.any.rs b/buffa-types/src/generated/google.protobuf.any.rs index 0c0d995..d77ec9e 100644 --- a/buffa-types/src/generated/google.protobuf.any.rs +++ b/buffa-types/src/generated/google.protobuf.any.rs @@ -266,244 +266,3 @@ pub const __ANY_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa::type_r text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// `Any` contains an arbitrary serialized protocol buffer message along with a -/// URL that describes the type of the serialized message. -/// -/// Protobuf library provides support to pack/unpack Any values in the form -/// of utility functions or additional generated methods of the Any type. -/// -/// Example 1: Pack and unpack a message in C++. -/// -/// ```text -/// Foo foo = ...; -/// Any any; -/// any.PackFrom(foo); -/// ... -/// if (any.UnpackTo(&foo)) { -/// ... -/// } -/// ``` -/// -/// Example 2: Pack and unpack a message in Java. -/// -/// ```text -/// Foo foo = ...; -/// Any any = Any.pack(foo); -/// ... -/// if (any.is(Foo.class)) { -/// foo = any.unpack(Foo.class); -/// } -/// // or ... -/// if (any.isSameTypeAs(Foo.getDefaultInstance())) { -/// foo = any.unpack(Foo.getDefaultInstance()); -/// } -/// ``` -/// -/// Example 3: Pack and unpack a message in Python. -/// -/// ```text -/// foo = Foo(...) -/// any = Any() -/// any.Pack(foo) -/// ... -/// if any.Is(Foo.DESCRIPTOR): -/// any.Unpack(foo) -/// ... -/// ``` -/// -/// Example 4: Pack and unpack a message in Go -/// -/// ```text -/// foo := &pb.Foo{...} -/// any, err := anypb.New(foo) -/// if err != nil { -/// ... -/// } -/// ... -/// foo := &pb.Foo{} -/// if err := any.UnmarshalTo(foo); err != nil { -/// ... -/// } -/// ``` -/// -/// The pack methods provided by protobuf library will by default use -/// 'type.googleapis.com/full.type.name' as the type URL and the unpack -/// methods only use the fully qualified type name after the last '/' -/// in the type URL, for example "foo.bar.com/x/y.z" will yield type -/// name "y.z". -/// -/// JSON -/// ==== -/// The JSON representation of an `Any` value uses the regular -/// representation of the deserialized, embedded message, with an -/// additional field `@type` which contains the type URL. Example: -/// -/// ```text -/// package google.profile; -/// message Person { -/// string first_name = 1; -/// string last_name = 2; -/// } -/// -/// { -/// "@type": "type.googleapis.com/google.profile.Person", -/// "firstName": , -/// "lastName": -/// } -/// ``` -/// -/// If the embedded message type is well-known and has a custom JSON -/// representation, that representation will be embedded adding a field -/// `value` which holds the custom JSON in addition to the `@type` -/// field. Example (for message \[google.protobuf.Duration\]\[\]): -/// -/// ```text -/// { -/// "@type": "type.googleapis.com/google.protobuf.Duration", -/// "value": "1.212s" -/// } -/// ``` -#[derive(Clone, Debug, Default)] -pub struct AnyView<'a> { - /// A URL/resource name that uniquely identifies the type of the serialized - /// protocol buffer message. This string must contain at least - /// one "/" character. The last segment of the URL's path must represent - /// the fully qualified name of the type (as in - /// `path/google.protobuf.Duration`). The name should be in a canonical form - /// (e.g., leading "." is not accepted). - /// - /// In practice, teams usually precompile into the binary all types that they - /// expect it to use in the context of Any. However, for URLs which use the - /// scheme `http`, `https`, or no scheme, one can optionally set up a type - /// server that maps type URLs to message definitions as follows: - /// - /// * If no scheme is provided, `https` is assumed. - /// * An HTTP GET on the URL must yield a \[google.protobuf.Type\]\[\] - /// value in binary format, or produce an error. - /// * Applications are allowed to cache lookup results based on the - /// URL, or have them precompiled into a binary to avoid any - /// lookup. Therefore, binary compatibility needs to be preserved - /// on changes to types. (Use versioned type names to manage - /// breaking changes.) - /// - /// Note: this functionality is not currently available in the official - /// protobuf release, and it is not used for type URLs beginning with - /// type.googleapis.com. As of May 2023, there are no widely used type server - /// implementations and no plans to implement one. - /// - /// Schemes other than `http`, `https` (or the empty scheme) might be - /// used with implementation specific semantics. - /// - /// Field 1: `type_url` - pub type_url: &'a str, - /// Must be a valid serialized protocol buffer of the above specified type. - /// - /// Field 2: `value` - pub value: &'a [u8], - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> AnyView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.type_url = ::buffa::types::borrow_str(&mut cur)?; - } - 2u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 2u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::borrow_bytes(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for AnyView<'a> { - type Owned = Any; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Any { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Any { - type_url: self.type_url.to_string(), - value: ::bytes::Bytes::copy_from_slice(self.value), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for AnyView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for AnyView<'a> { - type Static = AnyView<'static>; -} diff --git a/buffa-types/src/generated/google.protobuf.duration.__ext.rs b/buffa-types/src/generated/google.protobuf.duration.__ext.rs new file mode 100644 index 0000000..2bdabf5 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.duration.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/duration.proto + diff --git a/buffa-types/src/generated/google.protobuf.duration.__oneof.rs b/buffa-types/src/generated/google.protobuf.duration.__oneof.rs new file mode 100644 index 0000000..2bdabf5 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.duration.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/duration.proto + diff --git a/buffa-types/src/generated/google.protobuf.duration.__view.rs b/buffa-types/src/generated/google.protobuf.duration.__view.rs new file mode 100644 index 0000000..69a8f4c --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.duration.__view.rs @@ -0,0 +1,191 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/duration.proto + +/// A Duration represents a signed, fixed-length span of time represented +/// as a count of seconds and fractions of seconds at nanosecond +/// resolution. It is independent of any calendar and concepts like "day" +/// or "month". It is related to Timestamp in that the difference between +/// two Timestamp values is a Duration and it can be added or subtracted +/// from a Timestamp. Range is approximately +-10,000 years. +/// +/// # Examples +/// +/// Example 1: Compute Duration from two Timestamps in pseudo code. +/// +/// ```text +/// Timestamp start = ...; +/// Timestamp end = ...; +/// Duration duration = ...; +/// +/// duration.seconds = end.seconds - start.seconds; +/// duration.nanos = end.nanos - start.nanos; +/// +/// if (duration.seconds < 0 && duration.nanos > 0) { +/// duration.seconds += 1; +/// duration.nanos -= 1000000000; +/// } else if (duration.seconds > 0 && duration.nanos < 0) { +/// duration.seconds -= 1; +/// duration.nanos += 1000000000; +/// } +/// ``` +/// +/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +/// +/// ```text +/// Timestamp start = ...; +/// Duration duration = ...; +/// Timestamp end = ...; +/// +/// end.seconds = start.seconds + duration.seconds; +/// end.nanos = start.nanos + duration.nanos; +/// +/// if (end.nanos < 0) { +/// end.seconds -= 1; +/// end.nanos += 1000000000; +/// } else if (end.nanos >= 1000000000) { +/// end.seconds += 1; +/// end.nanos -= 1000000000; +/// } +/// ``` +/// +/// Example 3: Compute Duration from datetime.timedelta in Python. +/// +/// ```text +/// td = datetime.timedelta(days=3, minutes=10) +/// duration = Duration() +/// duration.FromTimedelta(td) +/// ``` +/// +/// # JSON Mapping +/// +/// In JSON format, the Duration type is encoded as a string rather than an +/// object, where the string ends in the suffix "s" (indicating seconds) and +/// is preceded by the number of seconds, with nanoseconds expressed as +/// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +/// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +/// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +/// microsecond should be expressed in JSON format as "3.000001s". +#[derive(Clone, Debug, Default)] +pub struct DurationView<'a> { + /// Signed seconds of the span of time. Must be from -315,576,000,000 + /// to +315,576,000,000 inclusive. Note: these bounds are computed from: + /// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + /// + /// Field 1: `seconds` + pub seconds: i64, + /// Signed fractions of a second at nanosecond resolution of the span + /// of time. Durations less than one second are represented with a 0 + /// `seconds` field and a positive or negative `nanos` field. For durations + /// of one second or more, a non-zero value for the `nanos` field must be + /// of the same sign as the `seconds` field. Must be from -999,999,999 + /// to +999,999,999 inclusive. + /// + /// Field 2: `nanos` + pub nanos: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> DurationView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.seconds = ::buffa::types::decode_int64(&mut cur)?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.nanos = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for DurationView<'a> { + type Owned = super::super::Duration; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Duration { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Duration { + seconds: self.seconds, + nanos: self.nanos, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for DurationView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for DurationView<'a> { + type Static = DurationView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs new file mode 100644 index 0000000..2bdabf5 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/duration.proto + diff --git a/buffa-types/src/generated/google.protobuf.duration.rs b/buffa-types/src/generated/google.protobuf.duration.rs index fb6cae2..c001848 100644 --- a/buffa-types/src/generated/google.protobuf.duration.rs +++ b/buffa-types/src/generated/google.protobuf.duration.rs @@ -241,191 +241,3 @@ pub const __DURATION_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa::t text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// A Duration represents a signed, fixed-length span of time represented -/// as a count of seconds and fractions of seconds at nanosecond -/// resolution. It is independent of any calendar and concepts like "day" -/// or "month". It is related to Timestamp in that the difference between -/// two Timestamp values is a Duration and it can be added or subtracted -/// from a Timestamp. Range is approximately +-10,000 years. -/// -/// # Examples -/// -/// Example 1: Compute Duration from two Timestamps in pseudo code. -/// -/// ```text -/// Timestamp start = ...; -/// Timestamp end = ...; -/// Duration duration = ...; -/// -/// duration.seconds = end.seconds - start.seconds; -/// duration.nanos = end.nanos - start.nanos; -/// -/// if (duration.seconds < 0 && duration.nanos > 0) { -/// duration.seconds += 1; -/// duration.nanos -= 1000000000; -/// } else if (duration.seconds > 0 && duration.nanos < 0) { -/// duration.seconds -= 1; -/// duration.nanos += 1000000000; -/// } -/// ``` -/// -/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -/// -/// ```text -/// Timestamp start = ...; -/// Duration duration = ...; -/// Timestamp end = ...; -/// -/// end.seconds = start.seconds + duration.seconds; -/// end.nanos = start.nanos + duration.nanos; -/// -/// if (end.nanos < 0) { -/// end.seconds -= 1; -/// end.nanos += 1000000000; -/// } else if (end.nanos >= 1000000000) { -/// end.seconds += 1; -/// end.nanos -= 1000000000; -/// } -/// ``` -/// -/// Example 3: Compute Duration from datetime.timedelta in Python. -/// -/// ```text -/// td = datetime.timedelta(days=3, minutes=10) -/// duration = Duration() -/// duration.FromTimedelta(td) -/// ``` -/// -/// # JSON Mapping -/// -/// In JSON format, the Duration type is encoded as a string rather than an -/// object, where the string ends in the suffix "s" (indicating seconds) and -/// is preceded by the number of seconds, with nanoseconds expressed as -/// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -/// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -/// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -/// microsecond should be expressed in JSON format as "3.000001s". -#[derive(Clone, Debug, Default)] -pub struct DurationView<'a> { - /// Signed seconds of the span of time. Must be from -315,576,000,000 - /// to +315,576,000,000 inclusive. Note: these bounds are computed from: - /// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - /// - /// Field 1: `seconds` - pub seconds: i64, - /// Signed fractions of a second at nanosecond resolution of the span - /// of time. Durations less than one second are represented with a 0 - /// `seconds` field and a positive or negative `nanos` field. For durations - /// of one second or more, a non-zero value for the `nanos` field must be - /// of the same sign as the `seconds` field. Must be from -999,999,999 - /// to +999,999,999 inclusive. - /// - /// Field 2: `nanos` - pub nanos: i32, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> DurationView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.seconds = ::buffa::types::decode_int64(&mut cur)?; - } - 2u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 2u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.nanos = ::buffa::types::decode_int32(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for DurationView<'a> { - type Owned = Duration; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Duration { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Duration { - seconds: self.seconds, - nanos: self.nanos, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for DurationView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for DurationView<'a> { - type Static = DurationView<'static>; -} diff --git a/buffa-types/src/generated/google.protobuf.empty.__ext.rs b/buffa-types/src/generated/google.protobuf.empty.__ext.rs new file mode 100644 index 0000000..eafd5d8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.empty.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/empty.proto + diff --git a/buffa-types/src/generated/google.protobuf.empty.__oneof.rs b/buffa-types/src/generated/google.protobuf.empty.__oneof.rs new file mode 100644 index 0000000..eafd5d8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.empty.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/empty.proto + diff --git a/buffa-types/src/generated/google.protobuf.empty.__view.rs b/buffa-types/src/generated/google.protobuf.empty.__view.rs new file mode 100644 index 0000000..cc4c4a0 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.empty.__view.rs @@ -0,0 +1,99 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/empty.proto + +/// A generic empty message that you can re-use to avoid defining duplicated +/// empty messages in your APIs. +/// +/// Example usage: gRPC uses google.protobuf.Empty as the input and output +/// type for RPCs defined as returning or accepting "nothing": +/// +/// ```text +/// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct EmptyView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> EmptyView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for EmptyView<'a> { + type Owned = super::super::Empty; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Empty { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Empty { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for EmptyView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for EmptyView<'a> { + type Static = EmptyView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs new file mode 100644 index 0000000..eafd5d8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/empty.proto + diff --git a/buffa-types/src/generated/google.protobuf.empty.rs b/buffa-types/src/generated/google.protobuf.empty.rs index 2c6b5ce..86c5376 100644 --- a/buffa-types/src/generated/google.protobuf.empty.rs +++ b/buffa-types/src/generated/google.protobuf.empty.rs @@ -120,99 +120,3 @@ pub const __EMPTY_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa::type text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// A generic empty message that you can re-use to avoid defining duplicated -/// empty messages in your APIs. -/// -/// Example usage: gRPC uses google.protobuf.Empty as the input and output -/// type for RPCs defined as returning or accepting "nothing": -/// -/// ```text -/// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); -/// ``` -#[derive(Clone, Debug, Default)] -pub struct EmptyView<'a> { - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> EmptyView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for EmptyView<'a> { - type Owned = Empty; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Empty { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Empty { - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for EmptyView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for EmptyView<'a> { - type Static = EmptyView<'static>; -} diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs b/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs new file mode 100644 index 0000000..e76a3b8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/field_mask.proto + diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs b/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs new file mode 100644 index 0000000..e76a3b8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/field_mask.proto + diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs new file mode 100644 index 0000000..08ad6a2 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs @@ -0,0 +1,328 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/field_mask.proto + +/// `FieldMask` represents a set of symbolic field paths, for example: +/// +/// ```text +/// paths: "f.a" +/// paths: "f.b.d" +/// ``` +/// +/// Here `f` represents a field in some root message, `a` and `b` +/// fields in the message found in `f`, and `d` a field found in the +/// message in `f.b`. +/// +/// Field masks are used to specify a subset of fields that should be +/// returned by a get operation or modified by an update operation. +/// Field masks also have a custom JSON encoding (see below). +/// +/// # Field Masks in Projections +/// +/// When used in the context of a projection, a response message or +/// sub-message is filtered by the API to only contain those fields as +/// specified in the mask. For example, if the mask in the previous +/// example is applied to a response message as follows: +/// +/// ```text +/// f { +/// a : 22 +/// b { +/// d : 1 +/// x : 2 +/// } +/// y : 13 +/// } +/// z: 8 +/// ``` +/// +/// The result will not contain specific values for fields x,y and z +/// (their value will be set to the default, and omitted in proto text +/// output): +/// +/// +/// ```text +/// f { +/// a : 22 +/// b { +/// d : 1 +/// } +/// } +/// ``` +/// +/// A repeated field is not allowed except at the last position of a +/// paths string. +/// +/// If a FieldMask object is not present in a get operation, the +/// operation applies to all fields (as if a FieldMask of all fields +/// had been specified). +/// +/// Note that a field mask does not necessarily apply to the +/// top-level response message. In case of a REST get operation, the +/// field mask applies directly to the response, but in case of a REST +/// list operation, the mask instead applies to each individual message +/// in the returned resource list. In case of a REST custom method, +/// other definitions may be used. Where the mask applies will be +/// clearly documented together with its declaration in the API. In +/// any case, the effect on the returned resource/resources is required +/// behavior for APIs. +/// +/// # Field Masks in Update Operations +/// +/// A field mask in update operations specifies which fields of the +/// targeted resource are going to be updated. The API is required +/// to only change the values of the fields as specified in the mask +/// and leave the others untouched. If a resource is passed in to +/// describe the updated values, the API ignores the values of all +/// fields not covered by the mask. +/// +/// If a repeated field is specified for an update operation, new values will +/// be appended to the existing repeated field in the target resource. Note that +/// a repeated field is only allowed in the last position of a `paths` string. +/// +/// If a sub-message is specified in the last position of the field mask for an +/// update operation, then new value will be merged into the existing sub-message +/// in the target resource. +/// +/// For example, given the target message: +/// +/// ```text +/// f { +/// b { +/// d: 1 +/// x: 2 +/// } +/// c: [1] +/// } +/// ``` +/// +/// And an update message: +/// +/// ```text +/// f { +/// b { +/// d: 10 +/// } +/// c: [2] +/// } +/// ``` +/// +/// then if the field mask is: +/// +/// paths: \["f.b", "f.c"\] +/// +/// then the result will be: +/// +/// ```text +/// f { +/// b { +/// d: 10 +/// x: 2 +/// } +/// c: [1, 2] +/// } +/// ``` +/// +/// An implementation may provide options to override this default behavior for +/// repeated and message fields. +/// +/// In order to reset a field's value to the default, the field must +/// be in the mask and set to the default value in the provided resource. +/// Hence, in order to reset all fields of a resource, provide a default +/// instance of the resource and set all fields in the mask, or do +/// not provide a mask as described below. +/// +/// If a field mask is not present on update, the operation applies to +/// all fields (as if a field mask of all fields has been specified). +/// Note that in the presence of schema evolution, this may mean that +/// fields the client does not know and has therefore not filled into +/// the request will be reset to their default. If this is unwanted +/// behavior, a specific service may require a client to always specify +/// a field mask, producing an error if not. +/// +/// As with get operations, the location of the resource which +/// describes the updated values in the request message depends on the +/// operation kind. In any case, the effect of the field mask is +/// required to be honored by the API. +/// +/// ## Considerations for HTTP REST +/// +/// The HTTP kind of an update operation which uses a field mask must +/// be set to PATCH instead of PUT in order to satisfy HTTP semantics +/// (PUT must only be used for full updates). +/// +/// # JSON Encoding of Field Masks +/// +/// In JSON, a field mask is encoded as a single string where paths are +/// separated by a comma. Fields name in each path are converted +/// to/from lower-camel naming conventions. +/// +/// As an example, consider the following message declarations: +/// +/// ```text +/// message Profile { +/// User user = 1; +/// Photo photo = 2; +/// } +/// message User { +/// string display_name = 1; +/// string address = 2; +/// } +/// ``` +/// +/// In proto a field mask for `Profile` may look as such: +/// +/// ```text +/// mask { +/// paths: "user.display_name" +/// paths: "photo" +/// } +/// ``` +/// +/// In JSON, the same mask is represented as below: +/// +/// ```text +/// { +/// mask: "user.displayName,photo" +/// } +/// ``` +/// +/// # Field Masks and Oneof Fields +/// +/// Field masks treat fields in oneofs just as regular fields. Consider the +/// following message: +/// +/// ```text +/// message SampleMessage { +/// oneof test_oneof { +/// string name = 4; +/// SubMessage sub_message = 9; +/// } +/// } +/// ``` +/// +/// The field mask can be: +/// +/// ```text +/// mask { +/// paths: "name" +/// } +/// ``` +/// +/// Or: +/// +/// ```text +/// mask { +/// paths: "sub_message" +/// } +/// ``` +/// +/// Note that oneof type names ("test_oneof" in this case) cannot be used in +/// paths. +/// +/// ## Field Mask Verification +/// +/// The implementation of any API method which has a FieldMask type field in the +/// request should verify the included field paths, and return an +/// `INVALID_ARGUMENT` error if any path is unmappable. +#[derive(Clone, Debug, Default)] +pub struct FieldMaskView<'a> { + /// The set of field mask paths. + /// + /// Field 1: `paths` + pub paths: ::buffa::RepeatedView<'a, &'a str>, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> FieldMaskView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.paths.push(::buffa::types::borrow_str(&mut cur)?); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for FieldMaskView<'a> { + type Owned = super::super::FieldMask; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::FieldMask { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::FieldMask { + paths: self.paths.iter().map(|s| s.to_string()).collect(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for FieldMaskView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for FieldMaskView<'a> { + type Static = FieldMaskView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs new file mode 100644 index 0000000..e76a3b8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/field_mask.proto + diff --git a/buffa-types/src/generated/google.protobuf.field_mask.rs b/buffa-types/src/generated/google.protobuf.field_mask.rs index 2d9ef78..1fee4fe 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.rs @@ -370,328 +370,3 @@ pub const __FIELD_MASK_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa: text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// `FieldMask` represents a set of symbolic field paths, for example: -/// -/// ```text -/// paths: "f.a" -/// paths: "f.b.d" -/// ``` -/// -/// Here `f` represents a field in some root message, `a` and `b` -/// fields in the message found in `f`, and `d` a field found in the -/// message in `f.b`. -/// -/// Field masks are used to specify a subset of fields that should be -/// returned by a get operation or modified by an update operation. -/// Field masks also have a custom JSON encoding (see below). -/// -/// # Field Masks in Projections -/// -/// When used in the context of a projection, a response message or -/// sub-message is filtered by the API to only contain those fields as -/// specified in the mask. For example, if the mask in the previous -/// example is applied to a response message as follows: -/// -/// ```text -/// f { -/// a : 22 -/// b { -/// d : 1 -/// x : 2 -/// } -/// y : 13 -/// } -/// z: 8 -/// ``` -/// -/// The result will not contain specific values for fields x,y and z -/// (their value will be set to the default, and omitted in proto text -/// output): -/// -/// -/// ```text -/// f { -/// a : 22 -/// b { -/// d : 1 -/// } -/// } -/// ``` -/// -/// A repeated field is not allowed except at the last position of a -/// paths string. -/// -/// If a FieldMask object is not present in a get operation, the -/// operation applies to all fields (as if a FieldMask of all fields -/// had been specified). -/// -/// Note that a field mask does not necessarily apply to the -/// top-level response message. In case of a REST get operation, the -/// field mask applies directly to the response, but in case of a REST -/// list operation, the mask instead applies to each individual message -/// in the returned resource list. In case of a REST custom method, -/// other definitions may be used. Where the mask applies will be -/// clearly documented together with its declaration in the API. In -/// any case, the effect on the returned resource/resources is required -/// behavior for APIs. -/// -/// # Field Masks in Update Operations -/// -/// A field mask in update operations specifies which fields of the -/// targeted resource are going to be updated. The API is required -/// to only change the values of the fields as specified in the mask -/// and leave the others untouched. If a resource is passed in to -/// describe the updated values, the API ignores the values of all -/// fields not covered by the mask. -/// -/// If a repeated field is specified for an update operation, new values will -/// be appended to the existing repeated field in the target resource. Note that -/// a repeated field is only allowed in the last position of a `paths` string. -/// -/// If a sub-message is specified in the last position of the field mask for an -/// update operation, then new value will be merged into the existing sub-message -/// in the target resource. -/// -/// For example, given the target message: -/// -/// ```text -/// f { -/// b { -/// d: 1 -/// x: 2 -/// } -/// c: [1] -/// } -/// ``` -/// -/// And an update message: -/// -/// ```text -/// f { -/// b { -/// d: 10 -/// } -/// c: [2] -/// } -/// ``` -/// -/// then if the field mask is: -/// -/// paths: \["f.b", "f.c"\] -/// -/// then the result will be: -/// -/// ```text -/// f { -/// b { -/// d: 10 -/// x: 2 -/// } -/// c: [1, 2] -/// } -/// ``` -/// -/// An implementation may provide options to override this default behavior for -/// repeated and message fields. -/// -/// In order to reset a field's value to the default, the field must -/// be in the mask and set to the default value in the provided resource. -/// Hence, in order to reset all fields of a resource, provide a default -/// instance of the resource and set all fields in the mask, or do -/// not provide a mask as described below. -/// -/// If a field mask is not present on update, the operation applies to -/// all fields (as if a field mask of all fields has been specified). -/// Note that in the presence of schema evolution, this may mean that -/// fields the client does not know and has therefore not filled into -/// the request will be reset to their default. If this is unwanted -/// behavior, a specific service may require a client to always specify -/// a field mask, producing an error if not. -/// -/// As with get operations, the location of the resource which -/// describes the updated values in the request message depends on the -/// operation kind. In any case, the effect of the field mask is -/// required to be honored by the API. -/// -/// ## Considerations for HTTP REST -/// -/// The HTTP kind of an update operation which uses a field mask must -/// be set to PATCH instead of PUT in order to satisfy HTTP semantics -/// (PUT must only be used for full updates). -/// -/// # JSON Encoding of Field Masks -/// -/// In JSON, a field mask is encoded as a single string where paths are -/// separated by a comma. Fields name in each path are converted -/// to/from lower-camel naming conventions. -/// -/// As an example, consider the following message declarations: -/// -/// ```text -/// message Profile { -/// User user = 1; -/// Photo photo = 2; -/// } -/// message User { -/// string display_name = 1; -/// string address = 2; -/// } -/// ``` -/// -/// In proto a field mask for `Profile` may look as such: -/// -/// ```text -/// mask { -/// paths: "user.display_name" -/// paths: "photo" -/// } -/// ``` -/// -/// In JSON, the same mask is represented as below: -/// -/// ```text -/// { -/// mask: "user.displayName,photo" -/// } -/// ``` -/// -/// # Field Masks and Oneof Fields -/// -/// Field masks treat fields in oneofs just as regular fields. Consider the -/// following message: -/// -/// ```text -/// message SampleMessage { -/// oneof test_oneof { -/// string name = 4; -/// SubMessage sub_message = 9; -/// } -/// } -/// ``` -/// -/// The field mask can be: -/// -/// ```text -/// mask { -/// paths: "name" -/// } -/// ``` -/// -/// Or: -/// -/// ```text -/// mask { -/// paths: "sub_message" -/// } -/// ``` -/// -/// Note that oneof type names ("test_oneof" in this case) cannot be used in -/// paths. -/// -/// ## Field Mask Verification -/// -/// The implementation of any API method which has a FieldMask type field in the -/// request should verify the included field paths, and return an -/// `INVALID_ARGUMENT` error if any path is unmappable. -#[derive(Clone, Debug, Default)] -pub struct FieldMaskView<'a> { - /// The set of field mask paths. - /// - /// Field 1: `paths` - pub paths: ::buffa::RepeatedView<'a, &'a str>, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> FieldMaskView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.paths.push(::buffa::types::borrow_str(&mut cur)?); - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for FieldMaskView<'a> { - type Owned = FieldMask; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> FieldMask { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - FieldMask { - paths: self.paths.iter().map(|s| s.to_string()).collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for FieldMaskView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for FieldMaskView<'a> { - type Static = FieldMaskView<'static>; -} diff --git a/buffa-types/src/generated/google.protobuf.mod.rs b/buffa-types/src/generated/google.protobuf.mod.rs new file mode 100644 index 0000000..b4b4ec8 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.mod.rs @@ -0,0 +1,53 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. + +include!("google.protobuf.any.rs"); +include!("google.protobuf.duration.rs"); +include!("google.protobuf.empty.rs"); +include!("google.protobuf.field_mask.rs"); +include!("google.protobuf.struct.rs"); +include!("google.protobuf.timestamp.rs"); +include!("google.protobuf.wrappers.rs"); +#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +pub mod buffa_ { + #[allow(unused_imports)] use super::*; + pub mod view { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.any.__view.rs"); + include!("google.protobuf.duration.__view.rs"); + include!("google.protobuf.empty.__view.rs"); + include!("google.protobuf.field_mask.__view.rs"); + include!("google.protobuf.struct.__view.rs"); + include!("google.protobuf.timestamp.__view.rs"); + include!("google.protobuf.wrappers.__view.rs"); + pub mod oneof { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.any.__view_oneof.rs"); + include!("google.protobuf.duration.__view_oneof.rs"); + include!("google.protobuf.empty.__view_oneof.rs"); + include!("google.protobuf.field_mask.__view_oneof.rs"); + include!("google.protobuf.struct.__view_oneof.rs"); + include!("google.protobuf.timestamp.__view_oneof.rs"); + include!("google.protobuf.wrappers.__view_oneof.rs"); + } + } + pub mod oneof { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.any.__oneof.rs"); + include!("google.protobuf.duration.__oneof.rs"); + include!("google.protobuf.empty.__oneof.rs"); + include!("google.protobuf.field_mask.__oneof.rs"); + include!("google.protobuf.struct.__oneof.rs"); + include!("google.protobuf.timestamp.__oneof.rs"); + include!("google.protobuf.wrappers.__oneof.rs"); + } + pub mod ext { + #[allow(unused_imports)] use super::*; + include!("google.protobuf.any.__ext.rs"); + include!("google.protobuf.duration.__ext.rs"); + include!("google.protobuf.empty.__ext.rs"); + include!("google.protobuf.field_mask.__ext.rs"); + include!("google.protobuf.struct.__ext.rs"); + include!("google.protobuf.timestamp.__ext.rs"); + include!("google.protobuf.wrappers.__ext.rs"); + } +} diff --git a/buffa-types/src/generated/google.protobuf.struct.__ext.rs b/buffa-types/src/generated/google.protobuf.struct.__ext.rs new file mode 100644 index 0000000..97f4e50 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.struct.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/struct.proto + diff --git a/buffa-types/src/generated/google.protobuf.struct.__oneof.rs b/buffa-types/src/generated/google.protobuf.struct.__oneof.rs new file mode 100644 index 0000000..675e7da --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.struct.__oneof.rs @@ -0,0 +1,39 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/struct.proto + +pub mod value { + #[allow(unused_imports)] + use super::*; + /// The kind of value. + #[derive(Clone, PartialEq, Debug)] + #[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))] + pub enum Kind { + NullValue(::buffa::EnumValue), + NumberValue(f64), + StringValue(::buffa::alloc::string::String), + BoolValue(bool), + StructValue(::buffa::alloc::boxed::Box), + ListValue(::buffa::alloc::boxed::Box), + } + impl ::buffa::Oneof for Kind {} + impl From for Kind { + fn from(v: super::super::super::Struct) -> Self { + Self::StructValue(::buffa::alloc::boxed::Box::new(v)) + } + } + impl From for ::core::option::Option { + fn from(v: super::super::super::Struct) -> Self { + Self::Some(Kind::from(v)) + } + } + impl From for Kind { + fn from(v: super::super::super::ListValue) -> Self { + Self::ListValue(::buffa::alloc::boxed::Box::new(v)) + } + } + impl From for ::core::option::Option { + fn from(v: super::super::super::ListValue) -> Self { + Self::Some(Kind::from(v)) + } + } +} diff --git a/buffa-types/src/generated/google.protobuf.struct.__view.rs b/buffa-types/src/generated/google.protobuf.struct.__view.rs new file mode 100644 index 0000000..7a5d3a4 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.struct.__view.rs @@ -0,0 +1,524 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/struct.proto + +/// `Struct` represents a structured data value, consisting of fields +/// which map to dynamically typed values. In some languages, `Struct` +/// might be supported by a native representation. For example, in +/// scripting languages like JS a struct is represented as an +/// object. The details of that representation are described together +/// with the proto support for the language. +/// +/// The JSON representation for `Struct` is JSON object. +#[derive(Clone, Debug, Default)] +pub struct StructView<'a> { + /// Unordered map of dynamically typed values. + /// + /// Field 1: `fields` (map) + pub fields: ::buffa::MapView<'a, &'a str, super::super::buffa_::view::ValueView<'a>>, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> StructView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + let entry_bytes = ::buffa::types::borrow_bytes(&mut cur)?; + let mut entry_cur: &'a [u8] = entry_bytes; + let mut key = ""; + let mut val = ::core::default::Default::default(); + while !entry_cur.is_empty() { + let entry_tag = ::buffa::encoding::Tag::decode(&mut entry_cur)?; + match entry_tag.field_number() { + 1 => { + if entry_tag.wire_type() + != ::buffa::encoding::WireType::LengthDelimited + { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: entry_tag.field_number(), + expected: 2u8, + actual: entry_tag.wire_type() as u8, + }); + } + key = ::buffa::types::borrow_str(&mut entry_cur)?; + } + 2 => { + if entry_tag.wire_type() + != ::buffa::encoding::WireType::LengthDelimited + { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: entry_tag.field_number(), + expected: 2u8, + actual: entry_tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut entry_cur)?; + val = super::super::buffa_::view::ValueView::_decode_depth( + sub, + depth - 1, + )?; + } + _ => { + ::buffa::encoding::skip_field_depth( + entry_tag, + &mut entry_cur, + depth, + )?; + } + } + } + view.fields.push(key, val); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for StructView<'a> { + type Owned = super::super::Struct; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Struct { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Struct { + fields: self + .fields + .iter() + .map(|(k, v)| (k.to_string(), v.to_owned_message())) + .collect(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for StructView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for StructView<'a> { + type Static = StructView<'static>; +} +/// `Value` represents a dynamically typed value which can be either +/// null, a number, a string, a boolean, a recursive struct value, or a +/// list of values. A producer of value is expected to set one of these +/// variants. Absence of any variant indicates an error. +/// +/// The JSON representation for `Value` is JSON value. +#[derive(Clone, Debug, Default)] +pub struct ValueView<'a> { + pub kind: ::core::option::Option>, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> ValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.kind = Some( + super::super::buffa_::view::oneof::value::Kind::NullValue( + ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ), + ), + ); + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Fixed64 { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 1u8, + actual: tag.wire_type() as u8, + }); + } + view.kind = Some( + super::super::buffa_::view::oneof::value::Kind::NumberValue( + ::buffa::types::decode_double(&mut cur)?, + ), + ); + } + 3u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 3u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.kind = Some( + super::super::buffa_::view::oneof::value::Kind::StringValue( + ::buffa::types::borrow_str(&mut cur)?, + ), + ); + } + 4u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 4u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.kind = Some( + super::super::buffa_::view::oneof::value::Kind::BoolValue( + ::buffa::types::decode_bool(&mut cur)?, + ), + ); + } + 5u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 5u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + if let Some( + super::super::buffa_::view::oneof::value::Kind::StructValue( + ref mut existing, + ), + ) = view.kind + { + existing._merge_into_view(sub, depth - 1)?; + } else { + view.kind = Some( + super::super::buffa_::view::oneof::value::Kind::StructValue( + ::buffa::alloc::boxed::Box::new( + super::super::buffa_::view::StructView::_decode_depth( + sub, + depth - 1, + )?, + ), + ), + ); + } + } + 6u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 6u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + if let Some( + super::super::buffa_::view::oneof::value::Kind::ListValue( + ref mut existing, + ), + ) = view.kind + { + existing._merge_into_view(sub, depth - 1)?; + } else { + view.kind = Some( + super::super::buffa_::view::oneof::value::Kind::ListValue( + ::buffa::alloc::boxed::Box::new( + super::super::buffa_::view::ListValueView::_decode_depth( + sub, + depth - 1, + )?, + ), + ), + ); + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for ValueView<'a> { + type Owned = super::super::Value; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Value { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Value { + kind: self + .kind + .as_ref() + .map(|v| match v { + super::super::buffa_::view::oneof::value::Kind::NullValue(v) => { + super::super::buffa_::oneof::value::Kind::NullValue(*v) + } + super::super::buffa_::view::oneof::value::Kind::NumberValue(v) => { + super::super::buffa_::oneof::value::Kind::NumberValue(*v) + } + super::super::buffa_::view::oneof::value::Kind::StringValue(v) => { + super::super::buffa_::oneof::value::Kind::StringValue( + v.to_string(), + ) + } + super::super::buffa_::view::oneof::value::Kind::BoolValue(v) => { + super::super::buffa_::oneof::value::Kind::BoolValue(*v) + } + super::super::buffa_::view::oneof::value::Kind::StructValue(v) => { + super::super::buffa_::oneof::value::Kind::StructValue( + ::buffa::alloc::boxed::Box::new(v.to_owned_message()), + ) + } + super::super::buffa_::view::oneof::value::Kind::ListValue(v) => { + super::super::buffa_::oneof::value::Kind::ListValue( + ::buffa::alloc::boxed::Box::new(v.to_owned_message()), + ) + } + }), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for ValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for ValueView<'a> { + type Static = ValueView<'static>; +} +/// `ListValue` is a wrapper around a repeated field of values. +/// +/// The JSON representation for `ListValue` is JSON array. +#[derive(Clone, Debug, Default)] +pub struct ListValueView<'a> { + /// Repeated field of dynamically typed values. + /// + /// Field 1: `values` + pub values: ::buffa::RepeatedView<'a, super::super::buffa_::view::ValueView<'a>>, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> ListValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + view.values + .push( + super::super::buffa_::view::ValueView::_decode_depth( + sub, + depth - 1, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for ListValueView<'a> { + type Owned = super::super::ListValue; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::ListValue { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::ListValue { + values: self.values.iter().map(|v| v.to_owned_message()).collect(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for ListValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for ListValueView<'a> { + type Static = ListValueView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs new file mode 100644 index 0000000..39576b5 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs @@ -0,0 +1,24 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/struct.proto + +pub mod value { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, Debug)] + pub enum Kind<'a> { + NullValue(::buffa::EnumValue), + NumberValue(f64), + StringValue(&'a str), + BoolValue(bool), + StructValue( + ::buffa::alloc::boxed::Box< + super::super::super::super::buffa_::view::StructView<'a>, + >, + ), + ListValue( + ::buffa::alloc::boxed::Box< + super::super::super::super::buffa_::view::ListValueView<'a>, + >, + ), + } +} diff --git a/buffa-types/src/generated/google.protobuf.struct.rs b/buffa-types/src/generated/google.protobuf.struct.rs index 23ac12d..278b651 100644 --- a/buffa-types/src/generated/google.protobuf.struct.rs +++ b/buffa-types/src/generated/google.protobuf.struct.rs @@ -319,164 +319,6 @@ pub const __STRUCT_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa::typ text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// `Struct` represents a structured data value, consisting of fields -/// which map to dynamically typed values. In some languages, `Struct` -/// might be supported by a native representation. For example, in -/// scripting languages like JS a struct is represented as an -/// object. The details of that representation are described together -/// with the proto support for the language. -/// -/// The JSON representation for `Struct` is JSON object. -#[derive(Clone, Debug, Default)] -pub struct StructView<'a> { - /// Unordered map of dynamically typed values. - /// - /// Field 1: `fields` (map) - pub fields: ::buffa::MapView<'a, &'a str, ValueView<'a>>, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> StructView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - let entry_bytes = ::buffa::types::borrow_bytes(&mut cur)?; - let mut entry_cur: &'a [u8] = entry_bytes; - let mut key = ""; - let mut val = ::core::default::Default::default(); - while !entry_cur.is_empty() { - let entry_tag = ::buffa::encoding::Tag::decode(&mut entry_cur)?; - match entry_tag.field_number() { - 1 => { - if entry_tag.wire_type() - != ::buffa::encoding::WireType::LengthDelimited - { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: entry_tag.field_number(), - expected: 2u8, - actual: entry_tag.wire_type() as u8, - }); - } - key = ::buffa::types::borrow_str(&mut entry_cur)?; - } - 2 => { - if entry_tag.wire_type() - != ::buffa::encoding::WireType::LengthDelimited - { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: entry_tag.field_number(), - expected: 2u8, - actual: entry_tag.wire_type() as u8, - }); - } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_bytes(&mut entry_cur)?; - val = ValueView::_decode_depth(sub, depth - 1)?; - } - _ => { - ::buffa::encoding::skip_field_depth( - entry_tag, - &mut entry_cur, - depth, - )?; - } - } - } - view.fields.push(key, val); - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for StructView<'a> { - type Owned = Struct; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Struct { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Struct { - fields: self - .fields - .iter() - .map(|(k, v)| (k.to_string(), v.to_owned_message())) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for StructView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for StructView<'a> { - type Static = StructView<'static>; -} /// `Value` represents a dynamically typed value which can be either /// null, a number, a string, a boolean, a recursive struct value, or a /// list of values. A producer of value is expected to set one of these @@ -486,7 +328,7 @@ unsafe impl<'a> ::buffa::HasDefaultViewInstance for StructView<'a> { #[derive(Clone, PartialEq, Default)] #[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))] pub struct Value { - pub kind: Option, + pub kind: Option, #[doc(hidden)] pub __buffa_unknown_fields: ::buffa::UnknownFields, #[doc(hidden)] @@ -522,25 +364,25 @@ impl ::buffa::Message for Value { let mut size = 0u32; if let ::core::option::Option::Some(ref v) = self.kind { match v { - value::KindOneof::NullValue(x) => { + buffa_::oneof::value::Kind::NullValue(x) => { size += 1u32 + ::buffa::types::int32_encoded_len(x.to_i32()) as u32; } - value::KindOneof::NumberValue(_x) => { + buffa_::oneof::value::Kind::NumberValue(_x) => { size += 1u32 + ::buffa::types::FIXED64_ENCODED_LEN as u32; } - value::KindOneof::StringValue(x) => { + buffa_::oneof::value::Kind::StringValue(x) => { size += 1u32 + ::buffa::types::string_encoded_len(x) as u32; } - value::KindOneof::BoolValue(_x) => { + buffa_::oneof::value::Kind::BoolValue(_x) => { size += 1u32 + ::buffa::types::BOOL_ENCODED_LEN as u32; } - value::KindOneof::StructValue(x) => { + buffa_::oneof::value::Kind::StructValue(x) => { let inner = x.compute_size(); size += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 + inner; } - value::KindOneof::ListValue(x) => { + buffa_::oneof::value::Kind::ListValue(x) => { let inner = x.compute_size(); size += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 @@ -557,7 +399,7 @@ impl ::buffa::Message for Value { use ::buffa::Enumeration as _; if let ::core::option::Option::Some(ref v) = self.kind { match v { - value::KindOneof::NullValue(x) => { + buffa_::oneof::value::Kind::NullValue(x) => { ::buffa::encoding::Tag::new( 1u32, ::buffa::encoding::WireType::Varint, @@ -565,7 +407,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_int32(x.to_i32(), buf); } - value::KindOneof::NumberValue(x) => { + buffa_::oneof::value::Kind::NumberValue(x) => { ::buffa::encoding::Tag::new( 2u32, ::buffa::encoding::WireType::Fixed64, @@ -573,7 +415,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_double(*x, buf); } - value::KindOneof::StringValue(x) => { + buffa_::oneof::value::Kind::StringValue(x) => { ::buffa::encoding::Tag::new( 3u32, ::buffa::encoding::WireType::LengthDelimited, @@ -581,7 +423,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_string(x, buf); } - value::KindOneof::BoolValue(x) => { + buffa_::oneof::value::Kind::BoolValue(x) => { ::buffa::encoding::Tag::new( 4u32, ::buffa::encoding::WireType::Varint, @@ -589,7 +431,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_bool(*x, buf); } - value::KindOneof::StructValue(x) => { + buffa_::oneof::value::Kind::StructValue(x) => { ::buffa::encoding::Tag::new( 5u32, ::buffa::encoding::WireType::LengthDelimited, @@ -598,7 +440,7 @@ impl ::buffa::Message for Value { ::buffa::encoding::encode_varint(x.cached_size() as u64, buf); x.write_to(buf); } - value::KindOneof::ListValue(x) => { + buffa_::oneof::value::Kind::ListValue(x) => { ::buffa::encoding::Tag::new( 6u32, ::buffa::encoding::WireType::LengthDelimited, @@ -631,7 +473,7 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - value::KindOneof::NullValue( + buffa_::oneof::value::Kind::NullValue( ::buffa::EnumValue::from(::buffa::types::decode_int32(buf)?), ), ); @@ -645,7 +487,9 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - value::KindOneof::NumberValue(::buffa::types::decode_double(buf)?), + buffa_::oneof::value::Kind::NumberValue( + ::buffa::types::decode_double(buf)?, + ), ); } 3u32 => { @@ -657,7 +501,9 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - value::KindOneof::StringValue(::buffa::types::decode_string(buf)?), + buffa_::oneof::value::Kind::StringValue( + ::buffa::types::decode_string(buf)?, + ), ); } 4u32 => { @@ -669,7 +515,9 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - value::KindOneof::BoolValue(::buffa::types::decode_bool(buf)?), + buffa_::oneof::value::Kind::BoolValue( + ::buffa::types::decode_bool(buf)?, + ), ); } 5u32 => { @@ -681,7 +529,7 @@ impl ::buffa::Message for Value { }); } if let ::core::option::Option::Some( - value::KindOneof::StructValue(ref mut existing), + buffa_::oneof::value::Kind::StructValue(ref mut existing), ) = self.kind { ::buffa::Message::merge_length_delimited( @@ -693,7 +541,7 @@ impl ::buffa::Message for Value { let mut val = ::core::default::Default::default(); ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; self.kind = ::core::option::Option::Some( - value::KindOneof::StructValue( + buffa_::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new(val), ), ); @@ -708,7 +556,7 @@ impl ::buffa::Message for Value { }); } if let ::core::option::Option::Some( - value::KindOneof::ListValue(ref mut existing), + buffa_::oneof::value::Kind::ListValue(ref mut existing), ) = self.kind { ::buffa::Message::merge_length_delimited( @@ -720,7 +568,9 @@ impl ::buffa::Message for Value { let mut val = ::core::default::Default::default(); ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; self.kind = ::core::option::Option::Some( - value::KindOneof::ListValue(::buffa::alloc::boxed::Box::new(val)), + buffa_::oneof::value::Kind::ListValue( + ::buffa::alloc::boxed::Box::new(val), + ), ); } } @@ -758,7 +608,7 @@ impl ::buffa::text::TextFormat for Value { use ::buffa::Enumeration as _; if let ::core::option::Option::Some(ref __v) = self.kind { match __v { - value::KindOneof::NullValue(__v) => { + buffa_::oneof::value::Kind::NullValue(__v) => { enc.write_field_name("null_value")?; match __v { ::buffa::EnumValue::Known(__e) => { @@ -767,23 +617,23 @@ impl ::buffa::text::TextFormat for Value { ::buffa::EnumValue::Unknown(__n) => enc.write_enum_number(*__n)?, } } - value::KindOneof::NumberValue(__v) => { + buffa_::oneof::value::Kind::NumberValue(__v) => { enc.write_field_name("number_value")?; enc.write_f64(*__v)?; } - value::KindOneof::StringValue(__v) => { + buffa_::oneof::value::Kind::StringValue(__v) => { enc.write_field_name("string_value")?; enc.write_string(__v)?; } - value::KindOneof::BoolValue(__v) => { + buffa_::oneof::value::Kind::BoolValue(__v) => { enc.write_field_name("bool_value")?; enc.write_bool(*__v)?; } - value::KindOneof::StructValue(__v) => { + buffa_::oneof::value::Kind::StructValue(__v) => { enc.write_field_name("struct_value")?; enc.write_message(&**__v)?; } - value::KindOneof::ListValue(__v) => { + buffa_::oneof::value::Kind::ListValue(__v) => { enc.write_field_name("list_value")?; enc.write_message(&**__v)?; } @@ -802,7 +652,7 @@ impl ::buffa::text::TextFormat for Value { match __name { "null_value" => { self.kind = ::core::option::Option::Some( - value::KindOneof::NullValue( + buffa_::oneof::value::Kind::NullValue( dec .read_enum_by_name::() .map(::buffa::EnumValue::from)?, @@ -811,22 +661,24 @@ impl ::buffa::text::TextFormat for Value { } "number_value" => { self.kind = ::core::option::Option::Some( - value::KindOneof::NumberValue(dec.read_f64()?), + buffa_::oneof::value::Kind::NumberValue(dec.read_f64()?), ); } "string_value" => { self.kind = ::core::option::Option::Some( - value::KindOneof::StringValue(dec.read_string()?.into_owned()), + buffa_::oneof::value::Kind::StringValue( + dec.read_string()?.into_owned(), + ), ); } "bool_value" => { self.kind = ::core::option::Option::Some( - value::KindOneof::BoolValue(dec.read_bool()?), + buffa_::oneof::value::Kind::BoolValue(dec.read_bool()?), ); } "struct_value" => { if let ::core::option::Option::Some( - value::KindOneof::StructValue(ref mut __existing), + buffa_::oneof::value::Kind::StructValue(ref mut __existing), ) = self.kind { dec.merge_message(&mut **__existing)?; @@ -834,7 +686,7 @@ impl ::buffa::text::TextFormat for Value { let mut __m = ::core::default::Default::default(); dec.merge_message(&mut __m)?; self.kind = ::core::option::Option::Some( - value::KindOneof::StructValue( + buffa_::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new(__m), ), ); @@ -842,7 +694,7 @@ impl ::buffa::text::TextFormat for Value { } "list_value" => { if let ::core::option::Option::Some( - value::KindOneof::ListValue(ref mut __existing), + buffa_::oneof::value::Kind::ListValue(ref mut __existing), ) = self.kind { dec.merge_message(&mut **__existing)?; @@ -850,7 +702,7 @@ impl ::buffa::text::TextFormat for Value { let mut __m = ::core::default::Default::default(); dec.merge_message(&mut __m)?; self.kind = ::core::option::Option::Some( - value::KindOneof::ListValue( + buffa_::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new(__m), ), ); @@ -868,278 +720,6 @@ pub const __VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa::type text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// `Value` represents a dynamically typed value which can be either -/// null, a number, a string, a boolean, a recursive struct value, or a -/// list of values. A producer of value is expected to set one of these -/// variants. Absence of any variant indicates an error. -/// -/// The JSON representation for `Value` is JSON value. -#[derive(Clone, Debug, Default)] -pub struct ValueView<'a> { - pub kind: ::core::option::Option>, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.kind = Some( - value::KindOneofView::NullValue( - ::buffa::EnumValue::from( - ::buffa::types::decode_int32(&mut cur)?, - ), - ), - ); - } - 2u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Fixed64 { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 2u32, - expected: 1u8, - actual: tag.wire_type() as u8, - }); - } - view.kind = Some( - value::KindOneofView::NumberValue( - ::buffa::types::decode_double(&mut cur)?, - ), - ); - } - 3u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 3u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.kind = Some( - value::KindOneofView::StringValue( - ::buffa::types::borrow_str(&mut cur)?, - ), - ); - } - 4u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 4u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.kind = Some( - value::KindOneofView::BoolValue( - ::buffa::types::decode_bool(&mut cur)?, - ), - ); - } - 5u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 5u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_bytes(&mut cur)?; - if let Some(value::KindOneofView::StructValue(ref mut existing)) = view - .kind - { - existing._merge_into_view(sub, depth - 1)?; - } else { - view.kind = Some( - value::KindOneofView::StructValue( - ::buffa::alloc::boxed::Box::new( - StructView::_decode_depth(sub, depth - 1)?, - ), - ), - ); - } - } - 6u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 6u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_bytes(&mut cur)?; - if let Some(value::KindOneofView::ListValue(ref mut existing)) = view - .kind - { - existing._merge_into_view(sub, depth - 1)?; - } else { - view.kind = Some( - value::KindOneofView::ListValue( - ::buffa::alloc::boxed::Box::new( - ListValueView::_decode_depth(sub, depth - 1)?, - ), - ), - ); - } - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for ValueView<'a> { - type Owned = Value; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Value { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Value { - kind: self - .kind - .as_ref() - .map(|v| match v { - value::KindOneofView::NullValue(v) => value::KindOneof::NullValue(*v), - value::KindOneofView::NumberValue(v) => { - value::KindOneof::NumberValue(*v) - } - value::KindOneofView::StringValue(v) => { - value::KindOneof::StringValue(v.to_string()) - } - value::KindOneofView::BoolValue(v) => value::KindOneof::BoolValue(*v), - value::KindOneofView::StructValue(v) => { - value::KindOneof::StructValue( - ::buffa::alloc::boxed::Box::new(v.to_owned_message()), - ) - } - value::KindOneofView::ListValue(v) => { - value::KindOneof::ListValue( - ::buffa::alloc::boxed::Box::new(v.to_owned_message()), - ) - } - }), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for ValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for ValueView<'a> { - type Static = ValueView<'static>; -} -pub mod value { - #[allow(unused_imports)] - use super::*; - /// The kind of value. - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))] - pub enum KindOneof { - NullValue(::buffa::EnumValue), - NumberValue(f64), - StringValue(::buffa::alloc::string::String), - BoolValue(bool), - StructValue(::buffa::alloc::boxed::Box), - ListValue(::buffa::alloc::boxed::Box), - } - impl ::buffa::Oneof for KindOneof {} - impl From for KindOneof { - fn from(v: super::Struct) -> Self { - Self::StructValue(::buffa::alloc::boxed::Box::new(v)) - } - } - impl From for ::core::option::Option { - fn from(v: super::Struct) -> Self { - Self::Some(KindOneof::from(v)) - } - } - impl From for KindOneof { - fn from(v: super::ListValue) -> Self { - Self::ListValue(::buffa::alloc::boxed::Box::new(v)) - } - } - impl From for ::core::option::Option { - fn from(v: super::ListValue) -> Self { - Self::Some(KindOneof::from(v)) - } - } - #[derive(Clone, Debug)] - pub enum KindOneofView<'a> { - NullValue(::buffa::EnumValue), - NumberValue(f64), - StringValue(&'a str), - BoolValue(bool), - StructValue(::buffa::alloc::boxed::Box>), - ListValue(::buffa::alloc::boxed::Box>), - } -} /// `ListValue` is a wrapper around a repeated field of values. /// /// The JSON representation for `ListValue` is JSON array. @@ -1299,112 +879,3 @@ pub const __LIST_VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa: text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// `ListValue` is a wrapper around a repeated field of values. -/// -/// The JSON representation for `ListValue` is JSON array. -#[derive(Clone, Debug, Default)] -pub struct ListValueView<'a> { - /// Repeated field of dynamically typed values. - /// - /// Field 1: `values` - pub values: ::buffa::RepeatedView<'a, ValueView<'a>>, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> ListValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_bytes(&mut cur)?; - view.values.push(ValueView::_decode_depth(sub, depth - 1)?); - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for ListValueView<'a> { - type Owned = ListValue; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> ListValue { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - ListValue { - values: self.values.iter().map(|v| v.to_owned_message()).collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for ListValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for ListValueView<'a> { - type Static = ListValueView<'static>; -} diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs b/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs new file mode 100644 index 0000000..94add37 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs b/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs new file mode 100644 index 0000000..94add37 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs new file mode 100644 index 0000000..ae81a31 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs @@ -0,0 +1,226 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + +/// A Timestamp represents a point in time independent of any time zone or local +/// calendar, encoded as a count of seconds and fractions of seconds at +/// nanosecond resolution. The count is relative to an epoch at UTC midnight on +/// January 1, 1970, in the proleptic Gregorian calendar which extends the +/// Gregorian calendar backwards to year one. +/// +/// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +/// second table is needed for interpretation, using a \[24-hour linear +/// smear\](). +/// +/// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +/// restricting to that range, we ensure that we can convert to and from \[RFC +/// 3339\]() date strings. +/// +/// # Examples +/// +/// Example 1: Compute Timestamp from POSIX `time()`. +/// +/// ```text +/// Timestamp timestamp; +/// timestamp.set_seconds(time(NULL)); +/// timestamp.set_nanos(0); +/// ``` +/// +/// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +/// +/// ```text +/// struct timeval tv; +/// gettimeofday(&tv, NULL); +/// +/// Timestamp timestamp; +/// timestamp.set_seconds(tv.tv_sec); +/// timestamp.set_nanos(tv.tv_usec * 1000); +/// ``` +/// +/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +/// +/// ```text +/// FILETIME ft; +/// GetSystemTimeAsFileTime(&ft); +/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +/// +/// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +/// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +/// Timestamp timestamp; +/// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +/// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +/// ``` +/// +/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +/// +/// ```text +/// long millis = System.currentTimeMillis(); +/// +/// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +/// .setNanos((int) ((millis % 1000) * 1000000)).build(); +/// ``` +/// +/// Example 5: Compute Timestamp from Java `Instant.now()`. +/// +/// ```text +/// Instant now = Instant.now(); +/// +/// Timestamp timestamp = +/// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) +/// .setNanos(now.getNano()).build(); +/// ``` +/// +/// Example 6: Compute Timestamp from current time in Python. +/// +/// ```text +/// timestamp = Timestamp() +/// timestamp.GetCurrentTime() +/// ``` +/// +/// # JSON Mapping +/// +/// In JSON format, the Timestamp type is encoded as a string in the +/// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +/// format is "{year}-{month}-{day}T{hour}:{min}:{sec}\[.{frac_sec}\]Z" +/// where {year} is always expressed using four digits while {month}, {day}, +/// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +/// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +/// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +/// is required. A proto3 JSON serializer should always use UTC (as indicated by +/// "Z") when printing the Timestamp type and a proto3 JSON parser should be +/// able to accept both UTC and other timezones (as indicated by an offset). +/// +/// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +/// 01:30 UTC on January 15, 2017. +/// +/// In JavaScript, one can convert a Date object to this format using the +/// standard +/// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) +/// method. In Python, a standard `datetime.datetime` object can be converted +/// to this format using +/// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +/// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +/// the Joda Time's \[`ISODateTimeFormat.dateTime()`\]( +/// ) +/// ) to obtain a formatter capable of generating timestamps in this format. +#[derive(Clone, Debug, Default)] +pub struct TimestampView<'a> { + /// Represents seconds of UTC time since Unix epoch + /// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + /// 9999-12-31T23:59:59Z inclusive. + /// + /// Field 1: `seconds` + pub seconds: i64, + /// Non-negative fractions of a second at nanosecond resolution. Negative + /// second values with fractions must still have non-negative nanos values + /// that count forward in time. Must be from 0 to 999,999,999 + /// inclusive. + /// + /// Field 2: `nanos` + pub nanos: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> TimestampView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.seconds = ::buffa::types::decode_int64(&mut cur)?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.nanos = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for TimestampView<'a> { + type Owned = super::super::Timestamp; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Timestamp { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Timestamp { + seconds: self.seconds, + nanos: self.nanos, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for TimestampView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for TimestampView<'a> { + type Static = TimestampView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs new file mode 100644 index 0000000..94add37 --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + diff --git a/buffa-types/src/generated/google.protobuf.timestamp.rs b/buffa-types/src/generated/google.protobuf.timestamp.rs index 34cf43c..141e5b9 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.rs @@ -276,226 +276,3 @@ pub const __TIMESTAMP_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa:: text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// A Timestamp represents a point in time independent of any time zone or local -/// calendar, encoded as a count of seconds and fractions of seconds at -/// nanosecond resolution. The count is relative to an epoch at UTC midnight on -/// January 1, 1970, in the proleptic Gregorian calendar which extends the -/// Gregorian calendar backwards to year one. -/// -/// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap -/// second table is needed for interpretation, using a \[24-hour linear -/// smear\](). -/// -/// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By -/// restricting to that range, we ensure that we can convert to and from \[RFC -/// 3339\]() date strings. -/// -/// # Examples -/// -/// Example 1: Compute Timestamp from POSIX `time()`. -/// -/// ```text -/// Timestamp timestamp; -/// timestamp.set_seconds(time(NULL)); -/// timestamp.set_nanos(0); -/// ``` -/// -/// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -/// -/// ```text -/// struct timeval tv; -/// gettimeofday(&tv, NULL); -/// -/// Timestamp timestamp; -/// timestamp.set_seconds(tv.tv_sec); -/// timestamp.set_nanos(tv.tv_usec * 1000); -/// ``` -/// -/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -/// -/// ```text -/// FILETIME ft; -/// GetSystemTimeAsFileTime(&ft); -/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -/// -/// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -/// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -/// Timestamp timestamp; -/// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -/// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -/// ``` -/// -/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -/// -/// ```text -/// long millis = System.currentTimeMillis(); -/// -/// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -/// .setNanos((int) ((millis % 1000) * 1000000)).build(); -/// ``` -/// -/// Example 5: Compute Timestamp from Java `Instant.now()`. -/// -/// ```text -/// Instant now = Instant.now(); -/// -/// Timestamp timestamp = -/// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) -/// .setNanos(now.getNano()).build(); -/// ``` -/// -/// Example 6: Compute Timestamp from current time in Python. -/// -/// ```text -/// timestamp = Timestamp() -/// timestamp.GetCurrentTime() -/// ``` -/// -/// # JSON Mapping -/// -/// In JSON format, the Timestamp type is encoded as a string in the -/// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -/// format is "{year}-{month}-{day}T{hour}:{min}:{sec}\[.{frac_sec}\]Z" -/// where {year} is always expressed using four digits while {month}, {day}, -/// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -/// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -/// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -/// is required. A proto3 JSON serializer should always use UTC (as indicated by -/// "Z") when printing the Timestamp type and a proto3 JSON parser should be -/// able to accept both UTC and other timezones (as indicated by an offset). -/// -/// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -/// 01:30 UTC on January 15, 2017. -/// -/// In JavaScript, one can convert a Date object to this format using the -/// standard -/// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) -/// method. In Python, a standard `datetime.datetime` object can be converted -/// to this format using -/// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with -/// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use -/// the Joda Time's \[`ISODateTimeFormat.dateTime()`\]( -/// ) -/// ) to obtain a formatter capable of generating timestamps in this format. -#[derive(Clone, Debug, Default)] -pub struct TimestampView<'a> { - /// Represents seconds of UTC time since Unix epoch - /// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - /// 9999-12-31T23:59:59Z inclusive. - /// - /// Field 1: `seconds` - pub seconds: i64, - /// Non-negative fractions of a second at nanosecond resolution. Negative - /// second values with fractions must still have non-negative nanos values - /// that count forward in time. Must be from 0 to 999,999,999 - /// inclusive. - /// - /// Field 2: `nanos` - pub nanos: i32, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> TimestampView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.seconds = ::buffa::types::decode_int64(&mut cur)?; - } - 2u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 2u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.nanos = ::buffa::types::decode_int32(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for TimestampView<'a> { - type Owned = Timestamp; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Timestamp { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Timestamp { - seconds: self.seconds, - nanos: self.nanos, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for TimestampView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for TimestampView<'a> { - type Static = TimestampView<'static>; -} diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs b/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs new file mode 100644 index 0000000..e8699ea --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/wrappers.proto + diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs b/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs new file mode 100644 index 0000000..e8699ea --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/wrappers.proto + diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs new file mode 100644 index 0000000..fe2334f --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs @@ -0,0 +1,948 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/wrappers.proto + +/// Wrapper message for `double`. +/// +/// The JSON representation for `DoubleValue` is JSON number. +#[derive(Clone, Debug, Default)] +pub struct DoubleValueView<'a> { + /// The double value. + /// + /// Field 1: `value` + pub value: f64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> DoubleValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Fixed64 { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 1u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_double(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for DoubleValueView<'a> { + type Owned = super::super::DoubleValue; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::DoubleValue { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::DoubleValue { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for DoubleValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for DoubleValueView<'a> { + type Static = DoubleValueView<'static>; +} +/// Wrapper message for `float`. +/// +/// The JSON representation for `FloatValue` is JSON number. +#[derive(Clone, Debug, Default)] +pub struct FloatValueView<'a> { + /// The float value. + /// + /// Field 1: `value` + pub value: f32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> FloatValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Fixed32 { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 5u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_float(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for FloatValueView<'a> { + type Owned = super::super::FloatValue; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::FloatValue { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::FloatValue { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for FloatValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for FloatValueView<'a> { + type Static = FloatValueView<'static>; +} +/// Wrapper message for `int64`. +/// +/// The JSON representation for `Int64Value` is JSON string. +#[derive(Clone, Debug, Default)] +pub struct Int64ValueView<'a> { + /// The int64 value. + /// + /// Field 1: `value` + pub value: i64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> Int64ValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_int64(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for Int64ValueView<'a> { + type Owned = super::super::Int64Value; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Int64Value { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Int64Value { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for Int64ValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for Int64ValueView<'a> { + type Static = Int64ValueView<'static>; +} +/// Wrapper message for `uint64`. +/// +/// The JSON representation for `UInt64Value` is JSON string. +#[derive(Clone, Debug, Default)] +pub struct UInt64ValueView<'a> { + /// The uint64 value. + /// + /// Field 1: `value` + pub value: u64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> UInt64ValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_uint64(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for UInt64ValueView<'a> { + type Owned = super::super::UInt64Value; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::UInt64Value { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::UInt64Value { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for UInt64ValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for UInt64ValueView<'a> { + type Static = UInt64ValueView<'static>; +} +/// Wrapper message for `int32`. +/// +/// The JSON representation for `Int32Value` is JSON number. +#[derive(Clone, Debug, Default)] +pub struct Int32ValueView<'a> { + /// The int32 value. + /// + /// Field 1: `value` + pub value: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> Int32ValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for Int32ValueView<'a> { + type Owned = super::super::Int32Value; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::Int32Value { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::Int32Value { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for Int32ValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for Int32ValueView<'a> { + type Static = Int32ValueView<'static>; +} +/// Wrapper message for `uint32`. +/// +/// The JSON representation for `UInt32Value` is JSON number. +#[derive(Clone, Debug, Default)] +pub struct UInt32ValueView<'a> { + /// The uint32 value. + /// + /// Field 1: `value` + pub value: u32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> UInt32ValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_uint32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for UInt32ValueView<'a> { + type Owned = super::super::UInt32Value; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::UInt32Value { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::UInt32Value { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for UInt32ValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for UInt32ValueView<'a> { + type Static = UInt32ValueView<'static>; +} +/// Wrapper message for `bool`. +/// +/// The JSON representation for `BoolValue` is JSON `true` and `false`. +#[derive(Clone, Debug, Default)] +pub struct BoolValueView<'a> { + /// The bool value. + /// + /// Field 1: `value` + pub value: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> BoolValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for BoolValueView<'a> { + type Owned = super::super::BoolValue; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::BoolValue { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::BoolValue { + value: self.value, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for BoolValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for BoolValueView<'a> { + type Static = BoolValueView<'static>; +} +/// Wrapper message for `string`. +/// +/// The JSON representation for `StringValue` is JSON string. +#[derive(Clone, Debug, Default)] +pub struct StringValueView<'a> { + /// The string value. + /// + /// Field 1: `value` + pub value: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> StringValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for StringValueView<'a> { + type Owned = super::super::StringValue; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::StringValue { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::StringValue { + value: self.value.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for StringValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for StringValueView<'a> { + type Static = StringValueView<'static>; +} +/// Wrapper message for `bytes`. +/// +/// The JSON representation for `BytesValue` is JSON string. +#[derive(Clone, Debug, Default)] +pub struct BytesValueView<'a> { + /// The bytes value. + /// + /// Field 1: `value` + pub value: &'a [u8], + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> BytesValueView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.value = ::buffa::types::borrow_bytes(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for BytesValueView<'a> { + type Owned = super::super::BytesValue; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + /// Convert this view to the owned message type. + #[allow(clippy::redundant_closure, clippy::useless_conversion)] + fn to_owned_message(&self) -> super::super::BytesValue { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + super::super::BytesValue { + value: (self.value).to_vec(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +unsafe impl ::buffa::DefaultViewInstance for BytesValueView<'static> { + fn default_view_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +unsafe impl<'a> ::buffa::HasDefaultViewInstance for BytesValueView<'a> { + type Static = BytesValueView<'static>; +} diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs new file mode 100644 index 0000000..e8699ea --- /dev/null +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: google/protobuf/wrappers.proto + diff --git a/buffa-types/src/generated/google.protobuf.wrappers.rs b/buffa-types/src/generated/google.protobuf.wrappers.rs index 4667c4a..fb6f578 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.rs @@ -142,111 +142,6 @@ pub const __DOUBLE_VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buff text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `double`. -/// -/// The JSON representation for `DoubleValue` is JSON number. -#[derive(Clone, Debug, Default)] -pub struct DoubleValueView<'a> { - /// The double value. - /// - /// Field 1: `value` - pub value: f64, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> DoubleValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Fixed64 { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 1u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_double(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for DoubleValueView<'a> { - type Owned = DoubleValue; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> DoubleValue { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - DoubleValue { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for DoubleValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for DoubleValueView<'a> { - type Static = DoubleValueView<'static>; -} /// Wrapper message for `float`. /// /// The JSON representation for `FloatValue` is JSON number. @@ -388,111 +283,6 @@ pub const __FLOAT_VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `float`. -/// -/// The JSON representation for `FloatValue` is JSON number. -#[derive(Clone, Debug, Default)] -pub struct FloatValueView<'a> { - /// The float value. - /// - /// Field 1: `value` - pub value: f32, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> FloatValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Fixed32 { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 5u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_float(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for FloatValueView<'a> { - type Owned = FloatValue; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> FloatValue { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - FloatValue { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for FloatValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for FloatValueView<'a> { - type Static = FloatValueView<'static>; -} /// Wrapper message for `int64`. /// /// The JSON representation for `Int64Value` is JSON string. @@ -634,111 +424,6 @@ pub const __INT64VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa: text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `int64`. -/// -/// The JSON representation for `Int64Value` is JSON string. -#[derive(Clone, Debug, Default)] -pub struct Int64ValueView<'a> { - /// The int64 value. - /// - /// Field 1: `value` - pub value: i64, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> Int64ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_int64(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for Int64ValueView<'a> { - type Owned = Int64Value; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Int64Value { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Int64Value { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for Int64ValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for Int64ValueView<'a> { - type Static = Int64ValueView<'static>; -} /// Wrapper message for `uint64`. /// /// The JSON representation for `UInt64Value` is JSON string. @@ -880,111 +565,6 @@ pub const __U_INT64VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buff text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `uint64`. -/// -/// The JSON representation for `UInt64Value` is JSON string. -#[derive(Clone, Debug, Default)] -pub struct UInt64ValueView<'a> { - /// The uint64 value. - /// - /// Field 1: `value` - pub value: u64, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> UInt64ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_uint64(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for UInt64ValueView<'a> { - type Owned = UInt64Value; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> UInt64Value { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - UInt64Value { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for UInt64ValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for UInt64ValueView<'a> { - type Static = UInt64ValueView<'static>; -} /// Wrapper message for `int32`. /// /// The JSON representation for `Int32Value` is JSON number. @@ -1126,111 +706,6 @@ pub const __INT32VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa: text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `int32`. -/// -/// The JSON representation for `Int32Value` is JSON number. -#[derive(Clone, Debug, Default)] -pub struct Int32ValueView<'a> { - /// The int32 value. - /// - /// Field 1: `value` - pub value: i32, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> Int32ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_int32(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for Int32ValueView<'a> { - type Owned = Int32Value; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> Int32Value { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - Int32Value { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for Int32ValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for Int32ValueView<'a> { - type Static = Int32ValueView<'static>; -} /// Wrapper message for `uint32`. /// /// The JSON representation for `UInt32Value` is JSON number. @@ -1372,111 +847,6 @@ pub const __U_INT32VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buff text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `uint32`. -/// -/// The JSON representation for `UInt32Value` is JSON number. -#[derive(Clone, Debug, Default)] -pub struct UInt32ValueView<'a> { - /// The uint32 value. - /// - /// Field 1: `value` - pub value: u32, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> UInt32ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_uint32(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for UInt32ValueView<'a> { - type Owned = UInt32Value; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> UInt32Value { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - UInt32Value { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for UInt32ValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for UInt32ValueView<'a> { - type Static = UInt32ValueView<'static>; -} /// Wrapper message for `bool`. /// /// The JSON representation for `BoolValue` is JSON `true` and `false`. @@ -1618,111 +988,6 @@ pub const __BOOL_VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa: text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `bool`. -/// -/// The JSON representation for `BoolValue` is JSON `true` and `false`. -#[derive(Clone, Debug, Default)] -pub struct BoolValueView<'a> { - /// The bool value. - /// - /// Field 1: `value` - pub value: bool, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> BoolValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::decode_bool(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for BoolValueView<'a> { - type Owned = BoolValue; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> BoolValue { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - BoolValue { - value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for BoolValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for BoolValueView<'a> { - type Static = BoolValueView<'static>; -} /// Wrapper message for `string`. /// /// The JSON representation for `StringValue` is JSON string. @@ -1867,111 +1132,6 @@ pub const __STRING_VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buff text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `string`. -/// -/// The JSON representation for `StringValue` is JSON string. -#[derive(Clone, Debug, Default)] -pub struct StringValueView<'a> { - /// The string value. - /// - /// Field 1: `value` - pub value: &'a str, - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> StringValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::borrow_str(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for StringValueView<'a> { - type Owned = StringValue; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> StringValue { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - StringValue { - value: self.value.to_string(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for StringValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for StringValueView<'a> { - type Static = StringValueView<'static>; -} /// Wrapper message for `bytes`. /// /// The JSON representation for `BytesValue` is JSON string. @@ -2116,108 +1276,3 @@ pub const __BYTES_VALUE_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa text_encode: ::buffa::type_registry::any_encode_text::, text_merge: ::buffa::type_registry::any_merge_text::, }; -/// Wrapper message for `bytes`. -/// -/// The JSON representation for `BytesValue` is JSON string. -#[derive(Clone, Debug, Default)] -pub struct BytesValueView<'a> { - /// The bytes value. - /// - /// Field 1: `value` - pub value: &'a [u8], - pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, -} -impl<'a> BytesValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. - /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. - /// - /// **Not part of the public API.** Named with a leading underscore to - /// signal that it is for generated-code use only. - #[doc(hidden)] - pub fn _decode_depth( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, depth)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.value = ::buffa::types::borrow_bytes(&mut cur)?; - } - _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); - } - } - } - ::core::result::Result::Ok(()) - } -} -impl<'a> ::buffa::MessageView<'a> for BytesValueView<'a> { - type Owned = BytesValue; - fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) - } - fn decode_view_with_limit( - buf: &'a [u8], - depth: u32, - ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) - } - /// Convert this view to the owned message type. - #[allow(clippy::redundant_closure, clippy::useless_conversion)] - fn to_owned_message(&self) -> BytesValue { - #[allow(unused_imports)] - use ::buffa::alloc::string::ToString as _; - BytesValue { - value: (self.value).to_vec(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), - ..::core::default::Default::default() - } - } -} -unsafe impl ::buffa::DefaultViewInstance for BytesValueView<'static> { - fn default_view_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} -unsafe impl<'a> ::buffa::HasDefaultViewInstance for BytesValueView<'a> { - type Static = BytesValueView<'static>; -} diff --git a/buffa-types/src/lib.rs b/buffa-types/src/lib.rs index 65283c5..3b63f04 100644 --- a/buffa-types/src/lib.rs +++ b/buffa-types/src/lib.rs @@ -68,13 +68,7 @@ mod wrapper_ext; )] pub mod google { pub mod protobuf { - include!("generated/google.protobuf.any.rs"); - include!("generated/google.protobuf.duration.rs"); - include!("generated/google.protobuf.empty.rs"); - include!("generated/google.protobuf.field_mask.rs"); - include!("generated/google.protobuf.struct.rs"); - include!("generated/google.protobuf.timestamp.rs"); - include!("generated/google.protobuf.wrappers.rs"); + include!("generated/google.protobuf.mod.rs"); } } diff --git a/buffa-types/src/timestamp_ext.rs b/buffa-types/src/timestamp_ext.rs index 38e42ae..653dfb0 100644 --- a/buffa-types/src/timestamp_ext.rs +++ b/buffa-types/src/timestamp_ext.rs @@ -540,7 +540,8 @@ mod tests { #[test] fn timestamp_view_round_trip() { - use crate::google::protobuf::{Timestamp, TimestampView}; + use crate::google::protobuf::buffa_::view::TimestampView; + use crate::google::protobuf::Timestamp; use buffa::{Message, MessageView}; let ts = Timestamp { diff --git a/buffa-types/src/value_ext.rs b/buffa-types/src/value_ext.rs index ef1cb71..697da39 100644 --- a/buffa-types/src/value_ext.rs +++ b/buffa-types/src/value_ext.rs @@ -5,7 +5,8 @@ use alloc::boxed::Box; use alloc::string::{String, ToString}; -use crate::google::protobuf::{value::KindOneof, ListValue, NullValue, Struct, Value}; +use crate::google::protobuf::buffa_::oneof::value::Kind as KindOneof; +use crate::google::protobuf::{ListValue, NullValue, Struct, Value}; impl Value { /// Construct a [`Value`] that represents a protobuf `null`. diff --git a/buffa-types/tests/wkt_roundtrip.rs b/buffa-types/tests/wkt_roundtrip.rs index 055f891..3b1a792 100644 --- a/buffa-types/tests/wkt_roundtrip.rs +++ b/buffa-types/tests/wkt_roundtrip.rs @@ -3,6 +3,7 @@ use buffa::{Message, MessageView}; use buffa_types::google::protobuf as wkt; +use buffa_types::google::protobuf::buffa_::view as wkt_view; fn encode_decode(msg: &T) -> T { let bytes = msg.encode_to_vec(); @@ -233,7 +234,7 @@ fn timestamp_view_roundtrip() { ..Default::default() }; let bytes = ts.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), ts); + assert_eq!(view_roundtrip::(&bytes), ts); } #[test] @@ -244,14 +245,14 @@ fn duration_view_roundtrip() { ..Default::default() }; let bytes = d.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), d); + assert_eq!(view_roundtrip::(&bytes), d); } #[test] fn empty_view_roundtrip() { let e = wkt::Empty::default(); let bytes = e.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), e); + assert_eq!(view_roundtrip::(&bytes), e); } #[test] @@ -262,7 +263,7 @@ fn any_view_roundtrip() { ..Default::default() }; let bytes = any.encode_to_vec(); - let owned = view_roundtrip::(&bytes); + let owned = view_roundtrip::(&bytes); assert_eq!(owned.type_url, any.type_url); assert_eq!(owned.value, any.value); } @@ -274,7 +275,7 @@ fn field_mask_view_roundtrip() { ..Default::default() }; let bytes = fm.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), fm); + assert_eq!(view_roundtrip::(&bytes), fm); } #[test] @@ -284,7 +285,7 @@ fn string_value_view_roundtrip() { ..Default::default() }; let bytes = w.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), w); + assert_eq!(view_roundtrip::(&bytes), w); } #[test] @@ -294,7 +295,7 @@ fn bytes_value_view_roundtrip() { ..Default::default() }; let bytes = w.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), w); + assert_eq!(view_roundtrip::(&bytes), w); } #[test] @@ -304,5 +305,5 @@ fn int64_value_view_roundtrip() { ..Default::default() }; let bytes = w.encode_to_vec(); - assert_eq!(view_roundtrip::(&bytes), w); + assert_eq!(view_roundtrip::(&bytes), w); } diff --git a/buffa/src/lib.rs b/buffa/src/lib.rs index ab0ecd6..0287cc2 100644 --- a/buffa/src/lib.rs +++ b/buffa/src/lib.rs @@ -118,6 +118,43 @@ pub extern crate alloc; #[doc(hidden)] pub use ::bytes; +/// Include the generated stitcher for a proto **package** from `OUT_DIR`. +/// +/// Codegen emits one `.mod.rs` per package which `include!`s the +/// per-proto content files and authors the `buffa_::{view, oneof, ext}` +/// ancillary tree, so a single macro call brings in everything. +/// +/// ```ignore +/// pub mod my_pkg { +/// buffa::include_proto!("my.pkg"); +/// } +/// ``` +/// +/// For the unnamed package, pass `"_"`. For checked-in generated code +/// (no `OUT_DIR`), use [`include_proto_relative!`]. +#[macro_export] +macro_rules! include_proto { + ($pkg:literal) => { + include!(concat!(env!("OUT_DIR"), "/", $pkg, ".mod.rs")); + }; +} + +/// Like [`include_proto!`] but takes a relative directory instead of +/// reading `OUT_DIR` — for crates that check generated code into the +/// source tree (e.g. `buffa-types`, `buffa-descriptor`). +/// +/// ```ignore +/// pub mod protobuf { +/// buffa::include_proto_relative!("generated", "google.protobuf"); +/// } +/// ``` +#[macro_export] +macro_rules! include_proto_relative { + ($dir:literal, $pkg:literal) => { + include!(concat!($dir, "/", $pkg, ".mod.rs")); + }; +} + #[cfg(feature = "json")] pub mod any_registry; mod cached_size; diff --git a/conformance/Cargo.lock b/conformance/Cargo.lock index 6d56441..bf034d1 100644 --- a/conformance/Cargo.lock +++ b/conformance/Cargo.lock @@ -22,7 +22,7 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "buffa" -version = "0.2.0" +version = "0.3.0" dependencies = [ "base64", "bytes", @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "buffa-build" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", "buffa-codegen", @@ -44,7 +44,7 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", "buffa-descriptor", @@ -57,16 +57,17 @@ dependencies = [ [[package]] name = "buffa-descriptor" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", ] [[package]] name = "buffa-types" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", + "bytes", "serde", "serde_json", "thiserror", diff --git a/conformance/src/main.rs b/conformance/src/main.rs index 0c2a810..6e50505 100644 --- a/conformance/src/main.rs +++ b/conformance/src/main.rs @@ -41,18 +41,12 @@ pub mod protobuf_test_messages { pub mod proto3 { pub use super::google; - include!(concat!( - env!("OUT_DIR"), - "/google.protobuf.test_messages_proto3.rs" - )); + buffa::include_proto!("protobuf_test_messages.proto3"); } pub mod proto2 { pub use super::google; - include!(concat!( - env!("OUT_DIR"), - "/google.protobuf.test_messages_proto2.rs" - )); + buffa::include_proto!("protobuf_test_messages.proto2"); } } @@ -69,27 +63,18 @@ pub mod protobuf_test_messages_editions { pub mod proto3 { pub use super::google; - include!(concat!( - env!("OUT_DIR"), - "/editions.golden.test_messages_proto3_editions.rs" - )); + buffa::include_proto!("protobuf_test_messages.editions.proto3"); } pub mod proto2 { pub use super::google; - include!(concat!( - env!("OUT_DIR"), - "/editions.golden.test_messages_proto2_editions.rs" - )); + buffa::include_proto!("protobuf_test_messages.editions.proto2"); } // Pure edition 2023: file-level DELIMITED message encoding. Binary-only // — no JSON generation. The package is `protobuf_test_messages.editions` // so the module path here matches where the suite expects to find it. - include!(concat!( - env!("OUT_DIR"), - "/conformance.test_protos.test_messages_edition2023.rs" - )); + buffa::include_proto!("protobuf_test_messages.editions"); } #[cfg(has_editions_protos)] @@ -130,15 +115,15 @@ fn setup_type_registry() { // (JSON + text) + extension entries. `test_messages_proto3.proto` // has no extensions, so its register_types is Any-only; // `test_messages_proto2.proto` declares `extension_int32` at field 120. - proto3::register_types(&mut reg); - proto2::register_types(&mut reg); + proto3::buffa_::register_types(&mut reg); + proto2::buffa_::register_types(&mut reg); #[cfg(has_editions_protos)] { - editions_proto3::register_types(&mut reg); - editions_proto2::register_types(&mut reg); + editions_proto3::buffa_::register_types(&mut reg); + editions_proto2::buffa_::register_types(&mut reg); // Edition2023's `groupliketype` / `delimited_ext` extensions — // needed for the text `[pkg.ext] { ... }` bracket tests. - protobuf_test_messages_editions::register_types(&mut reg); + protobuf_test_messages_editions::buffa_::register_types(&mut reg); } set_type_registry(reg); @@ -344,21 +329,21 @@ fn process_via_view(req: &envelope::Request) -> envelope::Response { match req.message_type.as_str() { MSG_PROTO3 => roundtrip_proto3( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_proto3_binary, ), MSG_PROTO2 => roundtrip_proto2( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_proto2_binary, ), #[cfg(has_editions_protos)] MSG_EDITIONS_PROTO3 => roundtrip( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_binary, ), #[cfg(has_editions_protos)] MSG_EDITIONS_PROTO2 => roundtrip( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_binary, ), other => Response::Skipped(format!("message type '{other}' not in view dispatch")), diff --git a/examples/addressbook/Cargo.lock b/examples/addressbook/Cargo.lock index 2485965..7379a9f 100644 --- a/examples/addressbook/Cargo.lock +++ b/examples/addressbook/Cargo.lock @@ -60,6 +60,7 @@ name = "buffa-types" version = "0.3.0" dependencies = [ "buffa", + "bytes", "serde", "serde_json", "thiserror", diff --git a/examples/addressbook/src/main.rs b/examples/addressbook/src/main.rs index 12456e0..031c707 100644 --- a/examples/addressbook/src/main.rs +++ b/examples/addressbook/src/main.rs @@ -19,8 +19,9 @@ mod proto { } use buffa::{EnumValue, Message}; +use proto::buffa::examples::addressbook::v1::buffa_::oneof::person::Address as AddressOneof; use proto::buffa::examples::addressbook::v1::{ - person::{AddressOneof, PhoneNumber, PhoneType}, + person::{PhoneNumber, PhoneType}, AddressBook, Person, StructuredAddress, }; use std::io::{self, BufRead, Write}; diff --git a/examples/envelope/Cargo.lock b/examples/envelope/Cargo.lock index 9b54992..9e7cf05 100644 --- a/examples/envelope/Cargo.lock +++ b/examples/envelope/Cargo.lock @@ -22,7 +22,7 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "buffa" -version = "0.2.0" +version = "0.3.0" dependencies = [ "base64", "bytes", @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "buffa-build" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", "buffa-codegen", @@ -44,9 +44,10 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", + "buffa-descriptor", "prettyplease", "proc-macro2", "quote", @@ -54,6 +55,13 @@ dependencies = [ "thiserror", ] +[[package]] +name = "buffa-descriptor" +version = "0.3.0" +dependencies = [ + "buffa", +] + [[package]] name = "bytes" version = "1.11.1" diff --git a/examples/envelope/src/main.rs b/examples/envelope/src/main.rs index 5de5f43..d8e254f 100644 --- a/examples/envelope/src/main.rs +++ b/examples/envelope/src/main.rs @@ -7,9 +7,8 @@ mod proto { } use buffa::{ExtensionSet, Message}; -use proto::buffa::examples::envelope::{ - Envelope, TraceContext, PRIORITY, RETRY_COUNT, ROUTING_HOPS, TRACE, -}; +use proto::buffa::examples::envelope::buffa_::ext::{PRIORITY, RETRY_COUNT, ROUTING_HOPS, TRACE}; +use proto::buffa::examples::envelope::{Envelope, TraceContext}; fn main() { binary_roundtrip(); @@ -133,9 +132,10 @@ fn json_roundtrip() { // `__buffa_unknown_fields` and are silently dropped from JSON output. use buffa::type_registry::{set_type_registry, TypeRegistry}; let mut reg = TypeRegistry::new(); - // Codegen emits this per file. It registers extension JSON converters, - // extension text converters, and `Any` type entries — one call covers all. - proto::buffa::examples::envelope::register_types(&mut reg); + // Codegen emits this per package. It registers extension JSON + // converters, extension text converters, and `Any` type entries — one + // call covers all. + proto::buffa::examples::envelope::buffa_::register_types(&mut reg); set_type_registry(reg); let mut env = Envelope { diff --git a/examples/logging/Cargo.lock b/examples/logging/Cargo.lock index 252b0cf..b319be1 100644 --- a/examples/logging/Cargo.lock +++ b/examples/logging/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "buffa" -version = "0.2.0" +version = "0.3.0" dependencies = [ "bytes", "hashbrown", @@ -16,9 +16,10 @@ dependencies = [ [[package]] name = "buffa-types" -version = "0.2.0" +version = "0.3.0" dependencies = [ "buffa", + "bytes", "serde", "serde_json", "thiserror", diff --git a/examples/logging/src/gen/buffa.examples.context.v1.mod.rs b/examples/logging/src/gen/buffa.examples.context.v1.mod.rs new file mode 100644 index 0000000..3adba5c --- /dev/null +++ b/examples/logging/src/gen/buffa.examples.context.v1.mod.rs @@ -0,0 +1,15 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. + +include!("context.v1.context.rs"); +#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +pub mod buffa_ { + #[allow(unused_imports)] use super::*; + pub mod oneof { + #[allow(unused_imports)] use super::*; + include!("context.v1.context.__oneof.rs"); + } + pub mod ext { + #[allow(unused_imports)] use super::*; + include!("context.v1.context.__ext.rs"); + } +} diff --git a/examples/logging/src/gen/buffa.examples.log.v1.mod.rs b/examples/logging/src/gen/buffa.examples.log.v1.mod.rs new file mode 100644 index 0000000..a04cfb2 --- /dev/null +++ b/examples/logging/src/gen/buffa.examples.log.v1.mod.rs @@ -0,0 +1,15 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. + +include!("log.v1.log.rs"); +#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +pub mod buffa_ { + #[allow(unused_imports)] use super::*; + pub mod oneof { + #[allow(unused_imports)] use super::*; + include!("log.v1.log.__oneof.rs"); + } + pub mod ext { + #[allow(unused_imports)] use super::*; + include!("log.v1.log.__ext.rs"); + } +} diff --git a/examples/logging/src/gen/context.v1.context.__ext.rs b/examples/logging/src/gen/context.v1.context.__ext.rs new file mode 100644 index 0000000..a2d385a --- /dev/null +++ b/examples/logging/src/gen/context.v1.context.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: context/v1/context.proto + diff --git a/examples/logging/src/gen/context.v1.context.__oneof.rs b/examples/logging/src/gen/context.v1.context.__oneof.rs new file mode 100644 index 0000000..a2d385a --- /dev/null +++ b/examples/logging/src/gen/context.v1.context.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: context/v1/context.proto + diff --git a/examples/logging/src/gen/context.v1.context.__view.rs b/examples/logging/src/gen/context.v1.context.__view.rs new file mode 100644 index 0000000..a2d385a --- /dev/null +++ b/examples/logging/src/gen/context.v1.context.__view.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: context/v1/context.proto + diff --git a/examples/logging/src/gen/context.v1.context.__view_oneof.rs b/examples/logging/src/gen/context.v1.context.__view_oneof.rs new file mode 100644 index 0000000..a2d385a --- /dev/null +++ b/examples/logging/src/gen/context.v1.context.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: context/v1/context.proto + diff --git a/examples/logging/src/gen/log.v1.log.__ext.rs b/examples/logging/src/gen/log.v1.log.__ext.rs new file mode 100644 index 0000000..7e1bec0 --- /dev/null +++ b/examples/logging/src/gen/log.v1.log.__ext.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: log/v1/log.proto + diff --git a/examples/logging/src/gen/log.v1.log.__oneof.rs b/examples/logging/src/gen/log.v1.log.__oneof.rs new file mode 100644 index 0000000..7e1bec0 --- /dev/null +++ b/examples/logging/src/gen/log.v1.log.__oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: log/v1/log.proto + diff --git a/examples/logging/src/gen/log.v1.log.__view.rs b/examples/logging/src/gen/log.v1.log.__view.rs new file mode 100644 index 0000000..7e1bec0 --- /dev/null +++ b/examples/logging/src/gen/log.v1.log.__view.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: log/v1/log.proto + diff --git a/examples/logging/src/gen/log.v1.log.__view_oneof.rs b/examples/logging/src/gen/log.v1.log.__view_oneof.rs new file mode 100644 index 0000000..7e1bec0 --- /dev/null +++ b/examples/logging/src/gen/log.v1.log.__view_oneof.rs @@ -0,0 +1,3 @@ +// @generated by protoc-gen-buffa. DO NOT EDIT. +// source: log/v1/log.proto + diff --git a/examples/logging/src/gen/log.v1.log.rs b/examples/logging/src/gen/log.v1.log.rs index d544d95..8053e95 100644 --- a/examples/logging/src/gen/log.v1.log.rs +++ b/examples/logging/src/gen/log.v1.log.rs @@ -55,6 +55,16 @@ impl ::buffa::Enumeration for Severity { _ => ::core::option::Option::None, } } + fn values() -> &'static [Self] { + &[ + Self::SEVERITY_UNSPECIFIED, + Self::DEBUG, + Self::INFO, + Self::WARN, + Self::ERROR, + Self::FATAL, + ] + } } /// A single structured log entry. #[derive(Clone, PartialEq, Default)] diff --git a/examples/logging/src/gen/mod.rs b/examples/logging/src/gen/mod.rs index 09ea485..71d73c6 100644 --- a/examples/logging/src/gen/mod.rs +++ b/examples/logging/src/gen/mod.rs @@ -13,7 +13,7 @@ pub mod buffa { #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] pub mod v1 { use super::*; - include!("context.v1.context.rs"); + include!("buffa.examples.context.v1.mod.rs"); } } #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] @@ -22,7 +22,7 @@ pub mod buffa { #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] pub mod v1 { use super::*; - include!("log.v1.log.rs"); + include!("buffa.examples.log.v1.mod.rs"); } } } diff --git a/protoc-gen-buffa-packaging/src/main.rs b/protoc-gen-buffa-packaging/src/main.rs index dc7fc61..34c3806 100644 --- a/protoc-gen-buffa-packaging/src/main.rs +++ b/protoc-gen-buffa-packaging/src/main.rs @@ -113,26 +113,25 @@ fn run() -> Result<(), String> { fn generate(request: &CodeGeneratorRequest) -> Result { let filter = parse_filter(request.parameter.as_deref().unwrap_or(""))?; - let entries = request - .file_to_generate + // Module tree wires up one `.mod.rs` per package; collect the + // distinct packages of the requested files (filtered). + let mut packages = std::collections::BTreeSet::new(); + for proto_name in &request.file_to_generate { + let fd = find_descriptor(&request.proto_file, proto_name).ok_or_else(|| { + format!("file_to_generate entry {proto_name:?} has no FileDescriptorProto") + })?; + if filter.include(fd) { + packages.insert(fd.package.as_deref().unwrap_or("").to_string()); + } + } + let entries: Vec<(String, String)> = packages + .into_iter() + .map(|p| (buffa_codegen::package_to_mod_filename(&p), p)) + .collect(); + let borrowed: Vec<(&str, &str)> = entries .iter() - .map(|proto_name| { - let fd = find_descriptor(&request.proto_file, proto_name).ok_or_else(|| { - format!("file_to_generate entry {proto_name:?} has no FileDescriptorProto") - })?; - if !filter.include(fd) { - return Ok(None); - } - let package = fd.package.as_deref().unwrap_or(""); - Ok(Some(( - buffa_codegen::proto_path_to_rust_module(proto_name), - package, - ))) - }) - .filter_map(Result::transpose) - .collect::, String>>()?; - - let borrowed: Vec<(&str, &str)> = entries.iter().map(|(f, p)| (f.as_str(), *p)).collect(); + .map(|(f, p)| (f.as_str(), p.as_str())) + .collect(); let content = buffa_codegen::generate_module_tree(&borrowed, "", true); Ok(CodeGeneratorResponse { @@ -225,29 +224,32 @@ mod tests { None, vec![ file("foo/v1/svc.proto", "foo.v1", true), - file("foo/v1/types.proto", "foo.v1", false), + file("bar/v1/types.proto", "bar.v1", false), ], ); let resp = generate(&req).unwrap(); assert_eq!(resp.file.len(), 1); let content = resp.file[0].content.as_deref().unwrap(); - assert!(content.contains("foo.v1.svc.rs")); - assert!(content.contains("foo.v1.types.rs")); + // Module tree wires up one `.mod.rs` per package. + assert!(content.contains("foo.v1.mod.rs")); + assert!(content.contains("bar.v1.mod.rs")); } #[test] fn services_filter_excludes_non_service_files() { + // Filter is per-file; a package is included if any file in it + // declares a service. `bar.v1` has no service files → excluded. let req = request( Some("filter=services"), vec![ file("foo/v1/svc.proto", "foo.v1", true), - file("foo/v1/types.proto", "foo.v1", false), + file("bar/v1/types.proto", "bar.v1", false), ], ); let resp = generate(&req).unwrap(); let content = resp.file[0].content.as_deref().unwrap(); - assert!(content.contains("foo.v1.svc.rs")); - assert!(!content.contains("foo.v1.types.rs")); + assert!(content.contains("foo.v1.mod.rs")); + assert!(!content.contains("bar.v1.mod.rs")); } #[test] diff --git a/stress/googleapis/gen_lib_rs.py b/stress/googleapis/gen_lib_rs.py index cbd17ef..8ffdb16 100644 --- a/stress/googleapis/gen_lib_rs.py +++ b/stress/googleapis/gen_lib_rs.py @@ -68,24 +68,24 @@ def main(): line = line.strip() if line and not line.startswith("#"): exclude_files.add(line) - rs_files = sorted(gen_dir.glob("*.rs")) + # Only the per-package `.mod.rs` stitchers need wiring; the + # per-proto content files (`*.rs`, `*.__view.rs`, …) are reached via + # `include!` from the stitcher. + rs_files = sorted(gen_dir.glob("*.mod.rs")) if not rs_files: - print("No .rs files found in", gen_dir, file=sys.stderr) + print("No .mod.rs files found in", gen_dir, file=sys.stderr) sys.exit(1) - # Group files by package path (all segments except the last one, - # which is the proto file name). - # e.g. "google.api.expr.v1alpha1.checked.rs" -> package ["google", "api", "expr", "v1alpha1"] + # `.mod.rs` → stem `.mod` → parts[:-1] = package segments. packages = defaultdict(list) excluded = [] for rs_file in rs_files: if rs_file.name in exclude_files: excluded.append(rs_file.name) continue - stem = rs_file.stem # e.g. "google.api.expr.v1alpha1.checked" + stem = rs_file.stem # e.g. "google.api.expr.v1alpha1.mod" parts = stem.split(".") - # The package is everything except the last segment. pkg = tuple(parts[:-1]) packages[pkg].append(rs_file.name) From c3dd4b1e26dc4c1f211e8f08e03e0251c98fc344 Mon Sep 17 00:00:00 2001 From: Ryan Brewster Date: Thu, 23 Apr 2026 19:47:48 +0000 Subject: [PATCH 2/6] codegen: address review findings on buffa_ sentinel layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - generate_package_mod: rebuild via quote! + prettyplease (was string concat); reuse format_tokens - @generated header: protoc-gen-buffa → buffa-codegen (runs under buffa-build too) - ALLOW_LINTS: single pub const at crate root; consumed by generate_module_tree, the .mod.rs stitcher, and buffa-build - generate_module_tree: take IncludeMode {Relative, OutDir}; buffa-build's generate_include_file now delegates to it instead of duplicating tree-building - validate_file: merge the three reserved-name/module-conflict checks into one walk - view.rs owned-path lookup: ? with CodeGenError::Other instead of a silent fallback - rust_type_relative_split extern branch: debug_assert on the segment-count invariant + two unit tests - ancillary_prefix: build super:: chain via quote! loop, not syn::parse_str - empty-package stitcher filename: use the reserved sentinel (buffa_.mod.rs) so it provably can't collide with a real package Regenerated WKT/bootstrap/logging .mod.rs files (prettyplease formatting change only). --- buffa-build/src/lib.rs | 73 +--- buffa-codegen/src/context.rs | 76 +++- buffa-codegen/src/lib.rs | 383 +++++++++--------- buffa-codegen/src/tests/generation.rs | 4 +- buffa-codegen/src/view.rs | 7 +- buffa-codegen/tests/codegen_integration.rs | 24 +- .../generated/google.protobuf.compiler.mod.rs | 21 +- .../google.protobuf.compiler.plugin.__ext.rs | 2 +- ...google.protobuf.compiler.plugin.__oneof.rs | 2 +- .../google.protobuf.compiler.plugin.__view.rs | 2 +- ...e.protobuf.compiler.plugin.__view_oneof.rs | 2 +- .../google.protobuf.compiler.plugin.rs | 2 +- .../google.protobuf.descriptor.__ext.rs | 2 +- .../google.protobuf.descriptor.__oneof.rs | 2 +- .../google.protobuf.descriptor.__view.rs | 2 +- ...google.protobuf.descriptor.__view_oneof.rs | 2 +- .../generated/google.protobuf.descriptor.rs | 2 +- .../src/generated/google.protobuf.mod.rs | 21 +- .../generated/google.protobuf.any.__ext.rs | 2 +- .../generated/google.protobuf.any.__oneof.rs | 2 +- .../generated/google.protobuf.any.__view.rs | 2 +- .../google.protobuf.any.__view_oneof.rs | 2 +- .../src/generated/google.protobuf.any.rs | 2 +- .../google.protobuf.duration.__ext.rs | 2 +- .../google.protobuf.duration.__oneof.rs | 2 +- .../google.protobuf.duration.__view.rs | 2 +- .../google.protobuf.duration.__view_oneof.rs | 2 +- .../src/generated/google.protobuf.duration.rs | 2 +- .../generated/google.protobuf.empty.__ext.rs | 2 +- .../google.protobuf.empty.__oneof.rs | 2 +- .../generated/google.protobuf.empty.__view.rs | 2 +- .../google.protobuf.empty.__view_oneof.rs | 2 +- .../src/generated/google.protobuf.empty.rs | 2 +- .../google.protobuf.field_mask.__ext.rs | 2 +- .../google.protobuf.field_mask.__oneof.rs | 2 +- .../google.protobuf.field_mask.__view.rs | 2 +- ...google.protobuf.field_mask.__view_oneof.rs | 2 +- .../generated/google.protobuf.field_mask.rs | 2 +- .../src/generated/google.protobuf.mod.rs | 27 +- .../generated/google.protobuf.struct.__ext.rs | 2 +- .../google.protobuf.struct.__oneof.rs | 2 +- .../google.protobuf.struct.__view.rs | 2 +- .../google.protobuf.struct.__view_oneof.rs | 2 +- .../src/generated/google.protobuf.struct.rs | 2 +- .../google.protobuf.timestamp.__ext.rs | 2 +- .../google.protobuf.timestamp.__oneof.rs | 2 +- .../google.protobuf.timestamp.__view.rs | 2 +- .../google.protobuf.timestamp.__view_oneof.rs | 2 +- .../generated/google.protobuf.timestamp.rs | 2 +- .../google.protobuf.wrappers.__ext.rs | 2 +- .../google.protobuf.wrappers.__oneof.rs | 2 +- .../google.protobuf.wrappers.__view.rs | 2 +- .../google.protobuf.wrappers.__view_oneof.rs | 2 +- .../src/generated/google.protobuf.wrappers.rs | 2 +- buffa/src/lib.rs | 5 +- .../src/gen/buffa.examples.context.v1.mod.rs | 21 +- .../src/gen/buffa.examples.log.v1.mod.rs | 21 +- .../src/gen/context.v1.context.__ext.rs | 2 +- .../src/gen/context.v1.context.__oneof.rs | 2 +- .../src/gen/context.v1.context.__view.rs | 2 +- .../gen/context.v1.context.__view_oneof.rs | 2 +- .../logging/src/gen/context.v1.context.rs | 2 +- examples/logging/src/gen/log.v1.log.__ext.rs | 2 +- .../logging/src/gen/log.v1.log.__oneof.rs | 2 +- examples/logging/src/gen/log.v1.log.__view.rs | 2 +- .../src/gen/log.v1.log.__view_oneof.rs | 2 +- examples/logging/src/gen/log.v1.log.rs | 2 +- examples/logging/src/gen/mod.rs | 2 +- protoc-gen-buffa-packaging/src/main.rs | 6 +- 69 files changed, 444 insertions(+), 357 deletions(-) diff --git a/buffa-build/src/lib.rs b/buffa-build/src/lib.rs index 0597034..60691e7 100644 --- a/buffa-build/src/lib.rs +++ b/buffa-build/src/lib.rs @@ -816,67 +816,18 @@ fn proto_relative_name(file: &Path, includes: &[PathBuf]) -> String { /// instead of the `env!("OUT_DIR")` prefix, so the include file works when /// checked into the source tree and referenced via `mod`. fn generate_include_file(entries: &[(String, String)], relative: bool) -> String { - use std::collections::BTreeMap; - use std::fmt::Write; - - fn escape_mod_name(name: &str) -> String { - buffa_codegen::idents::escape_mod_ident(name) - } - - #[derive(Default)] - struct ModNode { - files: Vec, - children: BTreeMap, - } - - let mut root = ModNode::default(); - for (file_name, package) in entries { - let pkg_parts: Vec<&str> = if package.is_empty() { - vec![] - } else { - package.split('.').collect() - }; - let mut node = &mut root; - for seg in &pkg_parts { - node = node.children.entry(seg.to_string()).or_default(); - } - node.files.push(file_name.clone()); - } - - let mut out = String::new(); - writeln!(out, "// @generated by buffa-build. DO NOT EDIT.").unwrap(); - writeln!(out).unwrap(); - - fn emit(out: &mut String, node: &ModNode, depth: usize, relative: bool) { - let indent = " ".repeat(depth); - for file in &node.files { - if relative { - writeln!(out, r#"{indent}include!("{file}");"#).unwrap(); - } else { - writeln!( - out, - r#"{indent}include!(concat!(env!("OUT_DIR"), "/{file}"));"# - ) - .unwrap(); - } - } - for (name, child) in &node.children { - let escaped = escape_mod_name(name); - writeln!( - out, - "{indent}#[allow(non_camel_case_types, dead_code, unused_imports, \ - clippy::derivable_impls, clippy::match_single_binding)]" - ) - .unwrap(); - writeln!(out, "{indent}pub mod {escaped} {{").unwrap(); - writeln!(out, "{indent} use super::*;").unwrap(); - emit(out, child, depth + 1, relative); - writeln!(out, "{indent}}}").unwrap(); - } - } - - emit(&mut out, &root, 0, relative); - out + let borrowed: Vec<(&str, &str)> = entries + .iter() + .map(|(f, p)| (f.as_str(), p.as_str())) + .collect(); + let mode = if relative { + buffa_codegen::IncludeMode::Relative("") + } else { + buffa_codegen::IncludeMode::OutDir + }; + // Inner-allow off: this output is consumed via `include!` from + // user-authored `lib.rs`, where `#![allow(...)]` is not valid. + buffa_codegen::generate_module_tree(&borrowed, mode, false) } #[cfg(test)] diff --git a/buffa-codegen/src/context.rs b/buffa-codegen/src/context.rs index 1915fc0..5b2abe1 100644 --- a/buffa-codegen/src/context.rs +++ b/buffa-codegen/src/context.rs @@ -12,7 +12,7 @@ use crate::CodeGenConfig; /// /// See `DESIGN.md` → "Generated code layout" for the full layout. The name /// is checked against proto package segments and message-module names by -/// [`crate::check_reserved_sentinel`]; a collision is a hard error. +/// [`crate::validate_file`]; a collision is a hard error. pub const SENTINEL_MOD: &str = "buffa_"; /// A Rust type path split at the target-package boundary. @@ -373,6 +373,15 @@ impl<'a> CodeGenContext<'a> { // Count the segments and strip that many from full_path. let within_segs = within_proto.split('.').count(); let full_segs: Vec<&str> = full_path.split("::").collect(); + // Invariant: `full_path` was built by `CodeGenContext::new` as + // `::`, so it always has at least + // `within_segs` trailing segments. If this fires the type_map + // and package_of maps are out of sync. + debug_assert!( + full_segs.len() >= within_segs, + "extern path '{full_path}' has fewer segments than \ + within-package proto path '{within_proto}'" + ); let cut = full_segs.len().saturating_sub(within_segs); full_segs[..cut].join("::") } else { @@ -567,12 +576,10 @@ pub(crate) fn ancillary_prefix( use crate::idents::make_field_ident; use quote::quote; - let supers = "super::".repeat(from_nesting); - let supers_tokens: proc_macro2::TokenStream = if supers.is_empty() { - proc_macro2::TokenStream::new() - } else { - syn::parse_str(&supers).expect("valid super:: chain") - }; + let mut supers_tokens = proc_macro2::TokenStream::new(); + for _ in 0..from_nesting { + supers_tokens.extend(quote! { super:: }); + } let sentinel = make_field_ident(SENTINEL_MOD); let kind_segs: Vec<_> = kind @@ -1265,6 +1272,61 @@ mod tests { assert_eq!(result, Some("crate::proto::google::type".into())); } + // ── rust_type_relative_split — extern branch ──────────────────────── + + #[test] + fn test_split_extern_top_level() { + let outer = msg_with_nested("Value", vec![msg("Inner")]); + let files = [make_file( + "struct.proto", + "google.protobuf", + vec![outer], + vec![], + )]; + let config = CodeGenConfig::default(); + let extern_paths = vec![( + ".google.protobuf".into(), + "::buffa_types::google::protobuf".into(), + )]; + let ctx = CodeGenContext::new(&files, &config, &extern_paths); + + let split = ctx + .rust_type_relative_split(".google.protobuf.Value", "my.pkg", 3) + .expect("type resolves"); + assert!(split.is_extern); + // Extern path is absolute → nesting irrelevant. + assert_eq!(split.to_package, "::buffa_types::google::protobuf"); + assert_eq!(split.within_package, "Value"); + } + + #[test] + fn test_split_extern_nested_type() { + // Nested `.google.protobuf.Value.Inner` → + // extern path `::buffa_types::google::protobuf::value::Inner`. + // Segment-count slice: 2 within-package segments → cut after the + // extern module prefix. + let outer = msg_with_nested("Value", vec![msg("Inner")]); + let files = [make_file( + "struct.proto", + "google.protobuf", + vec![outer], + vec![], + )]; + let config = CodeGenConfig::default(); + let extern_paths = vec![( + ".google.protobuf".into(), + "::buffa_types::google::protobuf".into(), + )]; + let ctx = CodeGenContext::new(&files, &config, &extern_paths); + + let split = ctx + .rust_type_relative_split(".google.protobuf.Value.Inner", "my.pkg", 0) + .expect("nested type resolves"); + assert!(split.is_extern); + assert_eq!(split.to_package, "::buffa_types::google::protobuf"); + assert_eq!(split.within_package, "value::Inner"); + } + #[test] fn test_extern_path_top_level_message() { let files = [make_file( diff --git a/buffa-codegen/src/lib.rs b/buffa-codegen/src/lib.rs index d0dbd03..bc67350 100644 --- a/buffa-codegen/src/lib.rs +++ b/buffa-codegen/src/lib.rs @@ -40,6 +40,30 @@ use crate::generated::descriptor::FileDescriptorProto; use proc_macro2::TokenStream; use quote::quote; +/// Lints suppressed on generated code at module boundaries. +/// +/// Consumed by [`generate_module_tree`], the per-package `.mod.rs` +/// stitcher, and `buffa-build`'s `_include.rs` writer. One list keeps +/// them in sync. +pub const ALLOW_LINTS: &[&str] = &[ + "non_camel_case_types", + "dead_code", + "unused_imports", + "clippy::derivable_impls", + "clippy::match_single_binding", + "clippy::uninlined_format_args", + "clippy::doc_lazy_continuation", +]; + +/// Render [`ALLOW_LINTS`] as a `#[allow(…)]` attribute token stream. +pub fn allow_lints_attr() -> TokenStream { + let lints: Vec = ALLOW_LINTS + .iter() + .map(|l| syn::parse_str(l).expect("lint name parses as path")) + .collect(); + quote! { #[allow( #(#lints),* )] } +} + /// One generated output file. /// /// Each `.proto` produces five **content files** (`.rs`, @@ -308,18 +332,14 @@ pub fn generate( /// [`GeneratedFileKind::PackageMod`] outputs need wiring; per-proto /// content files are reached via `include!` from the stitcher). /// -/// `include_prefix` is prepended to file names in `include!` directives. -/// Use `""` for relative paths or `concat!(env!("OUT_DIR"), "/")` style -/// for build.rs output. +/// `include_mode` controls how `include!` paths are emitted. /// -/// When `emit_inner_allow` is true, a `#![allow(...)]` inner attribute is -/// emitted at the top of the file. This is appropriate when the output is -/// used directly as a module file (e.g., `mod.rs`) but NOT when the output -/// is consumed via `include!` (inner attributes are not valid in that -/// context). +/// `emit_inner_allow` adds a `#![allow(...)]` inner attribute at the top — +/// valid when the output is used directly as a module file (`mod.rs`), +/// invalid when consumed via `include!`. pub fn generate_module_tree( entries: &[(&str, &str)], - include_prefix: &str, + include_mode: IncludeMode<'_>, emit_inner_allow: bool, ) -> String { use std::collections::BTreeMap; @@ -349,22 +369,30 @@ pub fn generate_module_tree( node.files.push(file_name.to_string()); } + let lints = ALLOW_LINTS.join(", "); let mut out = String::new(); - writeln!(out, "// @generated by buffa. DO NOT EDIT.").unwrap(); - const ALLOW_LINTS: &str = "non_camel_case_types, dead_code, unused_imports, \ - clippy::derivable_impls, clippy::match_single_binding, \ - clippy::uninlined_format_args, clippy::doc_lazy_continuation"; - + writeln!(out, "// @generated by buffa-codegen. DO NOT EDIT.").unwrap(); if emit_inner_allow { - writeln!(out, "#![allow({ALLOW_LINTS})]").unwrap(); + writeln!(out, "#![allow({lints})]").unwrap(); } writeln!(out).unwrap(); - fn emit(out: &mut String, node: &ModNode, depth: usize, prefix: &str, lints: &str) { + fn emit(out: &mut String, node: &ModNode, depth: usize, mode: IncludeMode<'_>, lints: &str) { let indent = " ".repeat(depth); for file in &node.files { - writeln!(out, r#"{indent}include!("{prefix}{file}");"#).unwrap(); + match mode { + IncludeMode::Relative(prefix) => { + writeln!(out, r#"{indent}include!("{prefix}{file}");"#).unwrap(); + } + IncludeMode::OutDir => { + writeln!( + out, + r#"{indent}include!(concat!(env!("OUT_DIR"), "/{file}"));"# + ) + .unwrap(); + } + } } for (name, child) in &node.children { @@ -372,71 +400,84 @@ pub fn generate_module_tree( writeln!(out, "{indent}#[allow({lints})]").unwrap(); writeln!(out, "{indent}pub mod {escaped} {{").unwrap(); writeln!(out, "{indent} use super::*;").unwrap(); - emit(out, child, depth + 1, prefix, lints); + emit(out, child, depth + 1, mode, lints); writeln!(out, "{indent}}}").unwrap(); } } - emit(&mut out, &root, 0, include_prefix, ALLOW_LINTS); + emit(&mut out, &root, 0, include_mode, &lints); out } -/// Check that no fields in the file use the `__buffa_` reserved prefix. -fn check_reserved_field_names(file: &FileDescriptorProto) -> Result<(), CodeGenError> { - fn check_message( - msg: &crate::generated::descriptor::DescriptorProto, - parent_name: &str, - ) -> Result<(), CodeGenError> { - let msg_name = msg.name.as_deref().unwrap_or(""); - let fqn = if parent_name.is_empty() { - msg_name.to_string() - } else { - format!("{}.{}", parent_name, msg_name) - }; - - for field in &msg.field { - if let Some(name) = &field.name { - if name.starts_with("__buffa_") { - return Err(CodeGenError::ReservedFieldName { - message_name: fqn, - field_name: name.clone(), - }); - } - } - } - - for nested in &msg.nested_type { - check_message(nested, &fqn)?; - } - - Ok(()) - } - - let package = file.package.as_deref().unwrap_or(""); - for msg in &file.message_type { - check_message(msg, package)?; - } - Ok(()) +/// How [`generate_module_tree`] emits `include!` paths. +#[derive(Debug, Clone, Copy)] +pub enum IncludeMode<'a> { + /// `include!("")` — relative to the including file. + /// Prefix is typically `""` or `"gen/"`. + Relative(&'a str), + /// `include!(concat!(env!("OUT_DIR"), "/"))` — for build.rs output. + OutDir, } -/// Check that no sibling messages produce the same snake_case module name. +/// Validate one input descriptor before generating code for it. +/// +/// Checks, in one walk of the message tree: /// -/// For example, `HTTPRequest` and `HttpRequest` both produce -/// `pub mod http_request`, which would be a compile error. -fn check_module_name_conflicts(file: &FileDescriptorProto) -> Result<(), CodeGenError> { +/// - **Reserved field names**: no field starts with `__buffa_` (would clash +/// with generated `__buffa_unknown_fields` / `__buffa_cached_size`). +/// - **Module-name conflicts**: no two sibling messages snake_case to the +/// same module name (e.g. `HTTPRequest` vs `HttpRequest`). +/// - **Reserved sentinel**: no package segment or message-module name +/// equals [`SENTINEL_MOD`](context::SENTINEL_MOD). Ancillary types live +/// under `pkg::buffa_::…`; a proto element emitting `pub mod buffa_` at +/// any level would produce E0428. This is the only name buffa reserves +/// in user namespace. +fn validate_file(file: &FileDescriptorProto) -> Result<(), CodeGenError> { use std::collections::HashMap; - fn check_siblings( + let sentinel = context::SENTINEL_MOD; + let package = file.package.as_deref().unwrap_or(""); + if package.split('.').any(|seg| seg == sentinel) { + return Err(CodeGenError::ReservedModuleName { + name: sentinel.to_string(), + location: format!("package '{package}'"), + }); + } + + fn walk( messages: &[crate::generated::descriptor::DescriptorProto], scope: &str, + sentinel: &str, ) -> Result<(), CodeGenError> { - // Map from snake_case module name → original proto name. + // snake_case module name → original proto name (for conflict diag). let mut seen: HashMap = HashMap::new(); for msg in messages { let name = msg.name.as_deref().unwrap_or(""); - let module_name = crate::oneof::to_snake_case(name); + let fqn = if scope.is_empty() { + name.to_string() + } else { + format!("{scope}.{name}") + }; + + for field in &msg.field { + if let Some(fname) = &field.name { + if fname.starts_with("__buffa_") { + return Err(CodeGenError::ReservedFieldName { + message_name: fqn, + field_name: fname.clone(), + }); + } + } + } + let module_name = crate::oneof::to_snake_case(name); + if module_name == sentinel { + return Err(CodeGenError::ReservedModuleName { + name: sentinel.to_string(), + location: format!("message '{fqn}'"), + }); + } if let Some(existing) = seen.get(&module_name) { return Err(CodeGenError::ModuleNameConflict { scope: scope.to_string(), @@ -447,62 +488,12 @@ fn check_module_name_conflicts(file: &FileDescriptorProto) -> Result<(), CodeGen } seen.insert(module_name, name); - // Recurse into nested messages. - let child_scope = if scope.is_empty() { - name.to_string() - } else { - format!("{}.{}", scope, name) - }; - check_siblings(&msg.nested_type, &child_scope)?; + walk(&msg.nested_type, &fqn, sentinel)?; } - Ok(()) } - let package = file.package.as_deref().unwrap_or(""); - check_siblings(&file.message_type, package) -} - -/// Check that no proto package segment or message-module name equals the -/// reserved [`SENTINEL_MOD`](context::SENTINEL_MOD). -/// -/// Ancillary types live under `pkg::buffa_::…`; a proto element that would -/// emit `pub mod buffa_` at any level (a package segment literally named -/// `buffa_`, or a message whose snake_case module name is `buffa_`) would -/// produce E0428. This is the **only** name buffa reserves in user -/// namespace, so the check is one place to look at when adding kinds. -fn check_reserved_sentinel(file: &FileDescriptorProto) -> Result<(), CodeGenError> { - let sentinel = context::SENTINEL_MOD; - let package = file.package.as_deref().unwrap_or(""); - if package.split('.').any(|seg| seg == sentinel) { - return Err(CodeGenError::ReservedModuleName { - name: sentinel.to_string(), - location: format!("package '{package}'"), - }); - } - fn check_messages( - messages: &[crate::generated::descriptor::DescriptorProto], - scope: &str, - sentinel: &str, - ) -> Result<(), CodeGenError> { - for msg in messages { - let name = msg.name.as_deref().unwrap_or(""); - if crate::oneof::to_snake_case(name) == sentinel { - return Err(CodeGenError::ReservedModuleName { - name: sentinel.to_string(), - location: format!("message '{scope}.{name}'"), - }); - } - let child_scope = if scope.is_empty() { - name.to_string() - } else { - format!("{}.{}", scope, name) - }; - check_messages(&msg.nested_type, &child_scope, sentinel)?; - } - Ok(()) - } - check_messages(&file.message_type, package, sentinel) + walk(&file.message_type, package, sentinel) } /// Per-proto content streams plus the file stem, ready to be formatted. @@ -525,9 +516,7 @@ fn generate_proto_content( use crate::idents::make_field_ident; use crate::message::MessageOutput; - check_reserved_field_names(file)?; - check_module_name_conflicts(file)?; - check_reserved_sentinel(file)?; + validate_file(file)?; let resolver = imports::ImportResolver::for_file(file); let features = crate::features::for_file(file); @@ -678,7 +667,7 @@ fn generate_package( name: package_to_mod_filename(current_package), package: current_package.to_string(), kind: GeneratedFileKind::PackageMod, - content: generate_package_mod(ctx, &stems, ®), + content: generate_package_mod(ctx, &stems, ®)?, }); Ok(()) @@ -693,83 +682,84 @@ fn generate_package_mod( ctx: &context::CodeGenContext, stems: &[String], reg: &message::RegistryPaths, -) -> String { - use std::fmt::Write as _; - - let mut s = String::new(); - writeln!(s, "// @generated by protoc-gen-buffa. DO NOT EDIT.").unwrap(); - writeln!(s).unwrap(); - let owned_includes = |s: &mut String, suffix: &str| { - for stem in stems { - writeln!(s, r#"include!("{stem}{suffix}.rs");"#).unwrap(); - } +) -> Result { + use crate::idents::make_field_ident; + + let includes = |suffix: &str| -> Vec { + stems + .iter() + .map(|stem| { + let path = format!("{stem}{suffix}.rs"); + quote! { include!(#path); } + }) + .collect() }; - owned_includes(&mut s, ""); - writeln!( - s, - "#[allow(non_camel_case_types, dead_code, unused_imports, \ - clippy::derivable_impls, clippy::match_single_binding)]" - ) - .unwrap(); - writeln!(s, "pub mod {} {{", context::SENTINEL_MOD).unwrap(); - writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); - if ctx.config.generate_views { - writeln!(s, " pub mod view {{").unwrap(); - writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); - for stem in stems { - writeln!(s, r#" include!("{stem}.__view.rs");"#).unwrap(); - } - writeln!(s, " pub mod oneof {{").unwrap(); - writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); - for stem in stems { - writeln!(s, r#" include!("{stem}.__view_oneof.rs");"#).unwrap(); - } - writeln!(s, " }}").unwrap(); - writeln!(s, " }}").unwrap(); - } - writeln!(s, " pub mod oneof {{").unwrap(); - writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); - for stem in stems { - writeln!(s, r#" include!("{stem}.__oneof.rs");"#).unwrap(); - } - writeln!(s, " }}").unwrap(); - writeln!(s, " pub mod ext {{").unwrap(); - writeln!(s, " #[allow(unused_imports)] use super::*;").unwrap(); - for stem in stems { - writeln!(s, r#" include!("{stem}.__ext.rs");"#).unwrap(); - } - writeln!(s, " }}").unwrap(); - - if ctx.config.emit_register_fn && !reg.is_empty() { - writeln!( - s, - " /// Register this package's `Any` type entries and extension entries." - ) - .unwrap(); - writeln!( - s, - " pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry) {{" - ) - .unwrap(); - // TokenStream::Display inserts inter-token spaces; collapse them so - // the output is `super::foo::__BAR` not `super::foo :: __BAR`. - let path = |p: &TokenStream| p.to_string().replace(' ', ""); - for p in ®.json_any { - writeln!(s, " reg.register_json_any(super::{});", path(p)).unwrap(); - } - for p in ®.json_ext { - writeln!(s, " reg.register_json_ext(super::{});", path(p)).unwrap(); + + let owned = includes(""); + let view = includes(".__view"); + let view_oneof = includes(".__view_oneof"); + let oneof = includes(".__oneof"); + let ext = includes(".__ext"); + + let view_mod = if ctx.config.generate_views { + quote! { + pub mod view { + #[allow(unused_imports)] + use super::*; + #(#view)* + pub mod oneof { + #[allow(unused_imports)] + use super::*; + #(#view_oneof)* + } + } } - for p in ®.text_any { - writeln!(s, " reg.register_text_any(super::{});", path(p)).unwrap(); + } else { + TokenStream::new() + }; + + let register_fn = if ctx.config.emit_register_fn && !reg.is_empty() { + let json_any = ®.json_any; + let json_ext = ®.json_ext; + let text_any = ®.text_any; + let text_ext = ®.text_ext; + quote! { + /// Register this package's `Any` type entries and extension entries. + pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry) { + #( reg.register_json_any(super::#json_any); )* + #( reg.register_json_ext(super::#json_ext); )* + #( reg.register_text_any(super::#text_any); )* + #( reg.register_text_ext(super::#text_ext); )* + } } - for p in ®.text_ext { - writeln!(s, " reg.register_text_ext(super::{});", path(p)).unwrap(); + } else { + TokenStream::new() + }; + + let allow = allow_lints_attr(); + let sentinel = make_field_ident(context::SENTINEL_MOD); + let tokens = quote! { + #(#owned)* + #allow + pub mod #sentinel { + #[allow(unused_imports)] + use super::*; + #view_mod + pub mod oneof { + #[allow(unused_imports)] + use super::*; + #(#oneof)* + } + pub mod ext { + #[allow(unused_imports)] + use super::*; + #(#ext)* + } + #register_fn } - writeln!(s, " }}").unwrap(); - } - writeln!(s, "}}").unwrap(); - s + }; + + format_tokens(tokens, "") } /// Format a token stream into a generated-file string with the standard @@ -784,17 +774,20 @@ fn format_tokens(tokens: TokenStream, source: &str) -> Result String { if package.is_empty() { - "_.mod.rs".to_string() + format!("{}.mod.rs", context::SENTINEL_MOD) } else { format!("{package}.mod.rs") } diff --git a/buffa-codegen/src/tests/generation.rs b/buffa-codegen/src/tests/generation.rs index 2e35f69..53346a9 100644 --- a/buffa-codegen/src/tests/generation.rs +++ b/buffa-codegen/src/tests/generation.rs @@ -61,7 +61,7 @@ fn test_empty_file() { .iter() .find(|f| f.kind == GeneratedFileKind::PackageMod) .expect("stitcher present"); - assert_eq!(stitcher.name, "_.mod.rs"); + assert_eq!(stitcher.name, "buffa_.mod.rs"); assert!( stitcher.content.contains("@generated"), "missing header comment" @@ -75,7 +75,7 @@ fn test_package_to_mod_filename() { "google.protobuf.mod.rs" ); assert_eq!(package_to_mod_filename("foo"), "foo.mod.rs"); - assert_eq!(package_to_mod_filename(""), "_.mod.rs"); + assert_eq!(package_to_mod_filename(""), "buffa_.mod.rs"); assert_eq!( proto_path_to_stem("google/protobuf/timestamp.proto"), "google.protobuf.timestamp" diff --git a/buffa-codegen/src/view.rs b/buffa-codegen/src/view.rs index fbe489f..c34d848 100644 --- a/buffa-codegen/src/view.rs +++ b/buffa-codegen/src/view.rs @@ -88,7 +88,6 @@ pub(crate) fn generate_view_with_nesting( let oneof_idents = crate::oneof::resolve_oneof_idents(msg); let view_ident = format_ident!("{}View", rust_name); - let owned_ident = format_ident!("{}", rust_name); // Total module depth of the view-struct body below the package root. // All field-type / decode-arm / to-owned helpers below resolve paths @@ -189,7 +188,11 @@ pub(crate) fn generate_view_with_nesting( let dotted = format!(".{proto_fqn}"); let p = ctx .rust_type_relative(&dotted, current_package, view_depth) - .unwrap_or_else(|| owned_ident.to_string()); + .ok_or_else(|| { + CodeGenError::Other(format!( + "owned type for '{proto_fqn}' not resolvable from view tree" + )) + })?; rust_path_to_tokens(&p) }; diff --git a/buffa-codegen/tests/codegen_integration.rs b/buffa-codegen/tests/codegen_integration.rs index 91be3a5..80f8434 100644 --- a/buffa-codegen/tests/codegen_integration.rs +++ b/buffa-codegen/tests/codegen_integration.rs @@ -237,7 +237,11 @@ fn module_tree_basic() { ("bar.rs", "my.pkg"), ("baz.rs", "other"), ]; - let tree = buffa_codegen::generate_module_tree(&entries, "", false); + let tree = buffa_codegen::generate_module_tree( + &entries, + buffa_codegen::IncludeMode::Relative(""), + false, + ); assert!(tree.contains("pub mod my")); assert!(tree.contains("pub mod pkg")); assert!(tree.contains("pub mod other")); @@ -247,8 +251,16 @@ fn module_tree_basic() { #[test] fn module_tree_inner_allow() { let entries = vec![("f.rs", "pkg")]; - let with = buffa_codegen::generate_module_tree(&entries, "", true); - let without = buffa_codegen::generate_module_tree(&entries, "", false); + let with = buffa_codegen::generate_module_tree( + &entries, + buffa_codegen::IncludeMode::Relative(""), + true, + ); + let without = buffa_codegen::generate_module_tree( + &entries, + buffa_codegen::IncludeMode::Relative(""), + false, + ); assert!(with.contains("#![allow(")); assert!(!without.contains("#![allow(")); } @@ -256,7 +268,11 @@ fn module_tree_inner_allow() { #[test] fn module_tree_keyword_escaping() { let entries = vec![("t.rs", "google.type")]; - let tree = buffa_codegen::generate_module_tree(&entries, "", false); + let tree = buffa_codegen::generate_module_tree( + &entries, + buffa_codegen::IncludeMode::Relative(""), + false, + ); assert!(tree.contains("pub mod r#type")); } diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs index 53dc95e..e4294e3 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs @@ -1,15 +1,26 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. include!("google.protobuf.compiler.plugin.rs"); -#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +#[allow( + non_camel_case_types, + dead_code, + unused_imports, + clippy::derivable_impls, + clippy::match_single_binding, + clippy::uninlined_format_args, + clippy::doc_lazy_continuation +)] pub mod buffa_ { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; pub mod oneof { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.compiler.plugin.__oneof.rs"); } pub mod ext { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.compiler.plugin.__ext.rs"); } } diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs index 488122e..7e3d491 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/compiler/plugin.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs index 488122e..7e3d491 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/compiler/plugin.proto 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 488122e..7e3d491 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/compiler/plugin.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs index 488122e..7e3d491 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/compiler/plugin.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs index e5f13f5..6625bde 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/compiler/plugin.proto /// The version number of protocol compiler. diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs index 0794f60..6b0ab31 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/descriptor.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs index 0794f60..6b0ab31 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/descriptor.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs index 0794f60..6b0ab31 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/descriptor.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs index 0794f60..6b0ab31 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/descriptor.proto diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.rs index 6932363..7eed43e 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/descriptor.proto /// The full set of known editions. diff --git a/buffa-descriptor/src/generated/google.protobuf.mod.rs b/buffa-descriptor/src/generated/google.protobuf.mod.rs index 8b68cde..c92ee2e 100644 --- a/buffa-descriptor/src/generated/google.protobuf.mod.rs +++ b/buffa-descriptor/src/generated/google.protobuf.mod.rs @@ -1,15 +1,26 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. include!("google.protobuf.descriptor.rs"); -#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +#[allow( + non_camel_case_types, + dead_code, + unused_imports, + clippy::derivable_impls, + clippy::match_single_binding, + clippy::uninlined_format_args, + clippy::doc_lazy_continuation +)] pub mod buffa_ { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; pub mod oneof { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.descriptor.__oneof.rs"); } pub mod ext { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.descriptor.__ext.rs"); } } diff --git a/buffa-types/src/generated/google.protobuf.any.__ext.rs b/buffa-types/src/generated/google.protobuf.any.__ext.rs index 415a4fc..53a39a9 100644 --- a/buffa-types/src/generated/google.protobuf.any.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.any.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/any.proto diff --git a/buffa-types/src/generated/google.protobuf.any.__oneof.rs b/buffa-types/src/generated/google.protobuf.any.__oneof.rs index 415a4fc..53a39a9 100644 --- a/buffa-types/src/generated/google.protobuf.any.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.any.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/any.proto diff --git a/buffa-types/src/generated/google.protobuf.any.__view.rs b/buffa-types/src/generated/google.protobuf.any.__view.rs index 6fbeb1c..799446b 100644 --- a/buffa-types/src/generated/google.protobuf.any.__view.rs +++ b/buffa-types/src/generated/google.protobuf.any.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/any.proto /// `Any` contains an arbitrary serialized protocol buffer message along with a diff --git a/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs index 415a4fc..53a39a9 100644 --- a/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.any.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/any.proto diff --git a/buffa-types/src/generated/google.protobuf.any.rs b/buffa-types/src/generated/google.protobuf.any.rs index d77ec9e..0ddd7b7 100644 --- a/buffa-types/src/generated/google.protobuf.any.rs +++ b/buffa-types/src/generated/google.protobuf.any.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/any.proto /// `Any` contains an arbitrary serialized protocol buffer message along with a diff --git a/buffa-types/src/generated/google.protobuf.duration.__ext.rs b/buffa-types/src/generated/google.protobuf.duration.__ext.rs index 2bdabf5..5665aee 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/duration.proto diff --git a/buffa-types/src/generated/google.protobuf.duration.__oneof.rs b/buffa-types/src/generated/google.protobuf.duration.__oneof.rs index 2bdabf5..5665aee 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/duration.proto diff --git a/buffa-types/src/generated/google.protobuf.duration.__view.rs b/buffa-types/src/generated/google.protobuf.duration.__view.rs index 69a8f4c..af0b2e4 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__view.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/duration.proto /// A Duration represents a signed, fixed-length span of time represented diff --git a/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs index 2bdabf5..5665aee 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/duration.proto diff --git a/buffa-types/src/generated/google.protobuf.duration.rs b/buffa-types/src/generated/google.protobuf.duration.rs index c001848..11f65e8 100644 --- a/buffa-types/src/generated/google.protobuf.duration.rs +++ b/buffa-types/src/generated/google.protobuf.duration.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/duration.proto /// A Duration represents a signed, fixed-length span of time represented diff --git a/buffa-types/src/generated/google.protobuf.empty.__ext.rs b/buffa-types/src/generated/google.protobuf.empty.__ext.rs index eafd5d8..36cded0 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/empty.proto diff --git a/buffa-types/src/generated/google.protobuf.empty.__oneof.rs b/buffa-types/src/generated/google.protobuf.empty.__oneof.rs index eafd5d8..36cded0 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/empty.proto diff --git a/buffa-types/src/generated/google.protobuf.empty.__view.rs b/buffa-types/src/generated/google.protobuf.empty.__view.rs index cc4c4a0..433f85b 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__view.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/empty.proto /// A generic empty message that you can re-use to avoid defining duplicated diff --git a/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs index eafd5d8..36cded0 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/empty.proto diff --git a/buffa-types/src/generated/google.protobuf.empty.rs b/buffa-types/src/generated/google.protobuf.empty.rs index 86c5376..07da183 100644 --- a/buffa-types/src/generated/google.protobuf.empty.rs +++ b/buffa-types/src/generated/google.protobuf.empty.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/empty.proto /// A generic empty message that you can re-use to avoid defining duplicated diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs b/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs index e76a3b8..ded36e5 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/field_mask.proto diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs b/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs index e76a3b8..ded36e5 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/field_mask.proto 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 08ad6a2..61c1de1 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/field_mask.proto /// `FieldMask` represents a set of symbolic field paths, for example: diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs index e76a3b8..ded36e5 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/field_mask.proto diff --git a/buffa-types/src/generated/google.protobuf.field_mask.rs b/buffa-types/src/generated/google.protobuf.field_mask.rs index 1fee4fe..70ec708 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/field_mask.proto /// `FieldMask` represents a set of symbolic field paths, for example: diff --git a/buffa-types/src/generated/google.protobuf.mod.rs b/buffa-types/src/generated/google.protobuf.mod.rs index b4b4ec8..6337159 100644 --- a/buffa-types/src/generated/google.protobuf.mod.rs +++ b/buffa-types/src/generated/google.protobuf.mod.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. include!("google.protobuf.any.rs"); include!("google.protobuf.duration.rs"); @@ -7,11 +7,21 @@ include!("google.protobuf.field_mask.rs"); include!("google.protobuf.struct.rs"); include!("google.protobuf.timestamp.rs"); include!("google.protobuf.wrappers.rs"); -#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +#[allow( + non_camel_case_types, + dead_code, + unused_imports, + clippy::derivable_impls, + clippy::match_single_binding, + clippy::uninlined_format_args, + clippy::doc_lazy_continuation +)] pub mod buffa_ { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; pub mod view { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.any.__view.rs"); include!("google.protobuf.duration.__view.rs"); include!("google.protobuf.empty.__view.rs"); @@ -20,7 +30,8 @@ pub mod buffa_ { include!("google.protobuf.timestamp.__view.rs"); include!("google.protobuf.wrappers.__view.rs"); pub mod oneof { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.any.__view_oneof.rs"); include!("google.protobuf.duration.__view_oneof.rs"); include!("google.protobuf.empty.__view_oneof.rs"); @@ -31,7 +42,8 @@ pub mod buffa_ { } } pub mod oneof { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.any.__oneof.rs"); include!("google.protobuf.duration.__oneof.rs"); include!("google.protobuf.empty.__oneof.rs"); @@ -41,7 +53,8 @@ pub mod buffa_ { include!("google.protobuf.wrappers.__oneof.rs"); } pub mod ext { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("google.protobuf.any.__ext.rs"); include!("google.protobuf.duration.__ext.rs"); include!("google.protobuf.empty.__ext.rs"); diff --git a/buffa-types/src/generated/google.protobuf.struct.__ext.rs b/buffa-types/src/generated/google.protobuf.struct.__ext.rs index 97f4e50..4449756 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/struct.proto diff --git a/buffa-types/src/generated/google.protobuf.struct.__oneof.rs b/buffa-types/src/generated/google.protobuf.struct.__oneof.rs index 675e7da..f9e34ec 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__oneof.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/struct.proto pub mod value { diff --git a/buffa-types/src/generated/google.protobuf.struct.__view.rs b/buffa-types/src/generated/google.protobuf.struct.__view.rs index 7a5d3a4..6330b43 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/struct.proto /// `Struct` represents a structured data value, consisting of fields diff --git a/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs index 39576b5..575c712 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/struct.proto pub mod value { diff --git a/buffa-types/src/generated/google.protobuf.struct.rs b/buffa-types/src/generated/google.protobuf.struct.rs index 278b651..7dc39dc 100644 --- a/buffa-types/src/generated/google.protobuf.struct.rs +++ b/buffa-types/src/generated/google.protobuf.struct.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/struct.proto /// `NullValue` is a singleton enumeration to represent the null value for the diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs b/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs index 94add37..cb0ed2d 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/timestamp.proto diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs b/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs index 94add37..cb0ed2d 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/timestamp.proto diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs index ae81a31..5422c4b 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/timestamp.proto /// A Timestamp represents a point in time independent of any time zone or local diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs index 94add37..cb0ed2d 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/timestamp.proto diff --git a/buffa-types/src/generated/google.protobuf.timestamp.rs b/buffa-types/src/generated/google.protobuf.timestamp.rs index 141e5b9..35c4add 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/timestamp.proto /// A Timestamp represents a point in time independent of any time zone or local diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs b/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs index e8699ea..47c2c1a 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/wrappers.proto diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs b/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs index e8699ea..47c2c1a 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/wrappers.proto diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs index fe2334f..5b1f0d8 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/wrappers.proto /// Wrapper message for `double`. diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs index e8699ea..47c2c1a 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/wrappers.proto diff --git a/buffa-types/src/generated/google.protobuf.wrappers.rs b/buffa-types/src/generated/google.protobuf.wrappers.rs index fb6f578..4c6d0c1 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: google/protobuf/wrappers.proto /// Wrapper message for `double`. diff --git a/buffa/src/lib.rs b/buffa/src/lib.rs index 0287cc2..60c5e6c 100644 --- a/buffa/src/lib.rs +++ b/buffa/src/lib.rs @@ -130,8 +130,9 @@ pub use ::bytes; /// } /// ``` /// -/// For the unnamed package, pass `"_"`. For checked-in generated code -/// (no `OUT_DIR`), use [`include_proto_relative!`]. +/// For the unnamed package, pass `"buffa_"` (the reserved sentinel — no +/// real package can use it). For checked-in generated code (no +/// `OUT_DIR`), use [`include_proto_relative!`]. #[macro_export] macro_rules! include_proto { ($pkg:literal) => { diff --git a/examples/logging/src/gen/buffa.examples.context.v1.mod.rs b/examples/logging/src/gen/buffa.examples.context.v1.mod.rs index 3adba5c..cd248b5 100644 --- a/examples/logging/src/gen/buffa.examples.context.v1.mod.rs +++ b/examples/logging/src/gen/buffa.examples.context.v1.mod.rs @@ -1,15 +1,26 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. include!("context.v1.context.rs"); -#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +#[allow( + non_camel_case_types, + dead_code, + unused_imports, + clippy::derivable_impls, + clippy::match_single_binding, + clippy::uninlined_format_args, + clippy::doc_lazy_continuation +)] pub mod buffa_ { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; pub mod oneof { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("context.v1.context.__oneof.rs"); } pub mod ext { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("context.v1.context.__ext.rs"); } } diff --git a/examples/logging/src/gen/buffa.examples.log.v1.mod.rs b/examples/logging/src/gen/buffa.examples.log.v1.mod.rs index a04cfb2..02c1f1c 100644 --- a/examples/logging/src/gen/buffa.examples.log.v1.mod.rs +++ b/examples/logging/src/gen/buffa.examples.log.v1.mod.rs @@ -1,15 +1,26 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. include!("log.v1.log.rs"); -#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding)] +#[allow( + non_camel_case_types, + dead_code, + unused_imports, + clippy::derivable_impls, + clippy::match_single_binding, + clippy::uninlined_format_args, + clippy::doc_lazy_continuation +)] pub mod buffa_ { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; pub mod oneof { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("log.v1.log.__oneof.rs"); } pub mod ext { - #[allow(unused_imports)] use super::*; + #[allow(unused_imports)] + use super::*; include!("log.v1.log.__ext.rs"); } } diff --git a/examples/logging/src/gen/context.v1.context.__ext.rs b/examples/logging/src/gen/context.v1.context.__ext.rs index a2d385a..e2f49b7 100644 --- a/examples/logging/src/gen/context.v1.context.__ext.rs +++ b/examples/logging/src/gen/context.v1.context.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: context/v1/context.proto diff --git a/examples/logging/src/gen/context.v1.context.__oneof.rs b/examples/logging/src/gen/context.v1.context.__oneof.rs index a2d385a..e2f49b7 100644 --- a/examples/logging/src/gen/context.v1.context.__oneof.rs +++ b/examples/logging/src/gen/context.v1.context.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: context/v1/context.proto diff --git a/examples/logging/src/gen/context.v1.context.__view.rs b/examples/logging/src/gen/context.v1.context.__view.rs index a2d385a..e2f49b7 100644 --- a/examples/logging/src/gen/context.v1.context.__view.rs +++ b/examples/logging/src/gen/context.v1.context.__view.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: context/v1/context.proto diff --git a/examples/logging/src/gen/context.v1.context.__view_oneof.rs b/examples/logging/src/gen/context.v1.context.__view_oneof.rs index a2d385a..e2f49b7 100644 --- a/examples/logging/src/gen/context.v1.context.__view_oneof.rs +++ b/examples/logging/src/gen/context.v1.context.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: context/v1/context.proto diff --git a/examples/logging/src/gen/context.v1.context.rs b/examples/logging/src/gen/context.v1.context.rs index c49f247..61a32da 100644 --- a/examples/logging/src/gen/context.v1.context.rs +++ b/examples/logging/src/gen/context.v1.context.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: context/v1/context.proto /// Contextual information about the request that produced a log entry. diff --git a/examples/logging/src/gen/log.v1.log.__ext.rs b/examples/logging/src/gen/log.v1.log.__ext.rs index 7e1bec0..9c15cdf 100644 --- a/examples/logging/src/gen/log.v1.log.__ext.rs +++ b/examples/logging/src/gen/log.v1.log.__ext.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: log/v1/log.proto diff --git a/examples/logging/src/gen/log.v1.log.__oneof.rs b/examples/logging/src/gen/log.v1.log.__oneof.rs index 7e1bec0..9c15cdf 100644 --- a/examples/logging/src/gen/log.v1.log.__oneof.rs +++ b/examples/logging/src/gen/log.v1.log.__oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: log/v1/log.proto diff --git a/examples/logging/src/gen/log.v1.log.__view.rs b/examples/logging/src/gen/log.v1.log.__view.rs index 7e1bec0..9c15cdf 100644 --- a/examples/logging/src/gen/log.v1.log.__view.rs +++ b/examples/logging/src/gen/log.v1.log.__view.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: log/v1/log.proto diff --git a/examples/logging/src/gen/log.v1.log.__view_oneof.rs b/examples/logging/src/gen/log.v1.log.__view_oneof.rs index 7e1bec0..9c15cdf 100644 --- a/examples/logging/src/gen/log.v1.log.__view_oneof.rs +++ b/examples/logging/src/gen/log.v1.log.__view_oneof.rs @@ -1,3 +1,3 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: log/v1/log.proto diff --git a/examples/logging/src/gen/log.v1.log.rs b/examples/logging/src/gen/log.v1.log.rs index 8053e95..9628502 100644 --- a/examples/logging/src/gen/log.v1.log.rs +++ b/examples/logging/src/gen/log.v1.log.rs @@ -1,4 +1,4 @@ -// @generated by protoc-gen-buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. // source: log/v1/log.proto /// Severity level for a log entry. diff --git a/examples/logging/src/gen/mod.rs b/examples/logging/src/gen/mod.rs index 71d73c6..e72944d 100644 --- a/examples/logging/src/gen/mod.rs +++ b/examples/logging/src/gen/mod.rs @@ -1,4 +1,4 @@ -// @generated by buffa. DO NOT EDIT. +// @generated by buffa-codegen. DO NOT EDIT. #![allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] diff --git a/protoc-gen-buffa-packaging/src/main.rs b/protoc-gen-buffa-packaging/src/main.rs index 34c3806..32c4c9d 100644 --- a/protoc-gen-buffa-packaging/src/main.rs +++ b/protoc-gen-buffa-packaging/src/main.rs @@ -132,7 +132,11 @@ fn generate(request: &CodeGeneratorRequest) -> Result Date: Thu, 23 Apr 2026 21:15:15 +0000 Subject: [PATCH 3/6] docs: replace re-export TODO with explicit no-re-exports rationale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The buffa_:: canonical path is intentionally the only path. Convenience re-exports would make short paths work in the common case but silently change meaning when a user proto shadows them — predictability over brevity. --- DESIGN.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 3d8a0b2..c377e3d 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -268,8 +268,7 @@ pub mod my_pkg { The per-proto content files mean editing one `.proto` regenerates only its five siblings (incremental friendly); the per-package stitcher means `register_types` is naturally one fn per package, so multi-file packages (e.g. seven WKT files in `google.protobuf`) no longer collide. - +**No convenience re-exports.** Short-path aliases like `pub use buffa_::view::*` at package level are deliberately not emitted. They would make `pkg::FooView` work in the common case but silently change meaning (or disappear) when a user-defined `message FooView` exists — a "clean 95% / surprising 5%" pattern that trades predictability for brevity. The canonical `buffa_::` path is the only path; it is unconditional. ### 3. MessageField\ — Ergonomic Optional Messages From 225f82697002bf8414ad3e92d1af62eb5ce674f6 Mon Sep 17 00:00:00 2001 From: Ryan Brewster Date: Thu, 23 Apr 2026 21:21:27 +0000 Subject: [PATCH 4/6] chore: polish docs/asserts on buffa_ sentinel codegen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - generate_module_tree: drop .unwrap() on infallible String fmt::Write; accept &[(impl AsRef, impl AsRef)] so callers pass owned vecs directly (drops the re-borrow shim in buffa-build and packaging) - GeneratedFile / GeneratedFileKind / include_proto! docs: clarify that consumers wire up only PackageMod entries and that $pkg is the dotted proto package literal (empty package → "buffa_") - emit_register_fn doc: reflect per-package stitcher emission (the old multi-file collision rationale is obsolete) - ancillary_prefix: debug_assert dotless-FQN convention + doc note - RegistryPaths::is_empty: one-line doc --- buffa-build/src/lib.rs | 6 +-- buffa-codegen/src/context.rs | 8 ++++ buffa-codegen/src/lib.rs | 54 ++++++++++++++++---------- buffa-codegen/src/message.rs | 2 + buffa/src/lib.rs | 15 +++++-- protoc-gen-buffa-packaging/src/main.rs | 6 +-- 6 files changed, 57 insertions(+), 34 deletions(-) diff --git a/buffa-build/src/lib.rs b/buffa-build/src/lib.rs index 60691e7..5b8c1e4 100644 --- a/buffa-build/src/lib.rs +++ b/buffa-build/src/lib.rs @@ -816,10 +816,6 @@ fn proto_relative_name(file: &Path, includes: &[PathBuf]) -> String { /// instead of the `env!("OUT_DIR")` prefix, so the include file works when /// checked into the source tree and referenced via `mod`. fn generate_include_file(entries: &[(String, String)], relative: bool) -> String { - let borrowed: Vec<(&str, &str)> = entries - .iter() - .map(|(f, p)| (f.as_str(), p.as_str())) - .collect(); let mode = if relative { buffa_codegen::IncludeMode::Relative("") } else { @@ -827,7 +823,7 @@ fn generate_include_file(entries: &[(String, String)], relative: bool) -> String }; // Inner-allow off: this output is consumed via `include!` from // user-authored `lib.rs`, where `#![allow(...)]` is not valid. - buffa_codegen::generate_module_tree(&borrowed, mode, false) + buffa_codegen::generate_module_tree(entries, mode, false) } #[cfg(test)] diff --git a/buffa-codegen/src/context.rs b/buffa-codegen/src/context.rs index 5b2abe1..4ecbd08 100644 --- a/buffa-codegen/src/context.rs +++ b/buffa-codegen/src/context.rs @@ -565,6 +565,9 @@ impl AncillaryKind { /// package root (message-nesting plus any `buffa_::::` levels the /// caller is already inside). /// +/// `proto_fqn` follows the dotless convention used throughout codegen +/// (e.g. `"google.protobuf.Value"`, not `".google.protobuf.Value"`). +/// /// Returned tokens always end with `::` so callers append the type /// identifier directly: `quote! { #prefix #ident }`. pub(crate) fn ancillary_prefix( @@ -576,6 +579,11 @@ pub(crate) fn ancillary_prefix( use crate::idents::make_field_ident; use quote::quote; + debug_assert!( + !proto_fqn.starts_with('.'), + "ancillary_prefix expects dotless FQN, got {proto_fqn:?}" + ); + let mut supers_tokens = proc_macro2::TokenStream::new(); for _ in 0..from_nesting { supers_tokens.extend(quote! { super:: }); diff --git a/buffa-codegen/src/lib.rs b/buffa-codegen/src/lib.rs index bc67350..0a7ca6c 100644 --- a/buffa-codegen/src/lib.rs +++ b/buffa-codegen/src/lib.rs @@ -72,6 +72,12 @@ pub fn allow_lints_attr() -> TokenStream { /// `.mod.rs` **stitcher** that `include!`s the content files /// and authors the `pub mod buffa_ { … }` ancillary tree. /// See `DESIGN.md` → "Generated code layout". +/// +/// Consumers normally only need to wire up the +/// [`GeneratedFileKind::PackageMod`] entries (one per package); the five +/// per-proto content kinds are reached transitively via `include!` from +/// the stitcher. Write all files to disk; build a module tree from only +/// the `PackageMod` ones. #[derive(Debug)] pub struct GeneratedFile { /// The output file path (e.g., `"my.pkg.foo.rs"` or `"my.pkg.mod.rs"`). @@ -88,6 +94,10 @@ pub struct GeneratedFile { /// Kind of [`GeneratedFile`]. The five content kinds are 1:1 with input /// `.proto` files; `PackageMod` is 1:1 with packages. +/// +/// Build integrations only need to wire up [`PackageMod`](Self::PackageMod) +/// entries — the per-proto content kinds are reached via `include!` from +/// the stitcher and need only be written to disk alongside it. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GeneratedFileKind { /// Owned message structs and enums (`.rs`). @@ -183,14 +193,16 @@ pub struct CodeGenConfig { /// When this is `true`, the downstream crate must enable the `buffa/text` /// feature for the runtime encoder/decoder. pub generate_text: bool, - /// Whether to emit the file-level `register_types(&mut TypeRegistry)` fn. + /// Whether the per-package `.mod.rs` stitcher emits + /// `buffa_::register_types(&mut TypeRegistry)`. /// - /// Default `true`. Set to `false` when multiple generated files are - /// `include!`d into the same namespace (the identically-named fns would - /// collide) — e.g. `buffa-types`' WKTs, which hand-roll - /// `register_wkt_types` instead. The per-message `__*_JSON_ANY` / - /// `__*_TEXT_ANY` consts are still emitted; only the aggregating fn - /// is suppressed. + /// Default `true`. The fn aggregates `Any` type entries and extension + /// entries for every message in the package. Set to `false` for + /// crates that don't use extensions/`Any`, or that hand-roll + /// registration (e.g. `buffa-types`' `register_wkt_types`, which + /// knows the JSON-Any `is_wkt` special-casing the generic fn does + /// not). The per-message `__*_JSON_ANY` / `__*_TEXT_ANY` consts are + /// still emitted; only the aggregating fn is suppressed. pub emit_register_fn: bool, /// Custom attributes to inject on generated types (messages and enums). /// @@ -337,8 +349,8 @@ pub fn generate( /// `emit_inner_allow` adds a `#![allow(...)]` inner attribute at the top — /// valid when the output is used directly as a module file (`mod.rs`), /// invalid when consumed via `include!`. -pub fn generate_module_tree( - entries: &[(&str, &str)], +pub fn generate_module_tree, P: AsRef>( + entries: &[(F, P)], include_mode: IncludeMode<'_>, emit_inner_allow: bool, ) -> String { @@ -356,6 +368,7 @@ pub fn generate_module_tree( let mut root = ModNode::default(); for (file_name, package) in entries { + let package = package.as_ref(); let pkg_parts: Vec<&str> = if package.is_empty() { vec![] } else { @@ -366,16 +379,16 @@ pub fn generate_module_tree( for seg in &pkg_parts { node = node.children.entry(seg.to_string()).or_default(); } - node.files.push(file_name.to_string()); + node.files.push(file_name.as_ref().to_string()); } let lints = ALLOW_LINTS.join(", "); let mut out = String::new(); - writeln!(out, "// @generated by buffa-codegen. DO NOT EDIT.").unwrap(); + let _ = writeln!(out, "// @generated by buffa-codegen. DO NOT EDIT."); if emit_inner_allow { - writeln!(out, "#![allow({lints})]").unwrap(); + let _ = writeln!(out, "#![allow({lints})]"); } - writeln!(out).unwrap(); + let _ = writeln!(out); fn emit(out: &mut String, node: &ModNode, depth: usize, mode: IncludeMode<'_>, lints: &str) { let indent = " ".repeat(depth); @@ -383,25 +396,24 @@ pub fn generate_module_tree( for file in &node.files { match mode { IncludeMode::Relative(prefix) => { - writeln!(out, r#"{indent}include!("{prefix}{file}");"#).unwrap(); + let _ = writeln!(out, r#"{indent}include!("{prefix}{file}");"#); } IncludeMode::OutDir => { - writeln!( + let _ = writeln!( out, r#"{indent}include!(concat!(env!("OUT_DIR"), "/{file}"));"# - ) - .unwrap(); + ); } } } for (name, child) in &node.children { let escaped = escape_mod_ident(name); - writeln!(out, "{indent}#[allow({lints})]").unwrap(); - writeln!(out, "{indent}pub mod {escaped} {{").unwrap(); - writeln!(out, "{indent} use super::*;").unwrap(); + let _ = writeln!(out, "{indent}#[allow({lints})]"); + let _ = writeln!(out, "{indent}pub mod {escaped} {{"); + let _ = writeln!(out, "{indent} use super::*;"); emit(out, child, depth + 1, mode, lints); - writeln!(out, "{indent}}}").unwrap(); + let _ = writeln!(out, "{indent}}}"); } } diff --git a/buffa-codegen/src/message.rs b/buffa-codegen/src/message.rs index 9df609f..f305d06 100644 --- a/buffa-codegen/src/message.rs +++ b/buffa-codegen/src/message.rs @@ -28,6 +28,8 @@ pub(crate) struct RegistryPaths { } impl RegistryPaths { + /// True when no entries were collected — gates whether the package + /// stitcher emits `register_types` at all. pub(crate) fn is_empty(&self) -> bool { self.json_any.is_empty() && self.text_any.is_empty() diff --git a/buffa/src/lib.rs b/buffa/src/lib.rs index 60c5e6c..7de691a 100644 --- a/buffa/src/lib.rs +++ b/buffa/src/lib.rs @@ -124,15 +124,20 @@ pub use ::bytes; /// per-proto content files and authors the `buffa_::{view, oneof, ext}` /// ancillary tree, so a single macro call brings in everything. /// +/// `$pkg` is the **dotted proto package literal** exactly as it appears +/// in the `.proto`'s `package` declaration (e.g. `"google.protobuf"`, +/// not a Rust path or the `.proto` file path). For protos with no +/// `package` declaration, pass `"buffa_"` (the reserved sentinel; no +/// real package can use it). +/// /// ```ignore /// pub mod my_pkg { /// buffa::include_proto!("my.pkg"); /// } /// ``` /// -/// For the unnamed package, pass `"buffa_"` (the reserved sentinel — no -/// real package can use it). For checked-in generated code (no -/// `OUT_DIR`), use [`include_proto_relative!`]. +/// For checked-in generated code (no `OUT_DIR`), use +/// [`include_proto_relative!`]. #[macro_export] macro_rules! include_proto { ($pkg:literal) => { @@ -144,6 +149,10 @@ macro_rules! include_proto { /// reading `OUT_DIR` — for crates that check generated code into the /// source tree (e.g. `buffa-types`, `buffa-descriptor`). /// +/// `$pkg` is the dotted proto package literal exactly as in the +/// `.proto`'s `package` declaration; for the unnamed package pass +/// `"buffa_"`. `$dir` is relative to the calling source file. +/// /// ```ignore /// pub mod protobuf { /// buffa::include_proto_relative!("generated", "google.protobuf"); diff --git a/protoc-gen-buffa-packaging/src/main.rs b/protoc-gen-buffa-packaging/src/main.rs index 32c4c9d..01b45fa 100644 --- a/protoc-gen-buffa-packaging/src/main.rs +++ b/protoc-gen-buffa-packaging/src/main.rs @@ -128,12 +128,8 @@ fn generate(request: &CodeGeneratorRequest) -> Result = entries - .iter() - .map(|(f, p)| (f.as_str(), p.as_str())) - .collect(); let content = buffa_codegen::generate_module_tree( - &borrowed, + &entries, buffa_codegen::IncludeMode::Relative(""), true, ); From 98a71ee2b9c043f522d47adf8d19cccca1b37dbf Mon Sep 17 00:00:00 2001 From: Ryan Brewster Date: Thu, 23 Apr 2026 21:39:00 +0000 Subject: [PATCH 5/6] fix: reject file-level enum named buffa_; refresh packaging plugin doc validate_file checked package segments and message names against the reserved sentinel but not file-level enum names. Enum type names are emitted verbatim at package root, so `enum buffa_ { ... }` would land beside `pub mod buffa_` (E0428). Nested enums live inside their owner's module and cannot collide, so only file-level is checked. Adds two naming.rs tests (rejected file-level / allowed nested). Also: protoc-gen-buffa-packaging module doc still described per-file output and referenced the removed proto_path_to_rust_module; rewrite for the per-package .mod.rs stitcher model. --- DESIGN.md | 2 +- buffa-codegen/src/lib.rs | 33 ++++++++++++----- buffa-codegen/src/tests/naming.rs | 49 ++++++++++++++++++++++++++ protoc-gen-buffa-packaging/src/main.rs | 45 ++++++++++++----------- 4 files changed, 96 insertions(+), 33 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index c377e3d..e3e12a3 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -227,7 +227,7 @@ println!("name: {}", view.name); // Deref, zero-copy, 'static + Send **Generated code layout — the `buffa_::` sentinel tree:** -Ancillary generated items (views, oneof enums, file-level extensions, the per-package `register_types` fn) live under a single reserved module per package — `buffa_::` — instead of being interleaved with owned types. The sentinel is the **only** name buffa reserves in user namespace; codegen errors with `ReservedModuleName` if a proto package segment or message name would snake_case to `buffa_`. +Ancillary generated items (views, oneof enums, file-level extensions, the per-package `register_types` fn) live under a single reserved module per package — `buffa_::` — instead of being interleaved with owned types. The sentinel is the **only** name buffa reserves in user namespace; codegen errors with `ReservedModuleName` if a proto package segment, message name, or file-level enum name would emit a `buffa_` item at package root. ```text ::Foo # owned struct (unchanged) diff --git a/buffa-codegen/src/lib.rs b/buffa-codegen/src/lib.rs index 0a7ca6c..3e0581e 100644 --- a/buffa-codegen/src/lib.rs +++ b/buffa-codegen/src/lib.rs @@ -439,11 +439,12 @@ pub enum IncludeMode<'a> { /// with generated `__buffa_unknown_fields` / `__buffa_cached_size`). /// - **Module-name conflicts**: no two sibling messages snake_case to the /// same module name (e.g. `HTTPRequest` vs `HttpRequest`). -/// - **Reserved sentinel**: no package segment or message-module name -/// equals [`SENTINEL_MOD`](context::SENTINEL_MOD). Ancillary types live -/// under `pkg::buffa_::…`; a proto element emitting `pub mod buffa_` at -/// any level would produce E0428. This is the only name buffa reserves -/// in user namespace. +/// - **Reserved sentinel**: no package segment, message-module name, or +/// file-level enum name equals [`SENTINEL_MOD`](context::SENTINEL_MOD). +/// Ancillary types live under `pkg::buffa_::…`; a proto element +/// emitting an item named `buffa_` at package root would produce +/// E0428 against `pub mod buffa_`. This is the only name buffa +/// reserves in user namespace. fn validate_file(file: &FileDescriptorProto) -> Result<(), CodeGenError> { use std::collections::HashMap; @@ -455,6 +456,20 @@ fn validate_file(file: &FileDescriptorProto) -> Result<(), CodeGenError> { location: format!("package '{package}'"), }); } + // File-level enums emit `pub enum ` at package root with the + // proto name preserved verbatim (no PascalCase normalization), so a + // proto `enum buffa_` would land beside `pub mod buffa_`. Nested + // enums live inside their owner message's module and cannot collide + // with the package-root sentinel, so only file-level is checked. + for enum_type in &file.enum_type { + let name = enum_type.name.as_deref().unwrap_or(""); + if name == sentinel { + return Err(CodeGenError::ReservedModuleName { + name: sentinel.to_string(), + location: format!("enum '{package}.{name}'"), + }); + } + } fn walk( messages: &[crate::generated::descriptor::DescriptorProto], @@ -861,14 +876,14 @@ pub enum CodeGenError { name_b: String, module_name: String, }, - /// A proto package segment or message name would emit a Rust module - /// matching the reserved sentinel `buffa_`. + /// A proto package segment, message name, or file-level enum name + /// would emit a Rust item matching the reserved sentinel `buffa_`. /// /// This is the only name buffa reserves in user namespace. Resolve by /// renaming the proto element. #[error( - "reserved module name '{name}' at {location}: this name is reserved \ - for buffa's generated ancillary types (views, oneof enums, \ + "reserved name '{name}' at {location}: this name is reserved for \ + buffa's generated ancillary types (views, oneof enums, \ extensions). Rename the proto element." )] ReservedModuleName { name: String, location: String }, diff --git a/buffa-codegen/src/tests/naming.rs b/buffa-codegen/src/tests/naming.rs index d876e46..d46eb09 100644 --- a/buffa-codegen/src/tests/naming.rs +++ b/buffa-codegen/src/tests/naming.rs @@ -406,6 +406,55 @@ fn test_reserved_sentinel_message_name_rejected() { assert!(msg.contains("pkg.Buffa_"), "error should locate it: {msg}"); } +#[test] +fn test_reserved_sentinel_file_level_enum_rejected() { + // File-level `enum buffa_` emits `pub enum buffa_` at package root — + // E0428 against `pub mod buffa_`. Nested enums (inside a message) + // live in the owner's module and cannot collide, so are not checked. + let mut file = proto3_file("test.proto"); + file.package = Some("pkg".to_string()); + file.enum_type = vec![EnumDescriptorProto { + name: Some("buffa_".to_string()), + value: vec![enum_value("V", 0)], + ..Default::default() + }]; + let err = generate( + &[file], + &["test.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect_err("file-level enum buffa_ must be rejected"); + assert!( + matches!(err, CodeGenError::ReservedModuleName { .. }), + "expected ReservedModuleName, got {err:?}" + ); + let msg = err.to_string(); + assert!(msg.contains("enum 'pkg.buffa_'"), "should locate it: {msg}"); +} + +#[test] +fn test_nested_enum_named_buffa_allowed() { + // Nested enums emit inside the owner message's module, not at + // package root, so `Foo { enum buffa_ }` is fine. + let mut file = proto3_file("test.proto"); + file.package = Some("pkg".to_string()); + file.message_type = vec![DescriptorProto { + name: Some("Foo".to_string()), + enum_type: vec![EnumDescriptorProto { + name: Some("buffa_".to_string()), + value: vec![enum_value("V", 0)], + ..Default::default() + }], + ..Default::default() + }]; + generate( + &[file], + &["test.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect("nested enum buffa_ should be allowed"); +} + #[test] fn test_proto3_optional_field_name_matches_nested_enum_no_conflict() { // Proto3 `optional MatchOperator match_operator = 4;` creates a synthetic diff --git a/protoc-gen-buffa-packaging/src/main.rs b/protoc-gen-buffa-packaging/src/main.rs index 01b45fa..3e6944f 100644 --- a/protoc-gen-buffa-packaging/src/main.rs +++ b/protoc-gen-buffa-packaging/src/main.rs @@ -1,15 +1,13 @@ -//! protoc-gen-buffa-packaging — emits a `mod.rs` module tree for buffa-style -//! per-file output. +//! protoc-gen-buffa-packaging — emits a `mod.rs` module tree for buffa's +//! per-package `.mod.rs` stitcher output. //! -//! This plugin reads the proto package structure (not message/service bodies) -//! and writes a `mod.rs` that `include!`s each generated file at the right -//! module nesting. Requires `strategy: all` so the plugin sees the full file -//! set in a single invocation. -//! -//! Works with any codegen plugin that emits per-file output named via -//! [`buffa_codegen::proto_path_to_rust_module`] (`foo/v1/bar.proto` → -//! `foo.v1.bar.rs`). This includes `protoc-gen-buffa` itself and plugins -//! layered on top of it. +//! This plugin reads the proto package structure (not message/service +//! bodies) and writes a `mod.rs` that `include!`s each per-package +//! stitcher (see [`buffa_codegen::package_to_mod_filename`]) at the right +//! module nesting. The per-proto content files are reached transitively +//! via `include!` from the stitchers, so this plugin only wires up one +//! file per package. Requires `strategy: all` so the plugin sees the full +//! file set in a single invocation. //! //! # buf.gen.yaml //! @@ -29,9 +27,9 @@ //! //! # Options //! -//! - `filter=services` — only include proto files that declare at least one -//! `service`. Useful when packaging output from a service-stub generator -//! that skips files without services. +//! - `filter=services` — only include packages where at least one +//! `.proto` declares a `service`. Useful when packaging output from a +//! service-stub generator that skips files without services. //! //! Invoke the plugin once per output tree — use multiple entries in //! buf.gen.yaml with different `out:` directories and filters to package @@ -39,16 +37,17 @@ //! //! # Matching a codegen plugin's output set //! -//! This plugin cannot see the filesystem — it derives the set of files to -//! `include!` from `file_to_generate` and the chosen filter. The filter -//! must produce the same set the codegen plugin actually emitted, or the -//! `mod.rs` will reference nonexistent files (or miss real ones). +//! This plugin cannot see the filesystem — it derives the set of packages +//! to `include!` from `file_to_generate` and the chosen filter. The +//! filter must produce the same set the codegen plugin actually emitted, +//! or the `mod.rs` will reference nonexistent stitchers (or miss real +//! ones). //! -//! `protoc-gen-buffa` emits one file per proto file unconditionally, so no -//! filter is needed. A service-stub generator that skips files without a -//! `service` declaration needs `filter=services`. If a codegen plugin's -//! skip condition is not expressible as a predicate on `FileDescriptorProto`, -//! it is not packageable by this plugin. +//! `protoc-gen-buffa` emits a stitcher for every package unconditionally, +//! so no filter is needed. A service-stub generator that skips packages +//! without a `service` declaration needs `filter=services`. If a codegen +//! plugin's skip condition is not expressible as a predicate on +//! `FileDescriptorProto`, it is not packageable by this plugin. use std::io::{self, Read, Write}; From 4bd7a6ac790e31d90ad679d39c7d789fbd621798 Mon Sep 17 00:00:00 2001 From: Iain McGinniss <309153+iainmcgin@users.noreply.github.com> Date: Thu, 23 Apr 2026 22:21:05 +0000 Subject: [PATCH 6/6] Rename sentinel module buffa_ -> __buffa Aligns the sentinel with the existing reserved field-name prefix (__buffa_cached_size, __buffa_unknown_fields) so the rule is uniformly "anything starting __buffa is reserved by codegen". The trailing- underscore form was a distinct second pattern. Mechanical rename via SENTINEL_MOD constant; consumer paths and doc strings updated. Validator inputs adjusted (`__Buffa` snake_cases to `__buffa`; `Buffa_` no longer does). Adds two regression tests: - generation.rs: `package foo` + `package foo.view` produces two stitchers with the kind tree under __buffa, not as a top-level `pub mod view` sibling. - prelude_shadow.proto: `message View { Inner }` compiles end-to-end. Regenerated WKT, bootstrap descriptor, and logging-example checked-in code. --- DESIGN.md | 22 +++--- benchmarks/buffa/benches/protobuf.rs | 4 +- benchmarks/gen-datasets/src/main.rs | 2 +- buffa-codegen/src/context.rs | 22 +++--- buffa-codegen/src/lib.rs | 23 +++--- buffa-codegen/src/message.rs | 10 +-- buffa-codegen/src/oneof.rs | 6 +- buffa-codegen/src/tests/generation.rs | 71 +++++++++++++++++-- buffa-codegen/src/tests/naming.rs | 47 ++++++------ buffa-codegen/src/tests/view_codegen.rs | 4 +- buffa-codegen/src/view.rs | 12 ++-- buffa-codegen/tests/codegen_integration.rs | 4 +- .../generated/google.protobuf.compiler.mod.rs | 5 +- .../src/generated/google.protobuf.mod.rs | 5 +- buffa-test/protos/prelude_shadow.proto | 11 +++ buffa-test/src/tests/basic.rs | 2 +- buffa-test/src/tests/bytes_type.rs | 6 +- buffa-test/src/tests/closed_enum.rs | 10 +-- buffa-test/src/tests/collision.rs | 12 ++-- buffa-test/src/tests/extensions.rs | 4 +- buffa-test/src/tests/extensions_json.rs | 4 +- buffa-test/src/tests/json.rs | 14 ++-- buffa-test/src/tests/keyword.rs | 4 +- buffa-test/src/tests/message_set.rs | 2 +- buffa-test/src/tests/nesting.rs | 58 +++++++-------- buffa-test/src/tests/proto2.rs | 12 ++-- buffa-test/src/tests/proto3_semantics.rs | 10 +-- buffa-test/src/tests/textproto.rs | 10 +-- buffa-test/src/tests/utf8_validation.rs | 6 +- buffa-test/src/tests/view.rs | 8 +-- buffa-test/src/tests/wkt.rs | 4 +- .../src/generated/google.protobuf.mod.rs | 5 +- .../google.protobuf.struct.__view.rs | 60 +++++++++------- .../google.protobuf.struct.__view_oneof.rs | 4 +- .../src/generated/google.protobuf.struct.rs | 70 +++++++++--------- buffa-types/src/timestamp_ext.rs | 2 +- buffa-types/src/value_ext.rs | 2 +- buffa-types/tests/wkt_roundtrip.rs | 2 +- buffa/src/lib.rs | 6 +- conformance/src/main.rs | 18 ++--- examples/addressbook/src/main.rs | 2 +- examples/envelope/src/main.rs | 4 +- .../src/gen/buffa.examples.context.v1.mod.rs | 5 +- .../src/gen/buffa.examples.log.v1.mod.rs | 5 +- examples/logging/src/gen/mod.rs | 14 ++-- 45 files changed, 353 insertions(+), 260 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index e3e12a3..2283d44 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -225,22 +225,22 @@ let view = OwnedView::::decode(bytes)?; println!("name: {}", view.name); // Deref, zero-copy, 'static + Send ``` -**Generated code layout — the `buffa_::` sentinel tree:** +**Generated code layout — the `__buffa::` sentinel tree:** -Ancillary generated items (views, oneof enums, file-level extensions, the per-package `register_types` fn) live under a single reserved module per package — `buffa_::` — instead of being interleaved with owned types. The sentinel is the **only** name buffa reserves in user namespace; codegen errors with `ReservedModuleName` if a proto package segment, message name, or file-level enum name would emit a `buffa_` item at package root. +Ancillary generated items (views, oneof enums, file-level extensions, the per-package `register_types` fn) live under a single reserved module per package — `__buffa::` — instead of being interleaved with owned types. The sentinel is the **only** name buffa reserves in user namespace; codegen errors with `ReservedModuleName` if a proto package segment, message name, or file-level enum name would emit a `__buffa` item at package root. ```text ::Foo # owned struct (unchanged) ::foo::Bar # nested owned (unchanged) -::buffa_::view::FooView<'a> # view struct -::buffa_::view::foo::BarView<'a> # nested view (mirrors owned tree) -::buffa_::view::oneof::foo::Kind<'a> # view oneof enum (no suffix) -::buffa_::oneof::foo::Kind # owned oneof enum (no suffix) -::buffa_::ext::MY_EXT # file-level extension const -::buffa_::register_types(…) # one fn per package +::__buffa::view::FooView<'a> # view struct +::__buffa::view::foo::BarView<'a> # nested view (mirrors owned tree) +::__buffa::view::oneof::foo::Kind<'a> # view oneof enum (no suffix) +::__buffa::oneof::foo::Kind # owned oneof enum (no suffix) +::__buffa::ext::MY_EXT # file-level extension const +::__buffa::register_types(…) # one fn per package ``` -Oneof and view-oneof enums drop the `Oneof`/`View` suffix — the tree position disambiguates. View structs keep the `View` suffix because owned and view types are routinely co-imported (`use pkg::{Foo, buffa_::view::FooView}`). +Oneof and view-oneof enums drop the `Oneof`/`View` suffix — the tree position disambiguates. View structs keep the `View` suffix because owned and view types are routinely co-imported (`use pkg::{Foo, __buffa::view::FooView}`). This makes name collisions **structurally impossible**: a oneof `kind` and a nested message `Kind` can coexist because they land in different trees. There is no suffix-escalation or rename escape hatch; codegen emits proto names verbatim. @@ -256,7 +256,7 @@ Each `.proto` emits five sibling content files into `OUT_DIR`: | `.__view_oneof.rs` | View oneof enums | | `.__ext.rs` | File-level extension consts | -Each proto **package** additionally emits one `.mod.rs` stitcher that `include!`s the content files and authors the `pub mod buffa_ { … }` wrapper. Consumers wire up only the stitcher: +Each proto **package** additionally emits one `.mod.rs` stitcher that `include!`s the content files and authors the `pub mod __buffa { … }` wrapper. Consumers wire up only the stitcher: ```rust,ignore pub mod my_pkg { @@ -268,7 +268,7 @@ pub mod my_pkg { The per-proto content files mean editing one `.proto` regenerates only its five siblings (incremental friendly); the per-package stitcher means `register_types` is naturally one fn per package, so multi-file packages (e.g. seven WKT files in `google.protobuf`) no longer collide. -**No convenience re-exports.** Short-path aliases like `pub use buffa_::view::*` at package level are deliberately not emitted. They would make `pkg::FooView` work in the common case but silently change meaning (or disappear) when a user-defined `message FooView` exists — a "clean 95% / surprising 5%" pattern that trades predictability for brevity. The canonical `buffa_::` path is the only path; it is unconditional. +**No convenience re-exports.** Short-path aliases like `pub use __buffa::view::*` at package level are deliberately not emitted. They would make `pkg::FooView` work in the common case but silently change meaning (or disappear) when a user-defined `message FooView` exists — a "clean 95% / surprising 5%" pattern that trades predictability for brevity. The canonical `__buffa::` path is the only path; it is unconditional. ### 3. MessageField\ — Ergonomic Optional Messages diff --git a/benchmarks/buffa/benches/protobuf.rs b/benchmarks/buffa/benches/protobuf.rs index 4f2693e..617020e 100644 --- a/benchmarks/buffa/benches/protobuf.rs +++ b/benchmarks/buffa/benches/protobuf.rs @@ -2,10 +2,10 @@ use buffa::{Message, MessageView}; use criterion::{criterion_group, criterion_main, Criterion, Throughput}; use serde::{de::DeserializeOwned, Serialize}; -use bench_buffa::bench::buffa_::view::*; +use bench_buffa::bench::__buffa::view::*; use bench_buffa::bench::*; use bench_buffa::benchmarks::BenchmarkDataset; -use bench_buffa::proto3::buffa_::view::GoogleMessage1View; +use bench_buffa::proto3::__buffa::view::GoogleMessage1View; fn load_dataset(data: &[u8]) -> BenchmarkDataset { BenchmarkDataset::decode_from_slice(data).expect("failed to decode dataset") diff --git a/benchmarks/gen-datasets/src/main.rs b/benchmarks/gen-datasets/src/main.rs index 0c5eb7f..ca00d81 100644 --- a/benchmarks/gen-datasets/src/main.rs +++ b/benchmarks/gen-datasets/src/main.rs @@ -34,7 +34,7 @@ mod dataset_proto { } use proto::analytics_event::{Nested, Property}; -use proto::buffa_::oneof::analytics_event::property::Value; +use proto::__buffa::oneof::analytics_event::property::Value; use proto::log_record::Context; use proto::*; diff --git a/buffa-codegen/src/context.rs b/buffa-codegen/src/context.rs index 4ecbd08..3d3940e 100644 --- a/buffa-codegen/src/context.rs +++ b/buffa-codegen/src/context.rs @@ -13,13 +13,13 @@ use crate::CodeGenConfig; /// See `DESIGN.md` → "Generated code layout" for the full layout. The name /// is checked against proto package segments and message-module names by /// [`crate::validate_file`]; a collision is a hard error. -pub const SENTINEL_MOD: &str = "buffa_"; +pub const SENTINEL_MOD: &str = "__buffa"; /// A Rust type path split at the target-package boundary. /// /// Returned by [`CodeGenContext::rust_type_relative_split`]. The full owned /// path is `to_package + within_package` (concatenated with `::`); ancillary -/// kinds insert their `buffa_::::` prefix between the two halves. +/// kinds insert their `__buffa::::` prefix between the two halves. #[derive(Debug, Clone)] pub struct SplitPath { /// Path from the current emission scope to the **target package root**. @@ -322,14 +322,14 @@ impl<'a> CodeGenContext<'a> { /// Like [`rust_type_relative`](Self::rust_type_relative) but returns the /// path split at the target-package boundary. /// - /// Ancillary kinds (views, oneof enums) live in the `buffa_::::` + /// Ancillary kinds (views, oneof enums) live in the `__buffa::::` /// sub-tree of each package; callers compose the final path as - /// `to_package + "::buffa_::" + + "::" + within_package`. + /// `to_package + "::__buffa::" + + "::" + within_package`. /// /// `nesting` is the **total** module depth of the caller's emission /// scope below the current package root — i.e. message-nesting plus any - /// `buffa_::::` levels the caller is already inside (0 for owned - /// types, +2 for `buffa_::view::`, +3 for `buffa_::view::oneof::`). + /// `__buffa::::` levels the caller is already inside (0 for owned + /// types, +2 for `__buffa::view::`, +3 for `__buffa::view::oneof::`). pub fn rust_type_relative_split( &self, proto_fqn: &str, @@ -537,13 +537,13 @@ impl<'a> MessageScope<'a> { /// Kind of ancillary tree under the [`SENTINEL_MOD`] module. /// -/// `path_segments()` returns the module path *inside* `buffa_::` (not +/// `path_segments()` returns the module path *inside* `__buffa::` (not /// including the sentinel itself). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum AncillaryKind { - /// `buffa_::oneof::::` — owned oneof enums. + /// `__buffa::oneof::::` — owned oneof enums. Oneof, - /// `buffa_::view::oneof::::` — view oneof enums. + /// `__buffa::view::oneof::::` — view oneof enums. ViewOneof, } @@ -560,9 +560,9 @@ impl AncillaryKind { /// kind's location for the **current** message (`proto_fqn`). /// /// Always climbs to the package root via `super::` and re-descends through -/// `buffa_::::::` — uniform regardless of where the caller +/// `__buffa::::::` — uniform regardless of where the caller /// sits. `from_nesting` is the caller's total module depth below the -/// package root (message-nesting plus any `buffa_::::` levels the +/// package root (message-nesting plus any `__buffa::::` levels the /// caller is already inside). /// /// `proto_fqn` follows the dotless convention used throughout codegen diff --git a/buffa-codegen/src/lib.rs b/buffa-codegen/src/lib.rs index 3e0581e..d290e63 100644 --- a/buffa-codegen/src/lib.rs +++ b/buffa-codegen/src/lib.rs @@ -53,6 +53,9 @@ pub const ALLOW_LINTS: &[&str] = &[ "clippy::match_single_binding", "clippy::uninlined_format_args", "clippy::doc_lazy_continuation", + // A user `message View { message Inner }` produces + // `__buffa::view::view::InnerView`; harmless but trips this lint. + "clippy::module_inception", ]; /// Render [`ALLOW_LINTS`] as a `#[allow(…)]` attribute token stream. @@ -70,7 +73,7 @@ pub fn allow_lints_attr() -> TokenStream { /// `.__view.rs`, `.__oneof.rs`, `.__view_oneof.rs`, /// `.__ext.rs`) and each proto package produces one /// `.mod.rs` **stitcher** that `include!`s the content files -/// and authors the `pub mod buffa_ { … }` ancillary tree. +/// and authors the `pub mod __buffa { … }` ancillary tree. /// See `DESIGN.md` → "Generated code layout". /// /// Consumers normally only need to wire up the @@ -194,7 +197,7 @@ pub struct CodeGenConfig { /// feature for the runtime encoder/decoder. pub generate_text: bool, /// Whether the per-package `.mod.rs` stitcher emits - /// `buffa_::register_types(&mut TypeRegistry)`. + /// `__buffa::register_types(&mut TypeRegistry)`. /// /// Default `true`. The fn aggregates `Any` type entries and extension /// entries for every message in the package. Set to `false` for @@ -441,9 +444,9 @@ pub enum IncludeMode<'a> { /// same module name (e.g. `HTTPRequest` vs `HttpRequest`). /// - **Reserved sentinel**: no package segment, message-module name, or /// file-level enum name equals [`SENTINEL_MOD`](context::SENTINEL_MOD). -/// Ancillary types live under `pkg::buffa_::…`; a proto element -/// emitting an item named `buffa_` at package root would produce -/// E0428 against `pub mod buffa_`. This is the only name buffa +/// Ancillary types live under `pkg::__buffa::…`; a proto element +/// emitting an item named `__buffa` at package root would produce +/// E0428 against `pub mod __buffa`. This is the only name buffa /// reserves in user namespace. fn validate_file(file: &FileDescriptorProto) -> Result<(), CodeGenError> { use std::collections::HashMap; @@ -458,7 +461,7 @@ fn validate_file(file: &FileDescriptorProto) -> Result<(), CodeGenError> { } // File-level enums emit `pub enum ` at package root with the // proto name preserved verbatim (no PascalCase normalization), so a - // proto `enum buffa_` would land beside `pub mod buffa_`. Nested + // proto `enum __buffa` would land beside `pub mod __buffa`. Nested // enums live inside their owner message's module and cannot collide // with the package-root sentinel, so only file-level is checked. for enum_type in &file.enum_type { @@ -619,7 +622,7 @@ fn generate_proto_content( view_oneof.extend(msg_view_oneof); } - // File-level `extend` declarations → `buffa_::ext::` (depth 2). + // File-level `extend` declarations → `__buffa::ext::` (depth 2). let (file_ext_tokens, file_ext_json, file_ext_text) = extension::generate_extensions( ctx, &file.extension, @@ -656,7 +659,7 @@ fn generate_package( out: &mut Vec, ) -> Result<(), CodeGenError> { // Registry paths are package-root-relative; `register_types` lives at - // `buffa_::register_types` (one level deep), so each path gets a + // `__buffa::register_types` (one level deep), so each path gets a // single `super::` prefix when emitted into the fn body. let mut reg = message::RegistryPaths::default(); let mut stems: Vec = Vec::new(); @@ -809,7 +812,7 @@ fn format_tokens(tokens: TokenStream, source: &str) -> Result String { @@ -877,7 +880,7 @@ pub enum CodeGenError { module_name: String, }, /// A proto package segment, message name, or file-level enum name - /// would emit a Rust item matching the reserved sentinel `buffa_`. + /// would emit a Rust item matching the reserved sentinel `__buffa`. /// /// This is the only name buffa reserves in user namespace. Resolve by /// renaming the proto element. diff --git a/buffa-codegen/src/message.rs b/buffa-codegen/src/message.rs index f305d06..29f17aa 100644 --- a/buffa-codegen/src/message.rs +++ b/buffa-codegen/src/message.rs @@ -45,7 +45,7 @@ impl RegistryPaths { /// message `Foo` with nested `Bar` produces an `oneof_tree` containing /// `pub mod foo { /* Foo's oneofs */ pub mod bar { /* Bar's oneofs */ } }`. /// The package-level assembler in `lib.rs` places each tree under its -/// `buffa_::::` root. +/// `__buffa::::` root. #[derive(Default)] pub(crate) struct MessageOutput { /// Owned struct + impls — emitted at the message's owned-tree position. @@ -54,13 +54,13 @@ pub(crate) struct MessageOutput { /// emitted inside the message's `pub mod {name} {}` in the owned tree. pub owned_mod: TokenStream, /// Oneof enum definitions, wrapped in `pub mod {msg_name} { … }`. - /// Destined for `buffa_::oneof::`. + /// Destined for `__buffa::oneof::`. pub oneof_tree: TokenStream, /// View struct + impls, wrapped per-message-level. Destined for - /// `buffa_::view::`. + /// `__buffa::view::`. pub view_tree: TokenStream, /// Oneof view enum definitions, wrapped per-message-level. Destined - /// for `buffa_::view::oneof::`. + /// for `__buffa::view::oneof::`. pub view_oneof_tree: TokenStream, /// Registry const paths (relative to the package root). pub reg: RegistryPaths, @@ -198,7 +198,7 @@ fn generate_message_with_nesting( let oneof_idents = crate::oneof::resolve_oneof_idents(msg); // Path prefix from this struct's emission scope to its oneof enums at - // `buffa_::oneof::::`. The owned struct sits at `nesting` + // `__buffa::oneof::::`. The owned struct sits at `nesting` // levels below the package root. let oneof_prefix = ancillary_prefix(AncillaryKind::Oneof, current_package, proto_fqn, nesting); diff --git a/buffa-codegen/src/oneof.rs b/buffa-codegen/src/oneof.rs index 5d0f0c8..2da005d 100644 --- a/buffa-codegen/src/oneof.rs +++ b/buffa-codegen/src/oneof.rs @@ -106,7 +106,7 @@ fn collect_variant_info( // without codegen changes; only decode and JSON-deser need an // explicit Vec→Bytes conversion (see oneof_merge_arm and // oneof_variant_deser_arm). - // Oneof enums live at `buffa_::oneof::::`, which is + // Oneof enums live at `__buffa::oneof::::`, which is // `2 + (msg_nesting + 1)` levels below the package root // (sentinel + `oneof` + one snake-case segment per message in // the FQN path). `nesting` here is the owning message's @@ -487,7 +487,7 @@ pub(crate) fn oneof_variant_deser_arm(input: &OneofVariantDeserInput<'_>) -> Tok /// Build the Rust identifier for a oneof enum: `{PascalCase(oneof_name)}`. /// /// No suffix and no collision check — oneof enums live in the dedicated -/// `buffa_::oneof::::` tree where they cannot collide with nested +/// `__buffa::oneof::::` tree where they cannot collide with nested /// types, nested enums, or view structs. Two sibling oneofs would only /// produce the same ident if they share a proto name, which protoc /// rejects at parse time. @@ -499,7 +499,7 @@ fn oneof_enum_ident(oneof_name: &str) -> proc_macro2::Ident { /// /// Returns a map from oneof declaration index to its Rust enum `Ident`. /// Synthetic oneofs (proto3 `optional`) are omitted. Infallible: oneof -/// enums live in the `buffa_::oneof::` tree where collisions with +/// enums live in the `__buffa::oneof::` tree where collisions with /// nested types are structurally impossible. pub(crate) fn resolve_oneof_idents( msg: &DescriptorProto, diff --git a/buffa-codegen/src/tests/generation.rs b/buffa-codegen/src/tests/generation.rs index 53346a9..1379101 100644 --- a/buffa-codegen/src/tests/generation.rs +++ b/buffa-codegen/src/tests/generation.rs @@ -61,7 +61,7 @@ fn test_empty_file() { .iter() .find(|f| f.kind == GeneratedFileKind::PackageMod) .expect("stitcher present"); - assert_eq!(stitcher.name, "buffa_.mod.rs"); + assert_eq!(stitcher.name, "__buffa.mod.rs"); assert!( stitcher.content.contains("@generated"), "missing header comment" @@ -75,7 +75,7 @@ fn test_package_to_mod_filename() { "google.protobuf.mod.rs" ); assert_eq!(package_to_mod_filename("foo"), "foo.mod.rs"); - assert_eq!(package_to_mod_filename(""), "buffa_.mod.rs"); + assert_eq!(package_to_mod_filename(""), "__buffa.mod.rs"); assert_eq!( proto_path_to_stem("google/protobuf/timestamp.proto"), "google.protobuf.timestamp" @@ -113,13 +113,76 @@ fn test_multi_file_same_package_merged() { let content = &joined(&files); assert!(content.contains("pub struct A")); assert!(content.contains("pub struct B")); - // Exactly one `pub mod buffa_` (in the stitcher), and both content + // Exactly one `pub mod __buffa` (in the stitcher), and both content // files referenced from inside it. - assert_eq!(stitcher.content.matches("pub mod buffa_ {").count(), 1); + assert_eq!(stitcher.content.matches("pub mod __buffa {").count(), 1); assert!(stitcher.content.contains(r#"include!("a.__view.rs");"#)); assert!(stitcher.content.contains(r#"include!("b.__view.rs");"#)); } +#[test] +fn test_child_package_named_view_no_collision() { + // Regression: under the pre-sentinel design, `package foo.view` + // emitted `pub mod view { ... }` (child package) as a sibling of the + // kind-tree `pub mod view { ... }` inside `foo` — E0428. With the + // sentinel wrapper, the kind tree is `pub mod __buffa { pub mod view + // { ... } }`, so a child package literally named `view` is fine. + let mut a = proto3_file("a.proto"); + a.package = Some("foo".to_string()); + a.message_type.push(DescriptorProto { + name: Some("A".to_string()), + ..Default::default() + }); + let mut b = proto3_file("b.proto"); + b.package = Some("foo.view".to_string()); + b.message_type.push(DescriptorProto { + name: Some("B".to_string()), + ..Default::default() + }); + let files = generate( + &[a, b], + &["a.proto".to_string(), "b.proto".to_string()], + &CodeGenConfig::default(), + ) + .expect("`package foo.view` alongside `package foo` must compile"); + // One stitcher per package. + let stitchers: Vec<_> = files + .iter() + .filter(|f| f.kind == GeneratedFileKind::PackageMod) + .collect(); + assert_eq!(stitchers.len(), 2); + // Neither stitcher emits a bare `pub mod view {` at top level — the + // view kind tree is always nested under `pub mod __buffa {`. + for s in &stitchers { + let top_level_view = s + .content + .lines() + .any(|l| l.starts_with("pub mod view {") || l == "pub mod view {"); + assert!( + !top_level_view, + "stitcher {} must not emit top-level `pub mod view`: {}", + s.name, s.content + ); + assert!(s.content.contains("pub mod __buffa {")); + } + // The package tree assembled by `generate_module_tree` puts `view` as + // a child of `foo`, separate from `foo`'s `__buffa` wrapper. + let entries: Vec<_> = stitchers + .iter() + .map(|s| { + ( + s.name.clone(), + s.name.trim_end_matches(".mod.rs").to_string(), + ) + }) + .collect(); + let tree = crate::generate_module_tree(&entries, crate::IncludeMode::Relative(""), false); + assert!( + tree.contains("pub mod foo {") && tree.contains("pub mod view {"), + "tree must nest `view` under `foo`: {tree}" + ); +} + #[test] fn test_simple_enum() { let mut file = proto3_file("status.proto"); diff --git a/buffa-codegen/src/tests/naming.rs b/buffa-codegen/src/tests/naming.rs index d46eb09..a283c4d 100644 --- a/buffa-codegen/src/tests/naming.rs +++ b/buffa-codegen/src/tests/naming.rs @@ -142,7 +142,7 @@ fn test_different_snake_case_names_no_conflict() { #[test] fn test_nested_type_oneof_coexist_in_separate_trees() { // Nested message "MyField" and oneof "my_field" coexist structurally: - // the oneof enum lives at `buffa_::oneof::parent::MyField`, the nested + // the oneof enum lives at `__buffa::oneof::parent::MyField`, the nested // struct at `parent::MyField`. let msg = DescriptorProto { name: Some("Parent".to_string()), @@ -242,7 +242,7 @@ fn test_nested_enum_oneof_coexists_with_suffix() { let files = result.expect("nested enum + oneof same-name should coexist"); let content = &joined(&files); // Both `pub enum RegionCodes` declarations exist — one in the owned - // tree (the proto enum), one in `buffa_::oneof::` (the oneof enum). + // tree (the proto enum), one in `__buffa::oneof::` (the oneof enum). assert_eq!( content.matches("pub enum RegionCodes {").count(), 2, @@ -253,7 +253,7 @@ fn test_nested_enum_oneof_coexists_with_suffix() { #[test] fn test_sibling_oneof_view_names_do_not_collide() { // Two sibling oneofs `my_field` and `my_field_view`. Both live in - // `buffa_::oneof::parent::{MyField, MyFieldView}` — distinct because + // `__buffa::oneof::parent::{MyField, MyFieldView}` — distinct because // protoc rejects duplicate oneof names. let msg = DescriptorProto { name: Some("Parent".to_string()), @@ -304,7 +304,7 @@ fn test_sibling_oneof_view_names_do_not_collide() { #[test] fn test_foo_and_fooview_siblings_coexist() { - // Messages "Foo" and "FooView" — Foo's view (`buffa_::view::FooView`) + // Messages "Foo" and "FooView" — Foo's view (`__buffa::view::FooView`) // and the owned `FooView` struct (`pkg::FooView`) live in different // trees. Previously rejected via ViewNameConflict. let mut file = proto3_file("test.proto"); @@ -325,7 +325,7 @@ fn test_foo_and_fooview_siblings_coexist() { let files = result.expect("Foo + FooView siblings should coexist"); let content = &joined(&files); assert!(content.contains("pub struct Foo {")); - // pkg::FooView (owned) and buffa_::view::FooView<'a> (Foo's view). + // pkg::FooView (owned) and __buffa::view::FooView<'a> (Foo's view). assert!(content.contains("pub struct FooView {")); assert!(content.contains("pub struct FooView<'a>")); } @@ -334,7 +334,7 @@ fn test_foo_and_fooview_siblings_coexist() { fn test_top_level_message_named_view_compiles() { // Regression vs PR #54's bug: a top-level `message View { Inner }` // emits `pub mod view {}` (its nested-type module). Ancillary types - // live under `buffa_::view::`, NOT a bare `pub mod view {}`, so no + // live under `__buffa::view::`, NOT a bare `pub mod view {}`, so no // E0428. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); @@ -363,13 +363,13 @@ fn test_top_level_message_named_view_compiles() { let content = joined(&files); // The sentinel wraps the ancillary tree; the message's own // `pub mod view` (its nested-type module) is in the owned content. - assert!(content.contains("pub mod buffa_ {")); + assert!(content.contains("pub mod __buffa {")); } #[test] fn test_reserved_sentinel_package_segment_rejected() { let mut file = proto3_file("test.proto"); - file.package = Some("foo.buffa_".to_string()); + file.package = Some("foo.__buffa".to_string()); file.message_type = vec![DescriptorProto { name: Some("X".to_string()), ..Default::default() @@ -379,7 +379,7 @@ fn test_reserved_sentinel_package_segment_rejected() { &["test.proto".to_string()], &CodeGenConfig::default(), ) - .expect_err("buffa_ package segment must be rejected"); + .expect_err("__buffa package segment must be rejected"); assert!( matches!(err, CodeGenError::ReservedModuleName { .. }), "expected ReservedModuleName, got {err:?}" @@ -388,11 +388,11 @@ fn test_reserved_sentinel_package_segment_rejected() { #[test] fn test_reserved_sentinel_message_name_rejected() { - // Message name `Buffa_` snake_cases to `buffa_`. + // Message name `__Buffa` snake_cases to `__buffa`. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); file.message_type = vec![DescriptorProto { - name: Some("Buffa_".to_string()), + name: Some("__Buffa".to_string()), ..Default::default() }]; let err = generate( @@ -400,21 +400,21 @@ fn test_reserved_sentinel_message_name_rejected() { &["test.proto".to_string()], &CodeGenConfig::default(), ) - .expect_err("Buffa_ message name must be rejected"); + .expect_err("__Buffa message name must be rejected"); let msg = err.to_string(); - assert!(msg.contains("buffa_"), "error should name sentinel: {msg}"); - assert!(msg.contains("pkg.Buffa_"), "error should locate it: {msg}"); + assert!(msg.contains("__buffa"), "error should name sentinel: {msg}"); + assert!(msg.contains("pkg.__Buffa"), "error should locate it: {msg}"); } #[test] fn test_reserved_sentinel_file_level_enum_rejected() { - // File-level `enum buffa_` emits `pub enum buffa_` at package root — - // E0428 against `pub mod buffa_`. Nested enums (inside a message) + // File-level `enum __buffa` emits `pub enum __buffa` at package root — + // E0428 against `pub mod __buffa`. Nested enums (inside a message) // live in the owner's module and cannot collide, so are not checked. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); file.enum_type = vec![EnumDescriptorProto { - name: Some("buffa_".to_string()), + name: Some("__buffa".to_string()), value: vec![enum_value("V", 0)], ..Default::default() }]; @@ -423,25 +423,28 @@ fn test_reserved_sentinel_file_level_enum_rejected() { &["test.proto".to_string()], &CodeGenConfig::default(), ) - .expect_err("file-level enum buffa_ must be rejected"); + .expect_err("file-level enum __buffa must be rejected"); assert!( matches!(err, CodeGenError::ReservedModuleName { .. }), "expected ReservedModuleName, got {err:?}" ); let msg = err.to_string(); - assert!(msg.contains("enum 'pkg.buffa_'"), "should locate it: {msg}"); + assert!( + msg.contains("enum 'pkg.__buffa'"), + "should locate it: {msg}" + ); } #[test] fn test_nested_enum_named_buffa_allowed() { // Nested enums emit inside the owner message's module, not at - // package root, so `Foo { enum buffa_ }` is fine. + // package root, so `Foo { enum __buffa }` is fine. let mut file = proto3_file("test.proto"); file.package = Some("pkg".to_string()); file.message_type = vec![DescriptorProto { name: Some("Foo".to_string()), enum_type: vec![EnumDescriptorProto { - name: Some("buffa_".to_string()), + name: Some("__buffa".to_string()), value: vec![enum_value("V", 0)], ..Default::default() }], @@ -452,7 +455,7 @@ fn test_nested_enum_named_buffa_allowed() { &["test.proto".to_string()], &CodeGenConfig::default(), ) - .expect("nested enum buffa_ should be allowed"); + .expect("nested enum __buffa should be allowed"); } #[test] diff --git a/buffa-codegen/src/tests/view_codegen.rs b/buffa-codegen/src/tests/view_codegen.rs index 6e640f8..3552778 100644 --- a/buffa-codegen/src/tests/view_codegen.rs +++ b/buffa-codegen/src/tests/view_codegen.rs @@ -151,8 +151,8 @@ fn test_view_oneof_with_message_variant() { // (Prettyplease may wrap the path across lines, so check the // tail segment.) assert!( - content.contains("buffa_::view::oneof::request::Payload"), - "RequestView must reference buffa_::view::oneof::request::Payload: {content}" + content.contains("__buffa::view::oneof::request::Payload"), + "RequestView must reference __buffa::view::oneof::request::Payload: {content}" ); // The oneof view enum must have both variants. assert!( diff --git a/buffa-codegen/src/view.rs b/buffa-codegen/src/view.rs index c34d848..f28da60 100644 --- a/buffa-codegen/src/view.rs +++ b/buffa-codegen/src/view.rs @@ -65,10 +65,10 @@ fn bytes_to_owned( } /// `scope.nesting` is the **message-nesting** of the owning message (0 for -/// top-level). View structs are emitted into `buffa_::view::::`, +/// top-level). View structs are emitted into `__buffa::view::::`, /// so the view body's total depth below the package root is /// `scope.nesting + 2`; view-oneof enums go to -/// `buffa_::view::oneof::::`, depth `scope.nesting + 4`. +/// `__buffa::view::oneof::::`, depth `scope.nesting + 4`. pub(crate) fn generate_view_with_nesting( scope: MessageScope<'_>, msg: &DescriptorProto, @@ -123,7 +123,7 @@ pub(crate) fn generate_view_with_nesting( let oneof_struct_fields = oneof_view_struct_fields(ctx, msg, &view_oneof_prefix, features, &oneof_idents)?; - // Oneof view enum definitions (go into `buffa_::view::oneof::::`). + // Oneof view enum definitions (go into `__buffa::view::oneof::::`). let oneof_view_enums = msg .oneof_decl .iter() @@ -643,7 +643,7 @@ fn generate_oneof_view_enum( } // View-oneof enums share the owned oneof's identifier (no `View` suffix) - // — the `buffa_::view::oneof::` tree position disambiguates. They live + // — the `__buffa::view::oneof::` tree position disambiguates. They live // at depth `msg_nesting + 4` (sentinel + view + oneof + msg_path). let enum_body_depth = scope.nesting + 4; let body_scope = MessageScope { @@ -1479,7 +1479,7 @@ fn resolve_enum_ty( } /// Resolve the view type tokens for a message field -/// (e.g. `".pkg.Address"` → `super^n::buffa_::view::AddressView<'a>`). +/// (e.g. `".pkg.Address"` → `super^n::__buffa::view::AddressView<'a>`). /// /// `scope.nesting` must be the **total** depth of the caller below the /// package root (msg-nesting + kind-depth offset already applied by the @@ -1503,7 +1503,7 @@ fn resolve_view_decode_tokens( /// Compute the path to a message field's **view struct** from `scope`. /// /// Splits the resolved owned-type path at the target-package boundary and -/// inserts `buffa_::view::` between the halves, appending `View` to the +/// inserts `__buffa::view::` between the halves, appending `View` to the /// final identifier. fn resolve_view_path( scope: MessageScope<'_>, diff --git a/buffa-codegen/tests/codegen_integration.rs b/buffa-codegen/tests/codegen_integration.rs index 80f8434..fb763bd 100644 --- a/buffa-codegen/tests/codegen_integration.rs +++ b/buffa-codegen/tests/codegen_integration.rs @@ -380,7 +380,7 @@ fn inline_oneof() { "#, &no_views(), ); - assert!(content.contains("pub info: Option")); + assert!(content.contains("pub info: Option<__buffa::oneof::contact::Info>")); assert!(content.contains("pub enum Info")); assert!(content.contains("Email(")); assert!(content.contains("Phone(")); @@ -530,7 +530,7 @@ fn inline_oneof_duplicate_message_type_no_from_collision() { &no_views(), ); // Box on both message variants. Oneof body now sits at depth 3 - // (`buffa_::oneof::t::`), so 3× super. + // (`__buffa::oneof::t::`), so 3× super. assert_eq!( content .matches("::buffa::alloc::boxed::Box") diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs index e4294e3..8afffae 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.mod.rs @@ -8,9 +8,10 @@ include!("google.protobuf.compiler.plugin.rs"); clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, - clippy::doc_lazy_continuation + clippy::doc_lazy_continuation, + clippy::module_inception )] -pub mod buffa_ { +pub mod __buffa { #[allow(unused_imports)] use super::*; pub mod oneof { diff --git a/buffa-descriptor/src/generated/google.protobuf.mod.rs b/buffa-descriptor/src/generated/google.protobuf.mod.rs index c92ee2e..bdb029a 100644 --- a/buffa-descriptor/src/generated/google.protobuf.mod.rs +++ b/buffa-descriptor/src/generated/google.protobuf.mod.rs @@ -8,9 +8,10 @@ include!("google.protobuf.descriptor.rs"); clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, - clippy::doc_lazy_continuation + clippy::doc_lazy_continuation, + clippy::module_inception )] -pub mod buffa_ { +pub mod __buffa { #[allow(unused_imports)] use super::*; pub mod oneof { diff --git a/buffa-test/protos/prelude_shadow.proto b/buffa-test/protos/prelude_shadow.proto index 5d90811..c3c156f 100644 --- a/buffa-test/protos/prelude_shadow.proto +++ b/buffa-test/protos/prelude_shadow.proto @@ -55,3 +55,14 @@ message Outer { } optional Middle middle = 1; } + +// Regression for the kind-tree collision: a `message View` produces a +// nested-type module `pub mod view { ... }`. Under the sentinel design +// the kind-tree view wrapper is `pub mod __buffa { pub mod view { ... } }`, +// so this no longer collides. Compilation is the assertion. +message View { + message Inner { + optional string s = 1; + } + optional Inner inner = 1; +} diff --git a/buffa-test/src/tests/basic.rs b/buffa-test/src/tests/basic.rs index 851ceef..9c91fdf 100644 --- a/buffa-test/src/tests/basic.rs +++ b/buffa-test/src/tests/basic.rs @@ -1,7 +1,7 @@ //! Basic round-trips: Empty, Person, Address, unknown-field preservation. use super::round_trip; -use crate::basic::buffa_::oneof; +use crate::basic::__buffa::oneof; use crate::basic::*; use buffa::Message; diff --git a/buffa-test/src/tests/bytes_type.rs b/buffa-test/src/tests/bytes_type.rs index 443cfc6..2f7831c 100644 --- a/buffa-test/src/tests/bytes_type.rs +++ b/buffa-test/src/tests/bytes_type.rs @@ -49,7 +49,7 @@ fn test_bytes_type_view_to_owned() { // Views borrow &[u8]; to_owned_message must produce Bytes (not Vec) // when use_bytes_type() is active. Previously this emitted .to_vec() // unconditionally, failing to compile. - use crate::basic_bytes::buffa_::view::PersonView; + use crate::basic_bytes::__buffa::view::PersonView; use buffa::MessageView; let msg = Person { id: 7, @@ -82,8 +82,8 @@ fn test_bytes_type_view_to_owned() { // The bytes_variant build block compiles BytesContexts with use_bytes_type() // + generate_views=true; compilation alone is the primary assertion. -use crate::basic_bytes::buffa_::oneof::bytes_contexts::Choice as ChoiceOneof; -use crate::basic_bytes::buffa_::view::BytesContextsView; +use crate::basic_bytes::__buffa::oneof::bytes_contexts::Choice as ChoiceOneof; +use crate::basic_bytes::__buffa::view::BytesContextsView; use crate::basic_bytes::BytesContexts; #[test] diff --git a/buffa-test/src/tests/closed_enum.rs b/buffa-test/src/tests/closed_enum.rs index 4005aba..a4fcbc1 100644 --- a/buffa-test/src/tests/closed_enum.rs +++ b/buffa-test/src/tests/closed_enum.rs @@ -182,7 +182,7 @@ fn test_closed_enum_negative_unknown_value_sign_extension() { #[test] fn test_view_closed_enum_optional_unknown_to_unknown_fields() { - use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::__buffa::view::ClosedEnumContextsView; use buffa::MessageView; let wire = varint_field(1, 99); let view = ClosedEnumContextsView::decode_view(&wire).unwrap(); @@ -195,7 +195,7 @@ fn test_view_closed_enum_optional_unknown_to_unknown_fields() { #[test] fn test_view_closed_enum_repeated_unpacked_unknown_preserved() { - use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::__buffa::view::ClosedEnumContextsView; use crate::proto2::Priority; use buffa::MessageView; // Field 2 (unpacked): [LOW=0, 99, HIGH=2] @@ -220,7 +220,7 @@ fn test_view_closed_enum_repeated_unpacked_unknown_preserved() { #[test] fn test_view_closed_enum_oneof_unknown_to_unknown_fields() { - use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::__buffa::view::ClosedEnumContextsView; use buffa::MessageView; let wire = varint_field(4, 99); let view = ClosedEnumContextsView::decode_view(&wire).unwrap(); @@ -232,7 +232,7 @@ fn test_view_closed_enum_oneof_unknown_to_unknown_fields() { #[test] fn test_view_closed_enum_known_not_routed() { - use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::__buffa::view::ClosedEnumContextsView; use crate::proto2::Priority; use buffa::MessageView; let wire = varint_field(1, 2); // HIGH = 2 @@ -245,7 +245,7 @@ fn test_view_closed_enum_known_not_routed() { fn test_view_owned_parity_for_closed_enum_unknowns() { // Whatever the owned decoder produces, the view path must produce // byte-identical output after to_owned_message().encode_to_vec(). - use crate::proto2::buffa_::view::ClosedEnumContextsView; + use crate::proto2::__buffa::view::ClosedEnumContextsView; use crate::proto2::ClosedEnumContexts; use buffa::{Message, MessageView}; let mut wire = Vec::new(); diff --git a/buffa-test/src/tests/collision.rs b/buffa-test/src/tests/collision.rs index 8abcc1b..3125ab1 100644 --- a/buffa-test/src/tests/collision.rs +++ b/buffa-test/src/tests/collision.rs @@ -81,17 +81,17 @@ fn test_oneof_name_matching_parent_message() { use crate::collisions; let msg = collisions::Status { - status: Some(collisions::buffa_::oneof::status::Status::Code(42)), + status: Some(collisions::__buffa::oneof::status::Status::Code(42)), ..core::default::Default::default() }; let decoded = round_trip(&msg); assert_eq!( decoded.status, - Some(collisions::buffa_::oneof::status::Status::Code(42)) + Some(collisions::__buffa::oneof::status::Status::Code(42)) ); let msg2 = collisions::Status { - status: Some(collisions::buffa_::oneof::status::Status::Message( + status: Some(collisions::__buffa::oneof::status::Status::Message( "error".into(), )), ..core::default::Default::default() @@ -99,7 +99,7 @@ fn test_oneof_name_matching_parent_message() { let decoded = round_trip(&msg2); assert_eq!( decoded.status, - Some(collisions::buffa_::oneof::status::Status::Message( + Some(collisions::__buffa::oneof::status::Status::Message( "error".into() )) ); @@ -119,7 +119,7 @@ fn test_container_references_collision_types() { ..core::default::Default::default() }), status: buffa::MessageField::some(collisions::Status { - status: Some(collisions::buffa_::oneof::status::Status::Code(1)), + status: Some(collisions::__buffa::oneof::status::Status::Code(1)), ..core::default::Default::default() }), ..core::default::Default::default() @@ -139,7 +139,7 @@ fn test_nested_option_message_round_trip() { let msg = prelude_shadow::Picker { options: vec![picker::Option { title: Some("a".into()), - value: Some(prelude_shadow::buffa_::oneof::picker::option::Value::IntValue(7)), + value: Some(prelude_shadow::__buffa::oneof::picker::option::Value::IntValue(7)), ..core::default::Default::default() }], label: Some("L".into()), diff --git a/buffa-test/src/tests/extensions.rs b/buffa-test/src/tests/extensions.rs index dbb0d34..e07cc94 100644 --- a/buffa-test/src/tests/extensions.rs +++ b/buffa-test/src/tests/extensions.rs @@ -1,6 +1,6 @@ //! Integration tests for `extend` codegen and the `ExtensionSet` runtime API. -use crate::custopts::buffa_::ext::{ +use crate::custopts::__buffa::ext::{ ACTIVE, ANN, C_ACTIVE, C_ANN, C_FLAG, C_LABEL, C_MARKER, C_PRIORITY, C_TAGS, C_WEIGHT, IS_INTERNAL, LABEL, PRIORITY, TAGS, WEIGHT, }; @@ -273,7 +273,7 @@ fn proto2_default_after_roundtrip() { // Group-encoded extensions (editions DELIMITED) // ──────────────────────────────────────────────────────────────────────────── -use crate::groupext::buffa_::ext::{DELIM_INNER, DELIM_REPEATED}; +use crate::groupext::__buffa::ext::{DELIM_INNER, DELIM_REPEATED}; use crate::groupext::{Carrier as GroupCarrier, Inner}; use buffa::extension::codecs::{GroupCodec, Repeated}; diff --git a/buffa-test/src/tests/extensions_json.rs b/buffa-test/src/tests/extensions_json.rs index ba715cd..9dda59a 100644 --- a/buffa-test/src/tests/extensions_json.rs +++ b/buffa-test/src/tests/extensions_json.rs @@ -2,8 +2,8 @@ //! round-trip through `serde_json` via the generated `register_types` + //! the runtime's `#[serde(flatten)]` wrapper. -use crate::extjson::buffa_::ext::{ANN, ANNS, BIGS, COLOR, COLORS, NUMS, WEIGHT}; -use crate::extjson::buffa_::register_types; +use crate::extjson::__buffa::ext::{ANN, ANNS, BIGS, COLOR, COLORS, NUMS, WEIGHT}; +use crate::extjson::__buffa::register_types; use crate::extjson::{Ann, Carrier, Color}; use buffa::type_registry::{set_type_registry, TypeRegistry}; use buffa::{Enumeration, ExtensionSet}; diff --git a/buffa-test/src/tests/json.rs b/buffa-test/src/tests/json.rs index a09e93f..3c26956 100644 --- a/buffa-test/src/tests/json.rs +++ b/buffa-test/src/tests/json.rs @@ -51,7 +51,7 @@ fn test_json_oneof_round_trip() { use crate::json_types::WithOneof; let msg = WithOneof { - value: Some(crate::json_types::buffa_::oneof::with_oneof::Value::Text( + value: Some(crate::json_types::__buffa::oneof::with_oneof::Value::Text( "hello".into(), )), ..Default::default() @@ -66,7 +66,7 @@ fn test_json_oneof_all_scalar_types_round_trip() { // Exercises serde_helper_path dispatch for all proto3-JSON-special // scalar types in oneof position, and the corresponding runtime // json_helpers::{int64, uint32, uint64, float, double, bytes} paths. - use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; + use crate::json_types::__buffa::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; #[rustfmt::skip] @@ -106,7 +106,7 @@ fn test_json_oneof_all_scalar_types_round_trip() { #[test] fn test_json_oneof_float_special_values() { // NaN/Infinity/-Infinity serialize as string tokens per proto3-JSON spec. - use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; + use crate::json_types::__buffa::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; #[rustfmt::skip] @@ -151,7 +151,7 @@ fn test_json_oneof_float_special_values() { fn test_json_oneof_null_value() { // google.protobuf.NullValue in a oneof serializes as JSON null. // On deserialize, JSON null populates the NullValue variant (not unset). - use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; + use crate::json_types::__buffa::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; use buffa_types::google::protobuf::NullValue; @@ -174,7 +174,7 @@ fn test_json_oneof_null_value() { fn test_json_oneof_float_deserialize_from_integer() { // proto3-JSON: float/double fields accept integer JSON values. // Exercises json_helpers::float::visit_i64/visit_u64. - use crate::json_types::buffa_::oneof::with_oneof_types::Kind as KindOneof; + use crate::json_types::__buffa::oneof::with_oneof_types::Kind as KindOneof; use crate::json_types::WithOneofTypes; let decoded: WithOneofTypes = serde_json::from_str(r#"{"f32": 42}"#).unwrap(); @@ -437,7 +437,7 @@ fn test_json_optional_open_enum_integer_deserialize() { #[test] fn test_json_mixed_oneof_and_fields_round_trip() { - use crate::json_types::buffa_::oneof::mixed_oneof_and_fields::Choice as ChoiceOneof; + use crate::json_types::__buffa::oneof::mixed_oneof_and_fields::Choice as ChoiceOneof; use crate::json_types::{MixedOneofAndFields, Scalar}; let msg = MixedOneofAndFields { @@ -490,7 +490,7 @@ fn test_json_mixed_value_field_null_forwarding() { // not "field absent". The custom Deserialize must forward null to // Value's own Deserialize rather than skipping the field. use crate::json_types::MixedOneofAndFields; - use buffa_types::google::protobuf::buffa_::oneof::value::Kind as KindOneof; + use buffa_types::google::protobuf::__buffa::oneof::value::Kind as KindOneof; use buffa_types::google::protobuf::NullValue; let decoded: MixedOneofAndFields = serde_json::from_str(r#"{"dynamic": null}"#).unwrap(); diff --git a/buffa-test/src/tests/keyword.rs b/buffa-test/src/tests/keyword.rs index 1e8f4bf..00f6bd8 100644 --- a/buffa-test/src/tests/keyword.rs +++ b/buffa-test/src/tests/keyword.rs @@ -46,7 +46,7 @@ fn test_keyword_expression_with_oneof() { ..Default::default() }), match_mode: buffa::EnumValue::Known(keywords::Match::MATCH_EXACT), - value: Some(keywords::buffa_::oneof::expression::Value::Literal( + value: Some(keywords::__buffa::oneof::expression::Value::Literal( "42".into(), )), ..Default::default() @@ -55,7 +55,7 @@ fn test_keyword_expression_with_oneof() { assert_eq!(decoded.result_type.name, "bool"); assert_eq!( decoded.value, - Some(keywords::buffa_::oneof::expression::Value::Literal( + Some(keywords::__buffa::oneof::expression::Value::Literal( "42".into() )) ); diff --git a/buffa-test/src/tests/message_set.rs b/buffa-test/src/tests/message_set.rs index 29762d5..e6971f5 100644 --- a/buffa-test/src/tests/message_set.rs +++ b/buffa-test/src/tests/message_set.rs @@ -8,7 +8,7 @@ //! `{number: type_id, data: LengthDelimited(payload)}`. Decode unwraps the //! group; encode rewraps it. -use crate::msgset::buffa_::ext::{MARKER_EXT, PAYLOAD_EXT}; +use crate::msgset::__buffa::ext::{MARKER_EXT, PAYLOAD_EXT}; use crate::msgset::{Container, Marker, Payload}; use buffa::{ExtensionSet, Message}; diff --git a/buffa-test/src/tests/nesting.rs b/buffa-test/src/tests/nesting.rs index 8cbc7bd..2239d61 100644 --- a/buffa-test/src/tests/nesting.rs +++ b/buffa-test/src/tests/nesting.rs @@ -19,7 +19,7 @@ fn test_deep_nesting_round_trip() { }), ..Default::default() }), - content: Some(nested::buffa_::oneof::outer::Content::Text("hello".into())), + content: Some(nested::__buffa::oneof::outer::Content::Text("hello".into())), ..Default::default() }; let decoded = round_trip(&msg); @@ -64,41 +64,43 @@ fn test_multi_oneof_variants() { // Test each variant type round-trips correctly. let cases: Vec = vec![ MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::IntVal(42)), + value: Some(nested::__buffa::oneof::multi_oneof::Value::IntVal(42)), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::LongVal(i64::MAX)), + value: Some(nested::__buffa::oneof::multi_oneof::Value::LongVal( + i64::MAX, + )), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::FloatVal(1.5)), + value: Some(nested::__buffa::oneof::multi_oneof::Value::FloatVal(1.5)), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::DoubleVal( + value: Some(nested::__buffa::oneof::multi_oneof::Value::DoubleVal( std::f64::consts::PI, )), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::BoolVal(true)), + value: Some(nested::__buffa::oneof::multi_oneof::Value::BoolVal(true)), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::StringVal( + value: Some(nested::__buffa::oneof::multi_oneof::Value::StringVal( "hello".into(), )), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::BytesVal(vec![ + value: Some(nested::__buffa::oneof::multi_oneof::Value::BytesVal(vec![ 0xFF, 0x00, ])), ..Default::default() }, MultiOneof { - value: Some(nested::buffa_::oneof::multi_oneof::Value::MessageVal( + value: Some(nested::__buffa::oneof::multi_oneof::Value::MessageVal( Box::new(nested::outer::middle::Inner { data: vec![1, 2, 3], active: true, @@ -120,7 +122,7 @@ fn test_recursive_oneof_direct() { // Expr { kind { Expr negated = 3; } } is directly self-recursive // through the oneof. Message/group variants are always boxed to // break the infinite-size cycle. - use crate::nested::buffa_::oneof::expr; + use crate::nested::__buffa::oneof::expr; use crate::nested::Expr; let inner = Expr { kind: Some(expr::Kind::IntLiteral(42)), @@ -147,7 +149,7 @@ fn test_recursive_oneof_mutual() { // Expr -> BinaryOp -> Expr mutual recursion. BinaryOp fields use // MessageField (already boxed); the Expr.kind.binary variant is // the boxed side of the cycle. - use crate::nested::buffa_::oneof::expr; + use crate::nested::__buffa::oneof::expr; use crate::nested::{BinaryOp, Expr}; let lhs = Expr { kind: Some(expr::Kind::IntLiteral(1)), @@ -176,7 +178,7 @@ fn test_recursive_oneof_mutual() { fn test_from_msg_for_option_oneof() { // `From for Option` lets struct-literal construction skip both // the explicit `Some(...)` and `Box::new(...)` for message-typed variants. - use crate::nested::buffa_::oneof::expr; + use crate::nested::__buffa::oneof::expr; use crate::nested::{BinaryOp, Expr}; let op = BinaryOp { op: "*".into(), @@ -213,7 +215,7 @@ fn test_from_msg_for_option_oneof() { fn test_recursive_oneof_merge_semantics() { // When the same message-typed oneof variant appears twice on the // wire, the second occurrence merges into the first (proto3 spec). - use crate::nested::buffa_::oneof::expr; + use crate::nested::__buffa::oneof::expr; use crate::nested::{BinaryOp, Expr}; let first = Expr { kind: Some(expr::Kind::from(BinaryOp { @@ -254,8 +256,8 @@ fn test_recursive_oneof_merge_semantics() { fn test_view_oneof_boxed_message_variant() { // View oneof enums box message/group variants for the same reason // as owned enums. The Box holds a lifetime-bound view struct. - use crate::nested::buffa_::oneof::expr; - use crate::nested::buffa_::view::ExprView; + use crate::nested::__buffa::oneof::expr; + use crate::nested::__buffa::view::ExprView; use crate::nested::Expr; use buffa::MessageView; let inner = Expr { @@ -270,8 +272,8 @@ fn test_view_oneof_boxed_message_variant() { let view = ExprView::decode_view(&bytes).expect("decode_view"); // Pattern-matched binding auto-derefs through Box>. match &view.kind { - Some(crate::nested::buffa_::view::oneof::expr::Kind::Negated(v)) => match &v.kind { - Some(crate::nested::buffa_::view::oneof::expr::Kind::IntLiteral(n)) => { + Some(crate::nested::__buffa::view::oneof::expr::Kind::Negated(v)) => match &v.kind { + Some(crate::nested::__buffa::view::oneof::expr::Kind::IntLiteral(n)) => { assert_eq!(*n, 42) } other => panic!("expected IntLiteral, got {other:?}"), @@ -286,22 +288,22 @@ fn test_view_oneof_boxed_message_variant() { #[test] fn test_view_oneof_message_variant_to_owned() { // Non-recursive message variant: Middle in Outer.content.structured. - use crate::nested::buffa_::view::OuterView; + use crate::nested::__buffa::view::OuterView; use crate::nested::{self, Outer}; use buffa::MessageView; let msg = Outer { - content: Some(nested::buffa_::oneof::outer::Content::Structured(Box::new( - nested::outer::Middle { + content: Some(nested::__buffa::oneof::outer::Content::Structured( + Box::new(nested::outer::Middle { value: 7, ..Default::default() - }, - ))), + }), + )), ..Default::default() }; let bytes = msg.encode_to_vec(); let view = OuterView::decode_view(&bytes).expect("decode_view"); match &view.content { - Some(nested::buffa_::view::oneof::outer::Content::Structured(m)) => assert_eq!(m.value, 7), + Some(nested::__buffa::view::oneof::outer::Content::Structured(m)) => assert_eq!(m.value, 7), other => panic!("expected Structured, got {other:?}"), } assert_eq!(view.to_owned_message(), msg); @@ -336,7 +338,7 @@ fn test_recursive_singular_message_field() { fn test_view_recursive_singular_message_field() { // View path through the same cycle. MessageFieldView boxes internally, // Deref returns &V transparently. - use crate::nested::buffa_::view::CorecursiveView; + use crate::nested::__buffa::view::CorecursiveView; use crate::nested::{corecursive, Corecursive}; use buffa::MessageView; let msg = Corecursive { @@ -366,7 +368,7 @@ fn test_view_message_field_merge_semantics() { // When a singular message field appears twice on the wire, the // second occurrence merges into the first field-by-field (proto // spec). The view decoder must do this, not replace. - use crate::nested::buffa_::view::CorecursiveView; + use crate::nested::__buffa::view::CorecursiveView; use crate::nested::{corecursive, Corecursive}; use buffa::MessageView; // First: nested.value = 1, nested.back.name = "from_first" @@ -409,8 +411,8 @@ fn test_view_message_field_merge_semantics() { #[test] fn test_view_oneof_message_variant_merge_semantics() { // Same merge semantics for message-typed oneof variants. - use crate::nested::buffa_::oneof::expr; - use crate::nested::buffa_::view::ExprView; + use crate::nested::__buffa::oneof::expr; + use crate::nested::__buffa::view::ExprView; use crate::nested::{BinaryOp, Expr}; use buffa::MessageView; // First: binary with lhs set @@ -441,7 +443,7 @@ fn test_view_oneof_message_variant_merge_semantics() { let view = ExprView::decode_view(&wire).unwrap(); match &view.kind { - Some(crate::nested::buffa_::view::oneof::expr::Kind::Binary(b)) => { + Some(crate::nested::__buffa::view::oneof::expr::Kind::Binary(b)) => { assert_eq!(b.op, "+", "op from first (second didn't set it)"); assert!(b.lhs.is_set(), "lhs from first must survive merge"); assert!(b.rhs.is_set(), "rhs from second"); diff --git a/buffa-test/src/tests/proto2.rs b/buffa-test/src/tests/proto2.rs index 2196b54..2f92e65 100644 --- a/buffa-test/src/tests/proto2.rs +++ b/buffa-test/src/tests/proto2.rs @@ -261,7 +261,7 @@ fn test_proto2_group_wire_format() { #[test] fn test_view_coverage_owned_round_trip() { - use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::__buffa::oneof::view_coverage::Choice as ChoiceOneof; use crate::proto2::view_coverage::Payload; use crate::proto2::{Priority, ViewCoverage}; @@ -305,8 +305,8 @@ fn test_view_coverage_via_view() { // View-decode → to_owned_message → encode round-trip. // Exercises: singular closed-enum view type, MapView, // MapView<&str, ClosedEnum>, group-in-oneof view decode + merge. - use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; - use crate::proto2::buffa_::view::ViewCoverageView; + use crate::proto2::__buffa::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::__buffa::view::ViewCoverageView; use crate::proto2::view_coverage::Payload; use crate::proto2::{Priority, ViewCoverage}; use buffa::MessageView; @@ -362,7 +362,7 @@ fn test_view_coverage_via_view() { fn test_view_coverage_required_enum_default() { // Required closed-enum field defaults to the first enum value (LOW=0). // View decode of empty buffer should also produce the default. - use crate::proto2::buffa_::view::ViewCoverageView; + use crate::proto2::__buffa::view::ViewCoverageView; use crate::proto2::{Priority, ViewCoverage}; use buffa::MessageView; @@ -377,8 +377,8 @@ fn test_view_coverage_required_enum_default() { fn test_view_coverage_group_in_oneof_merge() { // Proto spec: same oneof field on the wire twice → merge (for messages/ // groups). Exercises the `_merge_into_view` branch for group-in-oneof. - use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; - use crate::proto2::buffa_::view::ViewCoverageView; + use crate::proto2::__buffa::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::__buffa::view::ViewCoverageView; use crate::proto2::view_coverage::Payload; use crate::proto2::{Priority, ViewCoverage}; use buffa::MessageView; diff --git a/buffa-test/src/tests/proto3_semantics.rs b/buffa-test/src/tests/proto3_semantics.rs index 9dba2f5..8ca0a61 100644 --- a/buffa-test/src/tests/proto3_semantics.rs +++ b/buffa-test/src/tests/proto3_semantics.rs @@ -366,7 +366,7 @@ fn enum_unknown_value_preserved_map() { fn enum_unknown_value_preserved_oneof() { let msg = EnumContexts { choice: Some( - crate::proto3sem::buffa_::oneof::enum_contexts::Choice::Picked(EnumValue::Unknown(77)), + crate::proto3sem::__buffa::oneof::enum_contexts::Choice::Picked(EnumValue::Unknown(77)), ), ..Default::default() }; @@ -374,7 +374,7 @@ fn enum_unknown_value_preserved_oneof() { assert_eq!( decoded.choice, Some( - crate::proto3sem::buffa_::oneof::enum_contexts::Choice::Picked(EnumValue::Unknown(77)) + crate::proto3sem::__buffa::oneof::enum_contexts::Choice::Picked(EnumValue::Unknown(77)) ) ); } @@ -570,7 +570,7 @@ fn view_implicit_presence_matches_owned() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = buffa_::view::ImplicitScalarsView::decode_view(&bytes).unwrap(); + let view = __buffa::view::ImplicitScalarsView::decode_view(&bytes).unwrap(); assert_eq!(view.i32, 42); assert_eq!(view.s, "view"); assert_eq!(view.by, &[0xAA, 0xBB]); @@ -591,7 +591,7 @@ fn view_optional_some_zero_matches_owned() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = buffa_::view::OptionalAllTypesView::decode_view(&bytes).unwrap(); + let view = __buffa::view::OptionalAllTypesView::decode_view(&bytes).unwrap(); assert_eq!(view.i32, Some(0)); assert_eq!(view.s, Some("")); assert_eq!(view.b, Some(false)); @@ -608,7 +608,7 @@ fn view_open_enum_unknown_preserved() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = buffa_::view::EnumContextsView::decode_view(&bytes).unwrap(); + let view = __buffa::view::EnumContextsView::decode_view(&bytes).unwrap(); assert_eq!(view.singular, EnumValue::Unknown(55)); let rep_collected: Vec<_> = view.rep.iter().copied().collect(); assert_eq!( diff --git a/buffa-test/src/tests/textproto.rs b/buffa-test/src/tests/textproto.rs index d43fb93..20148e6 100644 --- a/buffa-test/src/tests/textproto.rs +++ b/buffa-test/src/tests/textproto.rs @@ -96,7 +96,7 @@ fn person_roundtrip() { ..Default::default() }]; p.maybe_age = Some(30); - p.contact = Some(crate::basic::buffa_::oneof::person::Contact::Email( + p.contact = Some(crate::basic::__buffa::oneof::person::Contact::Email( "alice@example.com".into(), )); @@ -157,7 +157,7 @@ fn closed_enum_encode_decode() { #[test] fn oneof_variants() { let mut p = Person::default(); - p.contact = Some(crate::basic::buffa_::oneof::person::Contact::Phone( + p.contact = Some(crate::basic::__buffa::oneof::person::Contact::Phone( "555-1234".into(), )); assert_eq!(encode_to_string(&p), r#"phone: "555-1234""#); @@ -165,7 +165,7 @@ fn oneof_variants() { let p: Person = decode_from_str(r#"email: "x@y.com""#).unwrap(); assert_eq!( p.contact, - Some(crate::basic::buffa_::oneof::person::Contact::Email( + Some(crate::basic::__buffa::oneof::person::Contact::Email( "x@y.com".into() )) ); @@ -174,7 +174,7 @@ fn oneof_variants() { let p: Person = decode_from_str(r#"email: "a" phone: "b""#).unwrap(); assert_eq!( p.contact, - Some(crate::basic::buffa_::oneof::person::Contact::Phone( + Some(crate::basic::__buffa::oneof::person::Contact::Phone( "b".into() )) ); @@ -350,7 +350,7 @@ fn group_decode_accepts_both_names() { #[test] fn group_in_oneof_uses_type_name() { - use crate::proto2::buffa_::oneof::view_coverage::Choice as ChoiceOneof; + use crate::proto2::__buffa::oneof::view_coverage::Choice as ChoiceOneof; use crate::proto2::view_coverage::Payload; use crate::proto2::ViewCoverage; diff --git a/buffa-test/src/tests/utf8_validation.rs b/buffa-test/src/tests/utf8_validation.rs index 901e325..6875b4b 100644 --- a/buffa-test/src/tests/utf8_validation.rs +++ b/buffa-test/src/tests/utf8_validation.rs @@ -46,7 +46,7 @@ fn view_none_fields_are_byte_slices() { ..Default::default() }; let bytes = msg.encode_to_vec(); - let view = buffa_::view::StringNoValidationView::decode_view(&bytes).unwrap(); + let view = __buffa::view::StringNoValidationView::decode_view(&bytes).unwrap(); // raw_name is Option<&[u8]>, validated_name is Option<&str>. let raw: Option<&[u8]> = view.raw_name; let validated: Option<&str> = view.validated_name; @@ -57,13 +57,13 @@ fn view_none_fields_are_byte_slices() { #[test] fn view_none_accepts_invalid_utf8() { let wire = [0x0A, 0x02, 0xFF, 0xFE]; - let view = buffa_::view::StringNoValidationView::decode_view(&wire).unwrap(); + let view = __buffa::view::StringNoValidationView::decode_view(&wire).unwrap(); assert_eq!(view.raw_name, Some(&[0xFF, 0xFE][..])); } #[test] fn oneof_none_variant_is_vec_u8() { - use crate::utf8test::buffa_::oneof::oneof_no_validation::Content as ContentOneof; + use crate::utf8test::__buffa::oneof::oneof_no_validation::Content as ContentOneof; let msg = OneofNoValidation { content: Some(ContentOneof::RawText(b"bytes".to_vec())), ..Default::default() diff --git a/buffa-test/src/tests/view.rs b/buffa-test/src/tests/view.rs index d5b8c79..c23d87a 100644 --- a/buffa-test/src/tests/view.rs +++ b/buffa-test/src/tests/view.rs @@ -1,8 +1,8 @@ //! View type tests: decode_view, MessageFieldView Deref, to_owned_message, //! MapView iteration, oneof views, unknown-field preservation, recursion limit. -use crate::basic::buffa_::oneof; -use crate::basic::buffa_::view::*; +use crate::basic::__buffa::oneof; +use crate::basic::__buffa::view::*; use crate::basic::*; use buffa::{Message, MessageView}; @@ -102,7 +102,7 @@ fn test_view_decodes_oneof() { let bytes = msg.encode_to_vec(); let view = PersonView::decode_view(&bytes).expect("decode_view"); match view.contact { - Some(crate::basic::buffa_::view::oneof::person::Contact::Email(s)) => { + Some(crate::basic::__buffa::view::oneof::person::Contact::Email(s)) => { assert_eq!(s, "bob@example.com") } other => panic!("expected Email, got {other:?}"), @@ -320,7 +320,7 @@ fn test_view_map_with_open_enum_value() { #[test] fn test_view_no_unknown_fields_all_scalar_compiles() { - use crate::basic_no_uf::buffa_::view::{AllScalarsView, EmptyView}; + use crate::basic_no_uf::__buffa::view::{AllScalarsView, EmptyView}; use crate::basic_no_uf::{AllScalars, Empty}; // EmptyView<'a> has NO fields; AllScalarsView<'a> has only scalars. // Both now carry a PhantomData marker. diff --git a/buffa-test/src/tests/wkt.rs b/buffa-test/src/tests/wkt.rs index e8f5502..cb39fdc 100644 --- a/buffa-test/src/tests/wkt.rs +++ b/buffa-test/src/tests/wkt.rs @@ -13,7 +13,7 @@ fn test_wkt_in_oneof_from_impls() { // // The fact that this test compiles IS the test: wkt_usage.proto has // Envelope.content with Any/Timestamp (extern) + Event (local) variants. - use crate::wkt::buffa_::oneof::envelope; + use crate::wkt::__buffa::oneof::envelope; use crate::wkt::{Envelope, Event}; use buffa_types::google::protobuf::Any; @@ -86,7 +86,7 @@ fn test_wkt_view_with_extern_path() { // appends "View" to the last path segment: crate::wkt::Timestamp // → crate::wkt::TimestampView (which is re-exported from buffa-types' // generated code). - use crate::wkt::buffa_::view::EventView; + use crate::wkt::__buffa::view::EventView; use crate::wkt::Event; use buffa::MessageView; let msg = Event { diff --git a/buffa-types/src/generated/google.protobuf.mod.rs b/buffa-types/src/generated/google.protobuf.mod.rs index 6337159..a64186c 100644 --- a/buffa-types/src/generated/google.protobuf.mod.rs +++ b/buffa-types/src/generated/google.protobuf.mod.rs @@ -14,9 +14,10 @@ include!("google.protobuf.wrappers.rs"); clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, - clippy::doc_lazy_continuation + clippy::doc_lazy_continuation, + clippy::module_inception )] -pub mod buffa_ { +pub mod __buffa { #[allow(unused_imports)] use super::*; pub mod view { diff --git a/buffa-types/src/generated/google.protobuf.struct.__view.rs b/buffa-types/src/generated/google.protobuf.struct.__view.rs index 6330b43..0ac2db9 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view.rs @@ -14,7 +14,11 @@ pub struct StructView<'a> { /// Unordered map of dynamically typed values. /// /// Field 1: `fields` (map) - pub fields: ::buffa::MapView<'a, &'a str, super::super::buffa_::view::ValueView<'a>>, + pub fields: ::buffa::MapView< + 'a, + &'a str, + super::super::__buffa::view::ValueView<'a>, + >, pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> StructView<'a> { @@ -96,7 +100,7 @@ impl<'a> StructView<'a> { return Err(::buffa::DecodeError::RecursionLimitExceeded); } let sub = ::buffa::types::borrow_bytes(&mut entry_cur)?; - val = super::super::buffa_::view::ValueView::_decode_depth( + val = super::super::__buffa::view::ValueView::_decode_depth( sub, depth - 1, )?; @@ -170,7 +174,9 @@ unsafe impl<'a> ::buffa::HasDefaultViewInstance for StructView<'a> { /// The JSON representation for `Value` is JSON value. #[derive(Clone, Debug, Default)] pub struct ValueView<'a> { - pub kind: ::core::option::Option>, + pub kind: ::core::option::Option< + super::super::__buffa::view::oneof::value::Kind<'a>, + >, pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ValueView<'a> { @@ -220,7 +226,7 @@ impl<'a> ValueView<'a> { }); } view.kind = Some( - super::super::buffa_::view::oneof::value::Kind::NullValue( + super::super::__buffa::view::oneof::value::Kind::NullValue( ::buffa::EnumValue::from( ::buffa::types::decode_int32(&mut cur)?, ), @@ -236,7 +242,7 @@ impl<'a> ValueView<'a> { }); } view.kind = Some( - super::super::buffa_::view::oneof::value::Kind::NumberValue( + super::super::__buffa::view::oneof::value::Kind::NumberValue( ::buffa::types::decode_double(&mut cur)?, ), ); @@ -250,7 +256,7 @@ impl<'a> ValueView<'a> { }); } view.kind = Some( - super::super::buffa_::view::oneof::value::Kind::StringValue( + super::super::__buffa::view::oneof::value::Kind::StringValue( ::buffa::types::borrow_str(&mut cur)?, ), ); @@ -264,7 +270,7 @@ impl<'a> ValueView<'a> { }); } view.kind = Some( - super::super::buffa_::view::oneof::value::Kind::BoolValue( + super::super::__buffa::view::oneof::value::Kind::BoolValue( ::buffa::types::decode_bool(&mut cur)?, ), ); @@ -282,7 +288,7 @@ impl<'a> ValueView<'a> { } let sub = ::buffa::types::borrow_bytes(&mut cur)?; if let Some( - super::super::buffa_::view::oneof::value::Kind::StructValue( + super::super::__buffa::view::oneof::value::Kind::StructValue( ref mut existing, ), ) = view.kind @@ -290,9 +296,9 @@ impl<'a> ValueView<'a> { existing._merge_into_view(sub, depth - 1)?; } else { view.kind = Some( - super::super::buffa_::view::oneof::value::Kind::StructValue( + super::super::__buffa::view::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new( - super::super::buffa_::view::StructView::_decode_depth( + super::super::__buffa::view::StructView::_decode_depth( sub, depth - 1, )?, @@ -314,7 +320,7 @@ impl<'a> ValueView<'a> { } let sub = ::buffa::types::borrow_bytes(&mut cur)?; if let Some( - super::super::buffa_::view::oneof::value::Kind::ListValue( + super::super::__buffa::view::oneof::value::Kind::ListValue( ref mut existing, ), ) = view.kind @@ -322,9 +328,9 @@ impl<'a> ValueView<'a> { existing._merge_into_view(sub, depth - 1)?; } else { view.kind = Some( - super::super::buffa_::view::oneof::value::Kind::ListValue( + super::super::__buffa::view::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new( - super::super::buffa_::view::ListValueView::_decode_depth( + super::super::__buffa::view::ListValueView::_decode_depth( sub, depth - 1, )?, @@ -364,27 +370,27 @@ impl<'a> ::buffa::MessageView<'a> for ValueView<'a> { .kind .as_ref() .map(|v| match v { - super::super::buffa_::view::oneof::value::Kind::NullValue(v) => { - super::super::buffa_::oneof::value::Kind::NullValue(*v) + super::super::__buffa::view::oneof::value::Kind::NullValue(v) => { + super::super::__buffa::oneof::value::Kind::NullValue(*v) } - super::super::buffa_::view::oneof::value::Kind::NumberValue(v) => { - super::super::buffa_::oneof::value::Kind::NumberValue(*v) + super::super::__buffa::view::oneof::value::Kind::NumberValue(v) => { + super::super::__buffa::oneof::value::Kind::NumberValue(*v) } - super::super::buffa_::view::oneof::value::Kind::StringValue(v) => { - super::super::buffa_::oneof::value::Kind::StringValue( + super::super::__buffa::view::oneof::value::Kind::StringValue(v) => { + super::super::__buffa::oneof::value::Kind::StringValue( v.to_string(), ) } - super::super::buffa_::view::oneof::value::Kind::BoolValue(v) => { - super::super::buffa_::oneof::value::Kind::BoolValue(*v) + super::super::__buffa::view::oneof::value::Kind::BoolValue(v) => { + super::super::__buffa::oneof::value::Kind::BoolValue(*v) } - super::super::buffa_::view::oneof::value::Kind::StructValue(v) => { - super::super::buffa_::oneof::value::Kind::StructValue( + super::super::__buffa::view::oneof::value::Kind::StructValue(v) => { + super::super::__buffa::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new(v.to_owned_message()), ) } - super::super::buffa_::view::oneof::value::Kind::ListValue(v) => { - super::super::buffa_::oneof::value::Kind::ListValue( + super::super::__buffa::view::oneof::value::Kind::ListValue(v) => { + super::super::__buffa::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new(v.to_owned_message()), ) } @@ -415,7 +421,7 @@ pub struct ListValueView<'a> { /// Repeated field of dynamically typed values. /// /// Field 1: `values` - pub values: ::buffa::RepeatedView<'a, super::super::buffa_::view::ValueView<'a>>, + pub values: ::buffa::RepeatedView<'a, super::super::__buffa::view::ValueView<'a>>, pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ListValueView<'a> { @@ -470,7 +476,7 @@ impl<'a> ListValueView<'a> { let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.values .push( - super::super::buffa_::view::ValueView::_decode_depth( + super::super::__buffa::view::ValueView::_decode_depth( sub, depth - 1, )?, diff --git a/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs b/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs index 575c712..7ca4d96 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view_oneof.rs @@ -12,12 +12,12 @@ pub mod value { BoolValue(bool), StructValue( ::buffa::alloc::boxed::Box< - super::super::super::super::buffa_::view::StructView<'a>, + super::super::super::super::__buffa::view::StructView<'a>, >, ), ListValue( ::buffa::alloc::boxed::Box< - super::super::super::super::buffa_::view::ListValueView<'a>, + super::super::super::super::__buffa::view::ListValueView<'a>, >, ), } diff --git a/buffa-types/src/generated/google.protobuf.struct.rs b/buffa-types/src/generated/google.protobuf.struct.rs index 7dc39dc..f373a8b 100644 --- a/buffa-types/src/generated/google.protobuf.struct.rs +++ b/buffa-types/src/generated/google.protobuf.struct.rs @@ -328,7 +328,7 @@ pub const __STRUCT_TEXT_ANY: ::buffa::type_registry::TextAnyEntry = ::buffa::typ #[derive(Clone, PartialEq, Default)] #[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))] pub struct Value { - pub kind: Option, + pub kind: Option<__buffa::oneof::value::Kind>, #[doc(hidden)] pub __buffa_unknown_fields: ::buffa::UnknownFields, #[doc(hidden)] @@ -364,25 +364,25 @@ impl ::buffa::Message for Value { let mut size = 0u32; if let ::core::option::Option::Some(ref v) = self.kind { match v { - buffa_::oneof::value::Kind::NullValue(x) => { + __buffa::oneof::value::Kind::NullValue(x) => { size += 1u32 + ::buffa::types::int32_encoded_len(x.to_i32()) as u32; } - buffa_::oneof::value::Kind::NumberValue(_x) => { + __buffa::oneof::value::Kind::NumberValue(_x) => { size += 1u32 + ::buffa::types::FIXED64_ENCODED_LEN as u32; } - buffa_::oneof::value::Kind::StringValue(x) => { + __buffa::oneof::value::Kind::StringValue(x) => { size += 1u32 + ::buffa::types::string_encoded_len(x) as u32; } - buffa_::oneof::value::Kind::BoolValue(_x) => { + __buffa::oneof::value::Kind::BoolValue(_x) => { size += 1u32 + ::buffa::types::BOOL_ENCODED_LEN as u32; } - buffa_::oneof::value::Kind::StructValue(x) => { + __buffa::oneof::value::Kind::StructValue(x) => { let inner = x.compute_size(); size += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 + inner; } - buffa_::oneof::value::Kind::ListValue(x) => { + __buffa::oneof::value::Kind::ListValue(x) => { let inner = x.compute_size(); size += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 @@ -399,7 +399,7 @@ impl ::buffa::Message for Value { use ::buffa::Enumeration as _; if let ::core::option::Option::Some(ref v) = self.kind { match v { - buffa_::oneof::value::Kind::NullValue(x) => { + __buffa::oneof::value::Kind::NullValue(x) => { ::buffa::encoding::Tag::new( 1u32, ::buffa::encoding::WireType::Varint, @@ -407,7 +407,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_int32(x.to_i32(), buf); } - buffa_::oneof::value::Kind::NumberValue(x) => { + __buffa::oneof::value::Kind::NumberValue(x) => { ::buffa::encoding::Tag::new( 2u32, ::buffa::encoding::WireType::Fixed64, @@ -415,7 +415,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_double(*x, buf); } - buffa_::oneof::value::Kind::StringValue(x) => { + __buffa::oneof::value::Kind::StringValue(x) => { ::buffa::encoding::Tag::new( 3u32, ::buffa::encoding::WireType::LengthDelimited, @@ -423,7 +423,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_string(x, buf); } - buffa_::oneof::value::Kind::BoolValue(x) => { + __buffa::oneof::value::Kind::BoolValue(x) => { ::buffa::encoding::Tag::new( 4u32, ::buffa::encoding::WireType::Varint, @@ -431,7 +431,7 @@ impl ::buffa::Message for Value { .encode(buf); ::buffa::types::encode_bool(*x, buf); } - buffa_::oneof::value::Kind::StructValue(x) => { + __buffa::oneof::value::Kind::StructValue(x) => { ::buffa::encoding::Tag::new( 5u32, ::buffa::encoding::WireType::LengthDelimited, @@ -440,7 +440,7 @@ impl ::buffa::Message for Value { ::buffa::encoding::encode_varint(x.cached_size() as u64, buf); x.write_to(buf); } - buffa_::oneof::value::Kind::ListValue(x) => { + __buffa::oneof::value::Kind::ListValue(x) => { ::buffa::encoding::Tag::new( 6u32, ::buffa::encoding::WireType::LengthDelimited, @@ -473,7 +473,7 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::NullValue( + __buffa::oneof::value::Kind::NullValue( ::buffa::EnumValue::from(::buffa::types::decode_int32(buf)?), ), ); @@ -487,7 +487,7 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::NumberValue( + __buffa::oneof::value::Kind::NumberValue( ::buffa::types::decode_double(buf)?, ), ); @@ -501,7 +501,7 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::StringValue( + __buffa::oneof::value::Kind::StringValue( ::buffa::types::decode_string(buf)?, ), ); @@ -515,7 +515,7 @@ impl ::buffa::Message for Value { }); } self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::BoolValue( + __buffa::oneof::value::Kind::BoolValue( ::buffa::types::decode_bool(buf)?, ), ); @@ -529,7 +529,7 @@ impl ::buffa::Message for Value { }); } if let ::core::option::Option::Some( - buffa_::oneof::value::Kind::StructValue(ref mut existing), + __buffa::oneof::value::Kind::StructValue(ref mut existing), ) = self.kind { ::buffa::Message::merge_length_delimited( @@ -541,7 +541,7 @@ impl ::buffa::Message for Value { let mut val = ::core::default::Default::default(); ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::StructValue( + __buffa::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new(val), ), ); @@ -556,7 +556,7 @@ impl ::buffa::Message for Value { }); } if let ::core::option::Option::Some( - buffa_::oneof::value::Kind::ListValue(ref mut existing), + __buffa::oneof::value::Kind::ListValue(ref mut existing), ) = self.kind { ::buffa::Message::merge_length_delimited( @@ -568,7 +568,7 @@ impl ::buffa::Message for Value { let mut val = ::core::default::Default::default(); ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::ListValue( + __buffa::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new(val), ), ); @@ -608,7 +608,7 @@ impl ::buffa::text::TextFormat for Value { use ::buffa::Enumeration as _; if let ::core::option::Option::Some(ref __v) = self.kind { match __v { - buffa_::oneof::value::Kind::NullValue(__v) => { + __buffa::oneof::value::Kind::NullValue(__v) => { enc.write_field_name("null_value")?; match __v { ::buffa::EnumValue::Known(__e) => { @@ -617,23 +617,23 @@ impl ::buffa::text::TextFormat for Value { ::buffa::EnumValue::Unknown(__n) => enc.write_enum_number(*__n)?, } } - buffa_::oneof::value::Kind::NumberValue(__v) => { + __buffa::oneof::value::Kind::NumberValue(__v) => { enc.write_field_name("number_value")?; enc.write_f64(*__v)?; } - buffa_::oneof::value::Kind::StringValue(__v) => { + __buffa::oneof::value::Kind::StringValue(__v) => { enc.write_field_name("string_value")?; enc.write_string(__v)?; } - buffa_::oneof::value::Kind::BoolValue(__v) => { + __buffa::oneof::value::Kind::BoolValue(__v) => { enc.write_field_name("bool_value")?; enc.write_bool(*__v)?; } - buffa_::oneof::value::Kind::StructValue(__v) => { + __buffa::oneof::value::Kind::StructValue(__v) => { enc.write_field_name("struct_value")?; enc.write_message(&**__v)?; } - buffa_::oneof::value::Kind::ListValue(__v) => { + __buffa::oneof::value::Kind::ListValue(__v) => { enc.write_field_name("list_value")?; enc.write_message(&**__v)?; } @@ -652,7 +652,7 @@ impl ::buffa::text::TextFormat for Value { match __name { "null_value" => { self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::NullValue( + __buffa::oneof::value::Kind::NullValue( dec .read_enum_by_name::() .map(::buffa::EnumValue::from)?, @@ -661,24 +661,24 @@ impl ::buffa::text::TextFormat for Value { } "number_value" => { self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::NumberValue(dec.read_f64()?), + __buffa::oneof::value::Kind::NumberValue(dec.read_f64()?), ); } "string_value" => { self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::StringValue( + __buffa::oneof::value::Kind::StringValue( dec.read_string()?.into_owned(), ), ); } "bool_value" => { self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::BoolValue(dec.read_bool()?), + __buffa::oneof::value::Kind::BoolValue(dec.read_bool()?), ); } "struct_value" => { if let ::core::option::Option::Some( - buffa_::oneof::value::Kind::StructValue(ref mut __existing), + __buffa::oneof::value::Kind::StructValue(ref mut __existing), ) = self.kind { dec.merge_message(&mut **__existing)?; @@ -686,7 +686,7 @@ impl ::buffa::text::TextFormat for Value { let mut __m = ::core::default::Default::default(); dec.merge_message(&mut __m)?; self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::StructValue( + __buffa::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new(__m), ), ); @@ -694,7 +694,7 @@ impl ::buffa::text::TextFormat for Value { } "list_value" => { if let ::core::option::Option::Some( - buffa_::oneof::value::Kind::ListValue(ref mut __existing), + __buffa::oneof::value::Kind::ListValue(ref mut __existing), ) = self.kind { dec.merge_message(&mut **__existing)?; @@ -702,7 +702,7 @@ impl ::buffa::text::TextFormat for Value { let mut __m = ::core::default::Default::default(); dec.merge_message(&mut __m)?; self.kind = ::core::option::Option::Some( - buffa_::oneof::value::Kind::ListValue( + __buffa::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new(__m), ), ); diff --git a/buffa-types/src/timestamp_ext.rs b/buffa-types/src/timestamp_ext.rs index 653dfb0..d945252 100644 --- a/buffa-types/src/timestamp_ext.rs +++ b/buffa-types/src/timestamp_ext.rs @@ -540,7 +540,7 @@ mod tests { #[test] fn timestamp_view_round_trip() { - use crate::google::protobuf::buffa_::view::TimestampView; + use crate::google::protobuf::__buffa::view::TimestampView; use crate::google::protobuf::Timestamp; use buffa::{Message, MessageView}; diff --git a/buffa-types/src/value_ext.rs b/buffa-types/src/value_ext.rs index 697da39..834bc21 100644 --- a/buffa-types/src/value_ext.rs +++ b/buffa-types/src/value_ext.rs @@ -5,7 +5,7 @@ use alloc::boxed::Box; use alloc::string::{String, ToString}; -use crate::google::protobuf::buffa_::oneof::value::Kind as KindOneof; +use crate::google::protobuf::__buffa::oneof::value::Kind as KindOneof; use crate::google::protobuf::{ListValue, NullValue, Struct, Value}; impl Value { diff --git a/buffa-types/tests/wkt_roundtrip.rs b/buffa-types/tests/wkt_roundtrip.rs index 3b1a792..95c3737 100644 --- a/buffa-types/tests/wkt_roundtrip.rs +++ b/buffa-types/tests/wkt_roundtrip.rs @@ -3,7 +3,7 @@ use buffa::{Message, MessageView}; use buffa_types::google::protobuf as wkt; -use buffa_types::google::protobuf::buffa_::view as wkt_view; +use buffa_types::google::protobuf::__buffa::view as wkt_view; fn encode_decode(msg: &T) -> T { let bytes = msg.encode_to_vec(); diff --git a/buffa/src/lib.rs b/buffa/src/lib.rs index 7de691a..1173c54 100644 --- a/buffa/src/lib.rs +++ b/buffa/src/lib.rs @@ -121,13 +121,13 @@ pub use ::bytes; /// Include the generated stitcher for a proto **package** from `OUT_DIR`. /// /// Codegen emits one `.mod.rs` per package which `include!`s the -/// per-proto content files and authors the `buffa_::{view, oneof, ext}` +/// per-proto content files and authors the `__buffa::{view, oneof, ext}` /// ancillary tree, so a single macro call brings in everything. /// /// `$pkg` is the **dotted proto package literal** exactly as it appears /// in the `.proto`'s `package` declaration (e.g. `"google.protobuf"`, /// not a Rust path or the `.proto` file path). For protos with no -/// `package` declaration, pass `"buffa_"` (the reserved sentinel; no +/// `package` declaration, pass `"__buffa"` (the reserved sentinel; no /// real package can use it). /// /// ```ignore @@ -151,7 +151,7 @@ macro_rules! include_proto { /// /// `$pkg` is the dotted proto package literal exactly as in the /// `.proto`'s `package` declaration; for the unnamed package pass -/// `"buffa_"`. `$dir` is relative to the calling source file. +/// `"__buffa"`. `$dir` is relative to the calling source file. /// /// ```ignore /// pub mod protobuf { diff --git a/conformance/src/main.rs b/conformance/src/main.rs index 6e50505..46dc7ee 100644 --- a/conformance/src/main.rs +++ b/conformance/src/main.rs @@ -115,15 +115,15 @@ fn setup_type_registry() { // (JSON + text) + extension entries. `test_messages_proto3.proto` // has no extensions, so its register_types is Any-only; // `test_messages_proto2.proto` declares `extension_int32` at field 120. - proto3::buffa_::register_types(&mut reg); - proto2::buffa_::register_types(&mut reg); + proto3::__buffa::register_types(&mut reg); + proto2::__buffa::register_types(&mut reg); #[cfg(has_editions_protos)] { - editions_proto3::buffa_::register_types(&mut reg); - editions_proto2::buffa_::register_types(&mut reg); + editions_proto3::__buffa::register_types(&mut reg); + editions_proto2::__buffa::register_types(&mut reg); // Edition2023's `groupliketype` / `delimited_ext` extensions — // needed for the text `[pkg.ext] { ... }` bracket tests. - protobuf_test_messages_editions::buffa_::register_types(&mut reg); + protobuf_test_messages_editions::__buffa::register_types(&mut reg); } set_type_registry(reg); @@ -329,21 +329,21 @@ fn process_via_view(req: &envelope::Request) -> envelope::Response { match req.message_type.as_str() { MSG_PROTO3 => roundtrip_proto3( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_proto3_binary, ), MSG_PROTO2 => roundtrip_proto2( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_proto2_binary, ), #[cfg(has_editions_protos)] MSG_EDITIONS_PROTO3 => roundtrip( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_binary, ), #[cfg(has_editions_protos)] MSG_EDITIONS_PROTO2 => roundtrip( - || decode_binary_via_view::>(b), + || decode_binary_via_view::>(b), encode_binary, ), other => Response::Skipped(format!("message type '{other}' not in view dispatch")), diff --git a/examples/addressbook/src/main.rs b/examples/addressbook/src/main.rs index 031c707..c9af9cb 100644 --- a/examples/addressbook/src/main.rs +++ b/examples/addressbook/src/main.rs @@ -19,7 +19,7 @@ mod proto { } use buffa::{EnumValue, Message}; -use proto::buffa::examples::addressbook::v1::buffa_::oneof::person::Address as AddressOneof; +use proto::buffa::examples::addressbook::v1::__buffa::oneof::person::Address as AddressOneof; use proto::buffa::examples::addressbook::v1::{ person::{PhoneNumber, PhoneType}, AddressBook, Person, StructuredAddress, diff --git a/examples/envelope/src/main.rs b/examples/envelope/src/main.rs index d8e254f..07f698d 100644 --- a/examples/envelope/src/main.rs +++ b/examples/envelope/src/main.rs @@ -7,7 +7,7 @@ mod proto { } use buffa::{ExtensionSet, Message}; -use proto::buffa::examples::envelope::buffa_::ext::{PRIORITY, RETRY_COUNT, ROUTING_HOPS, TRACE}; +use proto::buffa::examples::envelope::__buffa::ext::{PRIORITY, RETRY_COUNT, ROUTING_HOPS, TRACE}; use proto::buffa::examples::envelope::{Envelope, TraceContext}; fn main() { @@ -135,7 +135,7 @@ fn json_roundtrip() { // Codegen emits this per package. It registers extension JSON // converters, extension text converters, and `Any` type entries — one // call covers all. - proto::buffa::examples::envelope::buffa_::register_types(&mut reg); + proto::buffa::examples::envelope::__buffa::register_types(&mut reg); set_type_registry(reg); let mut env = Envelope { diff --git a/examples/logging/src/gen/buffa.examples.context.v1.mod.rs b/examples/logging/src/gen/buffa.examples.context.v1.mod.rs index cd248b5..571428b 100644 --- a/examples/logging/src/gen/buffa.examples.context.v1.mod.rs +++ b/examples/logging/src/gen/buffa.examples.context.v1.mod.rs @@ -8,9 +8,10 @@ include!("context.v1.context.rs"); clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, - clippy::doc_lazy_continuation + clippy::doc_lazy_continuation, + clippy::module_inception )] -pub mod buffa_ { +pub mod __buffa { #[allow(unused_imports)] use super::*; pub mod oneof { diff --git a/examples/logging/src/gen/buffa.examples.log.v1.mod.rs b/examples/logging/src/gen/buffa.examples.log.v1.mod.rs index 02c1f1c..c6c5cfa 100644 --- a/examples/logging/src/gen/buffa.examples.log.v1.mod.rs +++ b/examples/logging/src/gen/buffa.examples.log.v1.mod.rs @@ -8,9 +8,10 @@ include!("log.v1.log.rs"); clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, - clippy::doc_lazy_continuation + clippy::doc_lazy_continuation, + clippy::module_inception )] -pub mod buffa_ { +pub mod __buffa { #[allow(unused_imports)] use super::*; pub mod oneof { diff --git a/examples/logging/src/gen/mod.rs b/examples/logging/src/gen/mod.rs index e72944d..03ada66 100644 --- a/examples/logging/src/gen/mod.rs +++ b/examples/logging/src/gen/mod.rs @@ -1,25 +1,25 @@ // @generated by buffa-codegen. DO NOT EDIT. -#![allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] +#![allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] -#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] +#[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] pub mod buffa { use super::*; - #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] + #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] pub mod examples { use super::*; - #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] + #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] pub mod context { use super::*; - #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] + #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] pub mod v1 { use super::*; include!("buffa.examples.context.v1.mod.rs"); } } - #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] + #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] pub mod log { use super::*; - #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation)] + #[allow(non_camel_case_types, dead_code, unused_imports, clippy::derivable_impls, clippy::match_single_binding, clippy::uninlined_format_args, clippy::doc_lazy_continuation, clippy::module_inception)] pub mod v1 { use super::*; include!("buffa.examples.log.v1.mod.rs");