Skip to main content

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}