use alloc::boxed::Box;
use super::value::ValueRef;
use super::DynamicMessage;
use crate::{DescriptorPool, FieldDescriptor, MessageDescriptor, OneofDescriptor};
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `ReflectMessage`, which vtable-mode reflection requires on this embedded type",
note = "if `{Self}` comes from another buffa-generated crate via an extern path (well-known types resolve to `buffa-types` by default), enable that crate's reflection feature, e.g. `buffa-types = {{ version = \"...\", features = [\"reflect\"] }}`",
note = "view reflection cannot degrade across modes: every view type embedded in a vtable-mode view must itself be vtable-grade (owned messages degrade through `Reflectable::reflect()` instead)",
note = "if `{Self}` is generated in this crate, its `build.rs` config must use `reflect_mode(ReflectMode::VTable)`"
)]
pub trait ReflectMessage {
fn message_descriptor(&self) -> &MessageDescriptor;
fn pool(&self) -> &alloc::sync::Arc<DescriptorPool>;
fn get(&self, field: &FieldDescriptor) -> ValueRef<'_>;
fn has(&self, field: &FieldDescriptor) -> bool;
fn for_each_set(&self, f: &mut dyn FnMut(&FieldDescriptor, ValueRef<'_>));
fn unknown_fields(&self) -> &buffa::UnknownFields {
static EMPTY: buffa::UnknownFields = buffa::UnknownFields::new();
&EMPTY
}
fn which_oneof(&self, oneof: &OneofDescriptor) -> Option<&FieldDescriptor> {
let md = self.message_descriptor();
for &i in oneof.field_indices() {
if let Some(fd) = md.fields().get(i as usize) {
if self.has(fd) {
return Some(fd);
}
}
}
None
}
fn to_dynamic(&self) -> DynamicMessage;
}
pub trait ReflectMessageMut: ReflectMessage {
fn set(&mut self, field: &FieldDescriptor, value: super::Value);
fn clear(&mut self, field: &FieldDescriptor);
}
pub enum ReflectCow<'a> {
Borrowed(&'a dyn ReflectMessage),
Owned(Box<DynamicMessage>),
}
impl core::fmt::Debug for ReflectCow<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Borrowed(_) => write!(f, "ReflectCow::Borrowed(..)"),
Self::Owned(d) => f.debug_tuple("ReflectCow::Owned").field(d).finish(),
}
}
}
impl<'a> ReflectCow<'a> {
#[must_use]
pub fn to_dynamic(&self) -> DynamicMessage {
match self {
Self::Borrowed(m) => m.to_dynamic(),
Self::Owned(d) => (**d).clone(),
}
}
}
impl<'a> core::ops::Deref for ReflectCow<'a> {
type Target = dyn ReflectMessage + 'a;
fn deref(&self) -> &Self::Target {
match self {
Self::Borrowed(m) => *m,
Self::Owned(d) => &**d,
}
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Reflectable` — no reflection is enabled for this message type",
note = "if `{Self}` comes from another buffa-generated crate via an extern path (well-known types resolve to `buffa-types` by default), enable that crate's reflection feature, e.g. `buffa-types = {{ version = \"...\", features = [\"reflect\"] }}`",
note = "if `{Self}` is generated in this crate, enable reflection in its `build.rs` config: `generate_reflection(true)` (vtable) or `reflect_mode(ReflectMode::Bridge)` for the smaller bridge impl — either emits `Reflectable`"
)]
pub trait Reflectable {
#[must_use = "reflect() returns a reflective handle borrowing self; bind it before reading fields"]
fn reflect(&self) -> ReflectCow<'_>;
}