use crate::{
array_debug, enum_debug, list_debug, map_debug, set_debug, struct_debug, tuple_debug,
tuple_struct_debug, DynamicTypePath, DynamicTyped, OpaqueInfo, ReflectCloneError, ReflectKind,
ReflectKindMismatchError, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, Typed,
};
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::string::ToString;
use core::{
any::{Any, TypeId},
fmt::Debug,
};
use thiserror::Error;
use crate::utility::NonGenericTypeInfoCell;
#[derive(Error, Debug)]
pub enum ApplyError {
#[error("attempted to apply `{from_kind}` to `{to_kind}`")]
MismatchedKinds {
from_kind: ReflectKind,
to_kind: ReflectKind,
},
#[error("enum variant `{variant_name}` doesn't have a field named `{field_name}`")]
MissingEnumField {
variant_name: Box<str>,
field_name: Box<str>,
},
#[error("`{from_type}` is not `{to_type}`")]
MismatchedTypes {
from_type: Box<str>,
to_type: Box<str>,
},
#[error("attempted to apply type with {from_size} size to a type with {to_size} size")]
DifferentSize {
from_size: usize,
to_size: usize,
},
#[error("variant with name `{variant_name}` does not exist on enum `{enum_name}`")]
UnknownVariant {
enum_name: Box<str>,
variant_name: Box<str>,
},
}
impl From<ReflectKindMismatchError> for ApplyError {
fn from(value: ReflectKindMismatchError) -> Self {
Self::MismatchedKinds {
from_kind: value.received,
to_kind: value.expected,
}
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `PartialReflect` so cannot be introspected",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait PartialReflect: DynamicTypePath + Send + Sync
where
Self: 'static,
{
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>;
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect>;
fn as_partial_reflect(&self) -> &dyn PartialReflect;
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect;
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>;
fn try_as_reflect(&self) -> Option<&dyn Reflect>;
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect>;
fn apply(&mut self, value: &dyn PartialReflect) {
PartialReflect::try_apply(self, value).unwrap();
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError>;
fn reflect_kind(&self) -> ReflectKind {
self.reflect_ref().kind()
}
fn reflect_ref(&self) -> ReflectRef<'_>;
fn reflect_mut(&mut self) -> ReflectMut<'_>;
fn reflect_owned(self: Box<Self>) -> ReflectOwned;
fn to_dynamic(&self) -> Box<dyn PartialReflect> {
match self.reflect_ref() {
ReflectRef::Struct(dyn_struct) => Box::new(dyn_struct.to_dynamic_struct()),
ReflectRef::TupleStruct(dyn_tuple_struct) => {
Box::new(dyn_tuple_struct.to_dynamic_tuple_struct())
}
ReflectRef::Tuple(dyn_tuple) => Box::new(dyn_tuple.to_dynamic_tuple()),
ReflectRef::List(dyn_list) => Box::new(dyn_list.to_dynamic_list()),
ReflectRef::Array(dyn_array) => Box::new(dyn_array.to_dynamic_array()),
ReflectRef::Map(dyn_map) => Box::new(dyn_map.to_dynamic_map()),
ReflectRef::Set(dyn_set) => Box::new(dyn_set.to_dynamic_set()),
ReflectRef::Enum(dyn_enum) => Box::new(dyn_enum.to_dynamic_enum()),
#[cfg(feature = "functions")]
ReflectRef::Function(dyn_function) => Box::new(dyn_function.to_dynamic_function()),
ReflectRef::Opaque(value) => value.reflect_clone().unwrap().into_partial_reflect(),
}
}
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Err(ReflectCloneError::NotImplemented {
type_path: Cow::Owned(self.reflect_type_path().to_string()),
})
}
fn reflect_clone_and_take<T: 'static>(&self) -> Result<T, ReflectCloneError>
where
Self: TypePath + Sized,
{
self.reflect_clone()?
.take()
.map_err(|_| ReflectCloneError::FailedDowncast {
expected: Cow::Borrowed(<Self as TypePath>::type_path()),
received: Cow::Owned(self.reflect_type_path().to_string()),
})
}
fn reflect_hash(&self) -> Option<u64> {
None
}
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
None
}
fn debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.reflect_ref() {
ReflectRef::Struct(dyn_struct) => struct_debug(dyn_struct, f),
ReflectRef::TupleStruct(dyn_tuple_struct) => tuple_struct_debug(dyn_tuple_struct, f),
ReflectRef::Tuple(dyn_tuple) => tuple_debug(dyn_tuple, f),
ReflectRef::List(dyn_list) => list_debug(dyn_list, f),
ReflectRef::Array(dyn_array) => array_debug(dyn_array, f),
ReflectRef::Map(dyn_map) => map_debug(dyn_map, f),
ReflectRef::Set(dyn_set) => set_debug(dyn_set, f),
ReflectRef::Enum(dyn_enum) => enum_debug(dyn_enum, f),
#[cfg(feature = "functions")]
ReflectRef::Function(dyn_function) => dyn_function.fmt(f),
ReflectRef::Opaque(_) => write!(f, "Reflect({})", self.reflect_type_path()),
}
}
fn is_dynamic(&self) -> bool {
false
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Reflect` so cannot be fully reflected",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait Reflect: PartialReflect + DynamicTyped + Any {
fn into_any(self: Box<Self>) -> Box<dyn Any>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect>;
fn as_reflect(&self) -> &dyn Reflect;
fn as_reflect_mut(&mut self) -> &mut dyn Reflect;
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
}
impl dyn PartialReflect {
#[inline]
pub fn represents<T: Reflect + TypePath>(&self) -> bool {
self.get_represented_type_info()
.is_some_and(|t| t.type_path() == T::type_path())
}
pub fn try_downcast<T: Any>(
self: Box<dyn PartialReflect>,
) -> Result<Box<T>, Box<dyn PartialReflect>> {
self.try_into_reflect()?
.downcast()
.map_err(PartialReflect::into_partial_reflect)
}
pub fn try_take<T: Any>(self: Box<dyn PartialReflect>) -> Result<T, Box<dyn PartialReflect>> {
self.try_downcast().map(|value| *value)
}
pub fn try_downcast_ref<T: Any>(&self) -> Option<&T> {
self.try_as_reflect()?.downcast_ref()
}
pub fn try_downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
self.try_as_reflect_mut()?.downcast_mut()
}
}
impl Debug for dyn PartialReflect {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl TypePath for dyn PartialReflect {
fn type_path() -> &'static str {
"dyn bevy_reflect::PartialReflect"
}
fn short_type_path() -> &'static str {
"dyn PartialReflect"
}
}
#[deny(rustdoc::broken_intra_doc_links)]
impl dyn Reflect {
pub fn downcast<T: Any>(self: Box<dyn Reflect>) -> Result<Box<T>, Box<dyn Reflect>> {
if self.is::<T>() {
Ok(self.into_any().downcast().unwrap())
} else {
Err(self)
}
}
pub fn take<T: Any>(self: Box<dyn Reflect>) -> Result<T, Box<dyn Reflect>> {
self.downcast::<T>().map(|value| *value)
}
#[inline]
pub fn is<T: Any>(&self) -> bool {
self.as_any().type_id() == TypeId::of::<T>()
}
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref::<T>()
}
#[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
self.as_any_mut().downcast_mut::<T>()
}
}
impl Debug for dyn Reflect {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl Typed for dyn Reflect {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}
impl TypePath for dyn Reflect {
fn type_path() -> &'static str {
"dyn bevy_reflect::Reflect"
}
fn short_type_path() -> &'static str {
"dyn Reflect"
}
}
macro_rules! impl_full_reflect {
($(<$($id:ident),* $(,)?>)? for $ty:ty $(where $($tt:tt)*)?) => {
impl $(<$($id),*>)? $crate::Reflect for $ty $(where $($tt)*)? {
fn into_any(self: bevy_platform::prelude::Box<Self>) -> bevy_platform::prelude::Box<dyn ::core::any::Any> {
self
}
fn as_any(&self) -> &dyn ::core::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
self
}
fn into_reflect(self: bevy_platform::prelude::Box<Self>) -> bevy_platform::prelude::Box<dyn $crate::Reflect> {
self
}
fn as_reflect(&self) -> &dyn $crate::Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn $crate::Reflect {
self
}
fn set(
&mut self,
value: bevy_platform::prelude::Box<dyn $crate::Reflect>,
) -> Result<(), bevy_platform::prelude::Box<dyn $crate::Reflect>> {
*self = <dyn $crate::Reflect>::take(value)?;
Ok(())
}
}
};
}
pub(crate) use impl_full_reflect;