buffa_types/lib.rs
1//! Protobuf well-known types for buffa.
2//!
3//! This crate provides Rust types for Google's well-known `.proto` types:
4//!
5//! - [`google::protobuf::Timestamp`] — Unix timestamp with nanosecond precision
6//! - [`google::protobuf::Duration`] — Signed duration with nanosecond precision
7//! - [`google::protobuf::Any`] — Any value with an attached type URL
8//! - [`google::protobuf::Struct`] / [`google::protobuf::Value`] / [`google::protobuf::ListValue`]
9//! — JSON-like dynamic values
10//! - [`google::protobuf::FieldMask`] — Specifies a subset of fields referenced in a message
11//! - [`google::protobuf::Empty`] — A generic empty message
12//! - Wrapper types: [`google::protobuf::BoolValue`], [`google::protobuf::Int32Value`],
13//! [`google::protobuf::Int64Value`], [`google::protobuf::UInt32Value`],
14//! [`google::protobuf::UInt64Value`], [`google::protobuf::FloatValue`],
15//! [`google::protobuf::DoubleValue`], [`google::protobuf::StringValue`],
16//! [`google::protobuf::BytesValue`]
17//!
18//! # Usage
19//!
20//! ```rust,no_run
21//! use buffa_types::google::protobuf::Timestamp;
22//! use buffa::Message;
23//!
24//! let ts = Timestamp { seconds: 1_000_000_000, nanos: 0, ..Default::default() };
25//! let bytes = ts.encode_to_vec();
26//! let decoded = Timestamp::decode_from_slice(&bytes).unwrap();
27//! assert_eq!(ts, decoded);
28//! ```
29//!
30//! # Ergonomic helpers
31//!
32//! Common Rust type conversions are provided as trait impls:
33//!
34//! - `Timestamp` ↔ [`std::time::SystemTime`] (requires `std` feature)
35//! - `Duration` ↔ [`std::time::Duration`] (requires `std` feature)
36//! - `Timestamp` ↔ [`chrono::DateTime`] (requires `chrono` feature; any time
37//! zone in, `Utc` out)
38//! - `Duration` ↔ [`chrono::TimeDelta`] (requires `chrono` feature)
39//! - `Any::pack` / `Any::unpack` helpers
40//! - `Value` constructors: [`Value::null`](google::protobuf::Value::null), `From<f64>`, `From<String>`, `From<bool>`, etc.
41//! - Wrapper type `From`/`Into` impls
42//!
43//! # Cargo features
44//!
45//! - **`std`** (default) — standard-library integration (`SystemTime`/`Duration`
46//! conversions, `std::error::Error`). Without it the crate is `no_std` + `alloc`.
47//! - **`json`** — proto3 canonical JSON serde for the WKTs.
48//! - **`arbitrary`** — `arbitrary::Arbitrary` derives for fuzzing.
49//! - **`chrono`** — `Timestamp` ↔ `chrono::DateTime` and `Duration` ↔
50//! `chrono::TimeDelta` conversions. `no_std`-compatible (`chrono` is pulled
51//! with `default-features = false`).
52//! - **`reflect`** — runtime reflection: the WKT view types implement
53//! `buffa_descriptor::reflect::ReflectMessage`, so a message that has a WKT
54//! field can reflect over it. This pulls a `buffa-descriptor` dependency and
55//! requires `std` (the embedded descriptor pool uses `std::sync::OnceLock`).
56//! If you reach for `&view as &dyn ReflectMessage` on a WKT view and the
57//! compiler says `ReflectMessage` is not implemented, enable this feature.
58
59#![cfg_attr(not(feature = "std"), no_std)]
60#![cfg_attr(docsrs, feature(doc_cfg))]
61#![deny(rustdoc::broken_intra_doc_links)]
62extern crate alloc;
63
64// Extension modules (ergonomic helpers — hand-written, not generated).
65mod any_ext;
66mod duration_ext;
67mod empty_ext;
68mod field_mask_ext;
69mod timestamp_ext;
70mod value_ext;
71#[cfg(feature = "json")]
72mod view_serde_ext;
73mod wrapper_ext;
74
75#[cfg(feature = "chrono")]
76mod duration_chrono;
77#[cfg(feature = "chrono")]
78mod timestamp_chrono;
79
80// Well-known type Rust structs — generated once by `gen_wkt_types`, checked
81// into src/generated/. These protos are Google-owned and frozen; regeneration
82// is only needed when buffa-codegen's output format changes. See the
83// `task gen-wkt-types` target and the `check-generated-code` CI job.
84//
85// The checked-in approach means consumers of buffa-types need only the
86// `buffa` runtime — NOT protoc, NOT buffa-build, NOT buffa-codegen.
87//
88// The allow attributes suppress lints that fire on generated code:
89// derivable_impls — enum Default impls are explicit rather than derived
90// match_single_binding — empty messages generate a single-arm wildcard merge
91#[allow(
92 clippy::derivable_impls,
93 clippy::match_single_binding,
94 non_camel_case_types
95)]
96pub mod google {
97 pub mod protobuf {
98 include!("generated/google.protobuf.mod.rs");
99 }
100}
101
102// Convenience re-exports of the most commonly-used well-known types.
103// Full paths (`google::protobuf::*`) remain available for disambiguation.
104// Wrapper types (Int32Value, etc.) are NOT re-exported to avoid name
105// collisions with similarly-named types in user code.
106pub use google::protobuf::{
107 Any, Duration, Empty, FieldMask, ListValue, NullValue, Struct, Timestamp, Value,
108};
109
110// Re-export error types from extension modules (these are hand-written types
111// in private modules, so re-exporting is the only way to make them accessible).
112pub use duration_ext::DurationError;
113pub use timestamp_ext::TimestampError;
114
115#[cfg(feature = "chrono")]
116#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
117pub use duration_chrono::DurationChronoError;
118
119// Re-export the WKT registry function for `Any` JSON + text support.
120pub use any_ext::register_wkt_types;
121
122#[cfg(test)]
123mod full_name_tests {
124 use super::google::protobuf::*;
125 use buffa::MessageName;
126
127 // Regression test: the WKT FQNs are baked into Any type-URLs, JSON
128 // serialization, and the type registry. Codegen must keep emitting them
129 // verbatim — these strings are observable on the wire.
130 #[test]
131 fn well_known_types_full_names_match_proto() {
132 assert_eq!(Timestamp::FULL_NAME, "google.protobuf.Timestamp");
133 assert_eq!(Duration::FULL_NAME, "google.protobuf.Duration");
134 assert_eq!(Any::FULL_NAME, "google.protobuf.Any");
135 assert_eq!(Empty::FULL_NAME, "google.protobuf.Empty");
136 assert_eq!(FieldMask::FULL_NAME, "google.protobuf.FieldMask");
137 assert_eq!(Struct::FULL_NAME, "google.protobuf.Struct");
138 assert_eq!(Value::FULL_NAME, "google.protobuf.Value");
139 assert_eq!(ListValue::FULL_NAME, "google.protobuf.ListValue");
140 }
141}