buffa_reflect/reflect.rs
1//! [`ReflectMessage`] — the runtime hand-off from a generated buffa message
2//! type to its descriptor.
3
4use crate::message::MessageDescriptor;
5
6/// Implemented by every type that has a descriptor in some
7/// [`crate::DescriptorPool`] — generated typed messages via
8/// `#[derive(ReflectMessage)]` and runtime-typed
9/// [`crate::DynamicMessage`].
10///
11/// Note: this trait deliberately does **not** require
12/// [`buffa::Message`] as a super-trait so that
13/// [`crate::DynamicMessage`] (which has no static
14/// `DefaultInstance`) can implement it. Where wire-encoding via
15/// `Self::encode_to_vec` is needed, individual methods name
16/// `Self: ::buffa::Message` as a where-clause.
17pub trait ReflectMessage {
18 /// Resolve the [`MessageDescriptor`] for `Self`.
19 ///
20 /// The pool the descriptor lives in is set up by the
21 /// `#[derive(ReflectMessage)]` macro, either:
22 /// * the user-supplied `descriptor_pool` expression, or
23 /// * a lazily-decoded pool keyed off the embedded `file_descriptor_set_bytes`.
24 fn descriptor(&self) -> MessageDescriptor;
25
26 /// Round-trip `self` through wire bytes into a [`crate::DynamicMessage`].
27 ///
28 /// The default implementation pays one wire round-trip; the impl
29 /// for [`crate::DynamicMessage`] short-circuits to `self.clone()`.
30 ///
31 /// # Panics
32 ///
33 /// Panics if `self.encode_to_vec()` produces bytes that fail to
34 /// decode against `self.descriptor()` — this would indicate a bug
35 /// in the generated [`descriptor()`](Self::descriptor) wiring or in
36 /// `self`'s `Message` impl.
37 #[cfg(feature = "dynamic")]
38 fn transcode_to_dynamic(&self) -> crate::DynamicMessage
39 where
40 Self: ::buffa::Message + Sized,
41 {
42 let descriptor = self.descriptor();
43 let bytes = ::buffa::Message::encode_to_vec(self);
44 crate::DynamicMessage::decode(descriptor, bytes.as_slice())
45 .expect("self-encoded message must decode against its own descriptor")
46 }
47}
48
49/// Reflection over a buffa view type. Implemented by every generated
50/// `*View<'a>` so the zero-copy decode path can introspect the
51/// message without allocating an owned form.
52///
53/// `descriptor()` returns the same [`MessageDescriptor`] the owned
54/// [`ReflectMessage`] returns for the same proto.
55pub trait ReflectMessageView<'a>: ::buffa::view::MessageView<'a> {
56 /// Resolve the [`MessageDescriptor`] for this view's proto type.
57 fn descriptor(&self) -> MessageDescriptor;
58}
59
60#[cfg(feature = "dynamic")]
61impl ReflectMessage for crate::DynamicMessage {
62 fn descriptor(&self) -> MessageDescriptor {
63 crate::DynamicMessage::descriptor(self)
64 }
65
66 // `transcode_to_dynamic` is intentionally not overridden here —
67 // the trait's default impl carries `where Self: buffa::Message`,
68 // which `DynamicMessage` cannot satisfy. Callers reach the
69 // short-circuit via the inherent
70 // [`crate::DynamicMessage::transcode_to_dynamic`], which has the
71 // same name and resolves first under Rust's method-resolution rules.
72}