Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

525
vendor/bevy_reflect/src/array.rs vendored Normal file
View File

@@ -0,0 +1,525 @@
use crate::generics::impl_generic_info_methods;
use crate::{
type_info::impl_type_methods, utility::reflect_hasher, ApplyError, Generics, MaybeTyped,
PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo,
TypePath,
};
use alloc::{boxed::Box, vec::Vec};
use bevy_reflect_derive::impl_type_path;
use core::{
any::Any,
fmt::{Debug, Formatter},
hash::{Hash, Hasher},
};
/// A trait used to power [array-like] operations via [reflection].
///
/// This corresponds to true Rust arrays like `[T; N]`,
/// but also to any fixed-size linear sequence types.
/// It is expected that implementors of this trait uphold this contract
/// and maintain a fixed size as returned by the [`Array::len`] method.
///
/// Due to the [type-erasing] nature of the reflection API as a whole,
/// this trait does not make any guarantees that the implementor's elements
/// are homogeneous (i.e. all the same type).
///
/// This trait has a blanket implementation over Rust arrays of up to 32 items.
/// This implementation can technically contain more than 32,
/// but the blanket [`GetTypeRegistration`] is only implemented up to the 32
/// item limit due to a [limitation] on [`Deserialize`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Array};
///
/// let foo: &dyn Array = &[123_u32, 456_u32, 789_u32];
/// assert_eq!(foo.len(), 3);
///
/// let field: &dyn PartialReflect = foo.get(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
/// [reflection]: crate
/// [`List`]: crate::List
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
/// [`GetTypeRegistration`]: crate::GetTypeRegistration
/// [limitation]: https://github.com/serde-rs/serde/issues/1937
/// [`Deserialize`]: ::serde::Deserialize
pub trait Array: PartialReflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of elements in the array.
fn len(&self) -> usize;
/// Returns `true` if the collection contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the array.
fn iter(&self) -> ArrayIter;
/// Drain the elements of this array to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the list, producing a [`DynamicArray`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_array` instead")]
fn clone_dynamic(&self) -> DynamicArray {
self.to_dynamic_array()
}
/// Creates a new [`DynamicArray`] from this array.
fn to_dynamic_array(&self) -> DynamicArray {
DynamicArray {
represented_type: self.get_represented_type_info(),
values: self.iter().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_array_info(&self) -> Option<&'static ArrayInfo> {
self.get_represented_type_info()?.as_array().ok()
}
}
/// A container for compile-time array info.
#[derive(Clone, Debug)]
pub struct ArrayInfo {
ty: Type,
generics: Generics,
item_info: fn() -> Option<&'static TypeInfo>,
item_ty: Type,
capacity: usize,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl ArrayInfo {
/// Create a new [`ArrayInfo`].
///
/// # Arguments
///
/// * `capacity`: The maximum capacity of the underlying array.
pub fn new<TArray: Array + TypePath, TItem: Reflect + MaybeTyped + TypePath>(
capacity: usize,
) -> Self {
Self {
ty: Type::of::<TArray>(),
generics: Generics::new(),
item_info: TItem::maybe_type_info,
item_ty: Type::of::<TItem>(),
capacity,
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this array.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// The compile-time capacity of the array.
pub fn capacity(&self) -> usize {
self.capacity
}
impl_type_methods!(ty);
/// The [`TypeInfo`] of the array item.
///
/// Returns `None` if the array item does not contain static type information,
/// such as for dynamic types.
pub fn item_info(&self) -> Option<&'static TypeInfo> {
(self.item_info)()
}
/// The [type] of the array item.
///
/// [type]: Type
pub fn item_ty(&self) -> Type {
self.item_ty
}
/// The docstring of this array, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// A fixed-size list of reflected values.
///
/// This differs from [`DynamicList`] in that the size of the [`DynamicArray`]
/// is constant, whereas a [`DynamicList`] can have items added and removed.
///
/// This isn't to say that a [`DynamicArray`] is immutable— its items
/// can be mutated— just that the _number_ of items cannot change.
///
/// [`DynamicList`]: crate::DynamicList
#[derive(Debug)]
pub struct DynamicArray {
pub(crate) represented_type: Option<&'static TypeInfo>,
pub(crate) values: Box<[Box<dyn PartialReflect>]>,
}
impl DynamicArray {
#[inline]
pub fn new(values: Box<[Box<dyn PartialReflect>]>) -> Self {
Self {
represented_type: None,
values,
}
}
/// Sets the [type] to be represented by this `DynamicArray`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Array`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Array(_)),
"expected TypeInfo::Array but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
}
impl PartialReflect for DynamicArray {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
array_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
array_try_apply(self, value)
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Array
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Array(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Array(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Array(self)
}
#[inline]
fn reflect_hash(&self) -> Option<u64> {
array_hash(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
array_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicArray(")?;
array_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl Array for DynamicArray {
#[inline]
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
self.values.get(index).map(|value| &**value)
}
#[inline]
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
#[inline]
fn len(&self) -> usize {
self.values.len()
}
#[inline]
fn iter(&self) -> ArrayIter {
ArrayIter::new(self)
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.values.into_vec()
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicArray {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect::<Vec<_>>().into_boxed_slice(),
}
}
}
impl<T: PartialReflect> FromIterator<T> for DynamicArray {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|value| Box::new(value).into_partial_reflect())
.collect()
}
}
impl IntoIterator for DynamicArray {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_vec().into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicArray {
type Item = &'a dyn PartialReflect;
type IntoIter = ArrayIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl_type_path!((in bevy_reflect) DynamicArray);
/// An iterator over an [`Array`].
pub struct ArrayIter<'a> {
array: &'a dyn Array,
index: usize,
}
impl ArrayIter<'_> {
/// Creates a new [`ArrayIter`].
#[inline]
pub const fn new(array: &dyn Array) -> ArrayIter {
ArrayIter { array, index: 0 }
}
}
impl<'a> Iterator for ArrayIter<'a> {
type Item = &'a dyn PartialReflect;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let value = self.array.get(self.index);
self.index += value.is_some() as usize;
value
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.array.len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for ArrayIter<'a> {}
/// Returns the `u64` hash of the given [array](Array).
#[inline]
pub fn array_hash<A: Array + ?Sized>(array: &A) -> Option<u64> {
let mut hasher = reflect_hasher();
Any::type_id(array).hash(&mut hasher);
array.len().hash(&mut hasher);
for value in array.iter() {
hasher.write_u64(value.reflect_hash()?);
}
Some(hasher.finish())
}
/// Applies the reflected [array](Array) data to the given [array](Array).
///
/// # Panics
///
/// * Panics if the two arrays have differing lengths.
/// * Panics if the reflected value is not a [valid array](ReflectRef::Array).
#[inline]
pub fn array_apply<A: Array + ?Sized>(array: &mut A, reflect: &dyn PartialReflect) {
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
if array.len() != reflect_array.len() {
panic!("Attempted to apply different sized `Array` types.");
}
for (i, value) in reflect_array.iter().enumerate() {
let v = array.get_mut(i).unwrap();
v.apply(value);
}
} else {
panic!("Attempted to apply a non-`Array` type to an `Array` type.");
}
}
/// Tries to apply the reflected [array](Array) data to the given [array](Array) and
/// returns a Result.
///
/// # Errors
///
/// * Returns an [`ApplyError::DifferentSize`] if the two arrays have differing lengths.
/// * Returns an [`ApplyError::MismatchedKinds`] if the reflected value is not a
/// [valid array](ReflectRef::Array).
/// * Returns any error that is generated while applying elements to each other.
#[inline]
pub fn array_try_apply<A: Array>(
array: &mut A,
reflect: &dyn PartialReflect,
) -> Result<(), ApplyError> {
let reflect_array = reflect.reflect_ref().as_array()?;
if array.len() != reflect_array.len() {
return Err(ApplyError::DifferentSize {
from_size: reflect_array.len(),
to_size: array.len(),
});
}
for (i, value) in reflect_array.iter().enumerate() {
let v = array.get_mut(i).unwrap();
v.try_apply(value)?;
}
Ok(())
}
/// Compares two [arrays](Array) (one concrete and one reflected) to see if they
/// are equal.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn array_partial_eq<A: Array + ?Sized>(
array: &A,
reflect: &dyn PartialReflect,
) -> Option<bool> {
match reflect.reflect_ref() {
ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => {
for (a, b) in array.iter().zip(reflect_array.iter()) {
let eq_result = a.reflect_partial_eq(b);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}
}
_ => return Some(false),
}
Some(true)
}
/// The default debug formatter for [`Array`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
///
/// let my_array: &dyn Reflect = &[1, 2, 3];
/// println!("{:#?}", my_array);
///
/// // Output:
///
/// // [
/// // 1,
/// // 2,
/// // 3,
/// // ]
/// ```
#[inline]
pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_list();
for item in dyn_array.iter() {
debug.entry(&item as &dyn Debug);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use crate::Reflect;
use alloc::boxed::Box;
#[test]
fn next_index_increment() {
const SIZE: usize = if cfg!(debug_assertions) {
4
} else {
// If compiled in release mode, verify we dont overflow
usize::MAX
};
let b = Box::new([(); SIZE]).into_reflect();
let array = b.reflect_ref().as_array().unwrap();
let mut iter = array.iter();
iter.index = SIZE - 1;
assert!(iter.next().is_some());
// When None we should no longer increase index
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
}
}

446
vendor/bevy_reflect/src/attributes.rs vendored Normal file
View File

@@ -0,0 +1,446 @@
use crate::Reflect;
use alloc::boxed::Box;
use bevy_utils::TypeIdMap;
use core::{
any::TypeId,
fmt::{Debug, Formatter},
};
/// A collection of custom attributes for a type, field, or variant.
///
/// These attributes can be created with the [`Reflect` derive macro].
///
/// Attributes are stored by their [`TypeId`].
/// Because of this, there can only be one attribute per type.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{Reflect, Typed, TypeInfo};
/// use core::ops::RangeInclusive;
/// #[derive(Reflect)]
/// struct Slider {
/// #[reflect(@RangeInclusive::<f32>::new(0.0, 1.0))]
/// value: f32
/// }
///
/// let TypeInfo::Struct(info) = <Slider as Typed>::type_info() else {
/// panic!("expected struct info");
/// };
///
/// let range = info.field("value").unwrap().get_attribute::<RangeInclusive<f32>>().unwrap();
/// assert_eq!(0.0..=1.0, *range);
/// ```
///
/// [`Reflect` derive macro]: derive@crate::Reflect
#[derive(Default)]
pub struct CustomAttributes {
attributes: TypeIdMap<CustomAttribute>,
}
impl CustomAttributes {
/// Inserts a custom attribute into the collection.
///
/// Note that this will overwrite any existing attribute of the same type.
pub fn with_attribute<T: Reflect>(mut self, value: T) -> Self {
self.attributes
.insert(TypeId::of::<T>(), CustomAttribute::new(value));
self
}
/// Returns `true` if this collection contains a custom attribute of the specified type.
pub fn contains<T: Reflect>(&self) -> bool {
self.attributes.contains_key(&TypeId::of::<T>())
}
/// Returns `true` if this collection contains a custom attribute with the specified [`TypeId`].
pub fn contains_by_id(&self, id: TypeId) -> bool {
self.attributes.contains_key(&id)
}
/// Gets a custom attribute by type.
pub fn get<T: Reflect>(&self) -> Option<&T> {
self.attributes.get(&TypeId::of::<T>())?.value::<T>()
}
/// Gets a custom attribute by its [`TypeId`].
pub fn get_by_id(&self, id: TypeId) -> Option<&dyn Reflect> {
Some(self.attributes.get(&id)?.reflect_value())
}
/// Returns an iterator over all custom attributes.
pub fn iter(&self) -> impl ExactSizeIterator<Item = (&TypeId, &dyn Reflect)> {
self.attributes
.iter()
.map(|(key, value)| (key, value.reflect_value()))
}
/// Returns the number of custom attributes in this collection.
pub fn len(&self) -> usize {
self.attributes.len()
}
/// Returns `true` if this collection is empty.
pub fn is_empty(&self) -> bool {
self.attributes.is_empty()
}
}
impl Debug for CustomAttributes {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.attributes.values()).finish()
}
}
struct CustomAttribute {
value: Box<dyn Reflect>,
}
impl CustomAttribute {
pub fn new<T: Reflect>(value: T) -> Self {
Self {
value: Box::new(value),
}
}
pub fn value<T: Reflect>(&self) -> Option<&T> {
self.value.downcast_ref()
}
pub fn reflect_value(&self) -> &dyn Reflect {
&*self.value
}
}
impl Debug for CustomAttribute {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.value.debug(f)
}
}
/// Implements methods for accessing custom attributes.
///
/// Implements the following methods:
///
/// * `fn custom_attributes(&self) -> &CustomAttributes`
/// * `fn get_attribute<T: Reflect>(&self) -> Option<&T>`
/// * `fn get_attribute_by_id(&self, id: TypeId) -> Option<&dyn Reflect>`
/// * `fn has_attribute<T: Reflect>(&self) -> bool`
/// * `fn has_attribute_by_id(&self, id: TypeId) -> bool`
///
/// # Params
///
/// * `$self` - The name of the variable containing the custom attributes (usually `self`).
/// * `$attributes` - The name of the field containing the [`CustomAttributes`].
/// * `$term` - (Optional) The term used to describe the type containing the custom attributes.
/// This is purely used to generate better documentation. Defaults to `"item"`.
macro_rules! impl_custom_attribute_methods {
($self:ident . $attributes:ident, $term:literal) => {
$crate::attributes::impl_custom_attribute_methods!($self, &$self.$attributes, "item");
};
($self:ident, $attributes:expr, $term:literal) => {
#[doc = concat!("Returns the custom attributes for this ", $term, ".")]
pub fn custom_attributes(&$self) -> &$crate::attributes::CustomAttributes {
$attributes
}
/// Gets a custom attribute by type.
///
/// For dynamically accessing an attribute, see [`get_attribute_by_id`](Self::get_attribute_by_id).
pub fn get_attribute<T: $crate::Reflect>(&$self) -> Option<&T> {
$self.custom_attributes().get::<T>()
}
/// Gets a custom attribute by its [`TypeId`](core::any::TypeId).
///
/// This is the dynamic equivalent of [`get_attribute`](Self::get_attribute).
pub fn get_attribute_by_id(&$self, id: ::core::any::TypeId) -> Option<&dyn $crate::Reflect> {
$self.custom_attributes().get_by_id(id)
}
#[doc = concat!("Returns `true` if this ", $term, " has a custom attribute of the specified type.")]
#[doc = "\n\nFor dynamically checking if an attribute exists, see [`has_attribute_by_id`](Self::has_attribute_by_id)."]
pub fn has_attribute<T: $crate::Reflect>(&$self) -> bool {
$self.custom_attributes().contains::<T>()
}
#[doc = concat!("Returns `true` if this ", $term, " has a custom attribute with the specified [`TypeId`](::core::any::TypeId).")]
#[doc = "\n\nThis is the dynamic equivalent of [`has_attribute`](Self::has_attribute)"]
pub fn has_attribute_by_id(&$self, id: ::core::any::TypeId) -> bool {
$self.custom_attributes().contains_by_id(id)
}
};
}
pub(crate) use impl_custom_attribute_methods;
#[cfg(test)]
mod tests {
use super::*;
use crate::{type_info::Typed, TypeInfo, VariantInfo};
use alloc::{format, string::String};
use core::ops::RangeInclusive;
#[derive(Reflect, PartialEq, Debug)]
struct Tooltip(String);
impl Tooltip {
fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
}
#[test]
fn should_get_custom_attribute() {
let attributes = CustomAttributes::default().with_attribute(0.0..=1.0);
let value = attributes.get::<RangeInclusive<f64>>().unwrap();
assert_eq!(&(0.0..=1.0), value);
}
#[test]
fn should_get_custom_attribute_dynamically() {
let attributes = CustomAttributes::default().with_attribute(String::from("Hello, World!"));
let value = attributes.get_by_id(TypeId::of::<String>()).unwrap();
assert!(value
.reflect_partial_eq(&String::from("Hello, World!"))
.unwrap());
}
#[test]
fn should_debug_custom_attributes() {
let attributes = CustomAttributes::default().with_attribute("My awesome custom attribute!");
let debug = format!("{:?}", attributes);
assert_eq!(r#"{"My awesome custom attribute!"}"#, debug);
#[derive(Reflect)]
struct Foo {
value: i32,
}
let attributes = CustomAttributes::default().with_attribute(Foo { value: 42 });
let debug = format!("{:?}", attributes);
assert_eq!(
r#"{bevy_reflect::attributes::tests::Foo { value: 42 }}"#,
debug
);
}
#[test]
fn should_derive_custom_attributes_on_struct_container() {
#[derive(Reflect)]
#[reflect(@Tooltip::new("My awesome custom attribute!"))]
struct Slider {
value: f32,
}
let TypeInfo::Struct(info) = Slider::type_info() else {
panic!("expected struct info");
};
let tooltip = info.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("My awesome custom attribute!"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_struct_fields() {
#[derive(Reflect)]
struct Slider {
#[reflect(@0.0..=1.0)]
#[reflect(@Tooltip::new("Range: 0.0 to 1.0"))]
value: f32,
}
let TypeInfo::Struct(info) = Slider::type_info() else {
panic!("expected struct info");
};
let field = info.field("value").unwrap();
let range = field.get_attribute::<RangeInclusive<f64>>().unwrap();
assert_eq!(&(0.0..=1.0), range);
let tooltip = field.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("Range: 0.0 to 1.0"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_tuple_container() {
#[derive(Reflect)]
#[reflect(@Tooltip::new("My awesome custom attribute!"))]
struct Slider(f32);
let TypeInfo::TupleStruct(info) = Slider::type_info() else {
panic!("expected tuple struct info");
};
let tooltip = info.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("My awesome custom attribute!"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_tuple_struct_fields() {
#[derive(Reflect)]
struct Slider(
#[reflect(@0.0..=1.0)]
#[reflect(@Tooltip::new("Range: 0.0 to 1.0"))]
f32,
);
let TypeInfo::TupleStruct(info) = Slider::type_info() else {
panic!("expected tuple struct info");
};
let field = info.field_at(0).unwrap();
let range = field.get_attribute::<RangeInclusive<f64>>().unwrap();
assert_eq!(&(0.0..=1.0), range);
let tooltip = field.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("Range: 0.0 to 1.0"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_enum_container() {
#[derive(Reflect)]
#[reflect(@Tooltip::new("My awesome custom attribute!"))]
enum Color {
Transparent,
Grayscale(f32),
Rgb { r: u8, g: u8, b: u8 },
}
let TypeInfo::Enum(info) = Color::type_info() else {
panic!("expected enum info");
};
let tooltip = info.get_attribute::<Tooltip>().unwrap();
assert_eq!(&Tooltip::new("My awesome custom attribute!"), tooltip);
}
#[test]
fn should_derive_custom_attributes_on_enum_variants() {
#[derive(Reflect, Debug, PartialEq)]
enum Display {
Toggle,
Slider,
Picker,
}
#[derive(Reflect)]
enum Color {
#[reflect(@Display::Toggle)]
Transparent,
#[reflect(@Display::Slider)]
Grayscale(f32),
#[reflect(@Display::Picker)]
Rgb { r: u8, g: u8, b: u8 },
}
let TypeInfo::Enum(info) = Color::type_info() else {
panic!("expected enum info");
};
let VariantInfo::Unit(transparent_variant) = info.variant("Transparent").unwrap() else {
panic!("expected unit variant");
};
let display = transparent_variant.get_attribute::<Display>().unwrap();
assert_eq!(&Display::Toggle, display);
let VariantInfo::Tuple(grayscale_variant) = info.variant("Grayscale").unwrap() else {
panic!("expected tuple variant");
};
let display = grayscale_variant.get_attribute::<Display>().unwrap();
assert_eq!(&Display::Slider, display);
let VariantInfo::Struct(rgb_variant) = info.variant("Rgb").unwrap() else {
panic!("expected struct variant");
};
let display = rgb_variant.get_attribute::<Display>().unwrap();
assert_eq!(&Display::Picker, display);
}
#[test]
fn should_derive_custom_attributes_on_enum_variant_fields() {
#[derive(Reflect)]
enum Color {
Transparent,
Grayscale(#[reflect(@0.0..=1.0_f32)] f32),
Rgb {
#[reflect(@0..=255u8)]
r: u8,
#[reflect(@0..=255u8)]
g: u8,
#[reflect(@0..=255u8)]
b: u8,
},
}
let TypeInfo::Enum(info) = Color::type_info() else {
panic!("expected enum info");
};
let VariantInfo::Tuple(grayscale_variant) = info.variant("Grayscale").unwrap() else {
panic!("expected tuple variant");
};
let field = grayscale_variant.field_at(0).unwrap();
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
assert_eq!(&(0.0..=1.0), range);
let VariantInfo::Struct(rgb_variant) = info.variant("Rgb").unwrap() else {
panic!("expected struct variant");
};
let field = rgb_variant.field("g").unwrap();
let range = field.get_attribute::<RangeInclusive<u8>>().unwrap();
assert_eq!(&(0..=255), range);
}
#[test]
fn should_allow_unit_struct_attribute_values() {
#[derive(Reflect)]
struct Required;
#[derive(Reflect)]
struct Foo {
#[reflect(@Required)]
value: i32,
}
let TypeInfo::Struct(info) = Foo::type_info() else {
panic!("expected struct info");
};
let field = info.field("value").unwrap();
assert!(field.has_attribute::<Required>());
}
#[test]
fn should_accept_last_attribute() {
#[derive(Reflect)]
struct Foo {
#[reflect(@false)]
#[reflect(@true)]
value: i32,
}
let TypeInfo::Struct(info) = Foo::type_info() else {
panic!("expected struct info");
};
let field = info.field("value").unwrap();
assert!(field.get_attribute::<bool>().unwrap());
}
}

View File

@@ -0,0 +1,419 @@
use bevy_reflect_derive::impl_type_path;
use crate::{
enum_debug, enum_hash, enum_partial_eq, ApplyError, DynamicStruct, DynamicTuple, Enum,
PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple,
TypeInfo, VariantFieldIter, VariantType,
};
use alloc::{boxed::Box, string::String};
use core::fmt::Formatter;
use derive_more::derive::From;
/// A dynamic representation of an enum variant.
#[derive(Debug, Default, From)]
pub enum DynamicVariant {
#[default]
Unit,
Tuple(DynamicTuple),
Struct(DynamicStruct),
}
impl Clone for DynamicVariant {
fn clone(&self) -> Self {
match self {
DynamicVariant::Unit => DynamicVariant::Unit,
DynamicVariant::Tuple(data) => DynamicVariant::Tuple(data.to_dynamic_tuple()),
DynamicVariant::Struct(data) => DynamicVariant::Struct(data.to_dynamic_struct()),
}
}
}
impl From<()> for DynamicVariant {
fn from(_: ()) -> Self {
Self::Unit
}
}
/// A dynamic representation of an enum.
///
/// This allows for enums to be configured at runtime.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{DynamicEnum, DynamicVariant, Reflect, PartialReflect};
///
/// // The original enum value
/// let mut value: Option<usize> = Some(123);
///
/// // Create a DynamicEnum to represent the new value
/// let mut dyn_enum = DynamicEnum::new(
/// "None",
/// DynamicVariant::Unit
/// );
///
/// // Apply the DynamicEnum as a patch to the original value
/// value.apply(dyn_enum.as_partial_reflect());
///
/// // Tada!
/// assert_eq!(None, value);
/// ```
#[derive(Default, Debug)]
pub struct DynamicEnum {
represented_type: Option<&'static TypeInfo>,
variant_name: String,
variant_index: usize,
variant: DynamicVariant,
}
impl DynamicEnum {
/// Create a new [`DynamicEnum`] to represent an enum at runtime.
///
/// # Arguments
///
/// * `variant_name`: The name of the variant to set
/// * `variant`: The variant data
pub fn new<I: Into<String>, V: Into<DynamicVariant>>(variant_name: I, variant: V) -> Self {
Self {
represented_type: None,
variant_index: 0,
variant_name: variant_name.into(),
variant: variant.into(),
}
}
/// Create a new [`DynamicEnum`] with a variant index to represent an enum at runtime.
///
/// # Arguments
///
/// * `variant_index`: The index of the variant to set
/// * `variant_name`: The name of the variant to set
/// * `variant`: The variant data
pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
variant_index: usize,
variant_name: I,
variant: V,
) -> Self {
Self {
represented_type: None,
variant_index,
variant_name: variant_name.into(),
variant: variant.into(),
}
}
/// Sets the [type] to be represented by this `DynamicEnum`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Enum`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Enum(_)),
"expected TypeInfo::Enum but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Set the current enum variant represented by this struct.
pub fn set_variant<I: Into<String>, V: Into<DynamicVariant>>(&mut self, name: I, variant: V) {
self.variant_name = name.into();
self.variant = variant.into();
}
/// Set the current enum variant represented by this struct along with its variant index.
pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
&mut self,
variant_index: usize,
variant_name: I,
variant: V,
) {
self.variant_index = variant_index;
self.variant_name = variant_name.into();
self.variant = variant.into();
}
/// Get a reference to the [`DynamicVariant`] contained in `self`.
pub fn variant(&self) -> &DynamicVariant {
&self.variant
}
/// Get a mutable reference to the [`DynamicVariant`] contained in `self`.
///
/// Using the mut reference to switch to a different variant will ___not___ update the
/// internal tracking of the variant name and index.
///
/// If you want to switch variants, prefer one of the setters:
/// [`DynamicEnum::set_variant`] or [`DynamicEnum::set_variant_with_index`].
pub fn variant_mut(&mut self) -> &mut DynamicVariant {
&mut self.variant
}
/// Create a [`DynamicEnum`] from an existing one.
///
/// This is functionally the same as [`DynamicEnum::from_ref`] except it takes an owned value.
pub fn from<TEnum: Enum>(value: TEnum) -> Self {
Self::from_ref(&value)
}
/// Create a [`DynamicEnum`] from an existing one.
///
/// This is functionally the same as [`DynamicEnum::from`] except it takes a reference.
pub fn from_ref<TEnum: Enum + ?Sized>(value: &TEnum) -> Self {
let type_info = value.get_represented_type_info();
let mut dyn_enum = match value.variant_type() {
VariantType::Unit => DynamicEnum::new_with_index(
value.variant_index(),
value.variant_name(),
DynamicVariant::Unit,
),
VariantType::Tuple => {
let mut data = DynamicTuple::default();
for field in value.iter_fields() {
data.insert_boxed(field.value().to_dynamic());
}
DynamicEnum::new_with_index(
value.variant_index(),
value.variant_name(),
DynamicVariant::Tuple(data),
)
}
VariantType::Struct => {
let mut data = DynamicStruct::default();
for field in value.iter_fields() {
let name = field.name().unwrap();
data.insert_boxed(name, field.value().to_dynamic());
}
DynamicEnum::new_with_index(
value.variant_index(),
value.variant_name(),
DynamicVariant::Struct(data),
)
}
};
dyn_enum.set_represented_type(type_info);
dyn_enum
}
}
impl Enum for DynamicEnum {
fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
if let DynamicVariant::Struct(data) = &self.variant {
data.field(name)
} else {
None
}
}
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
if let DynamicVariant::Tuple(data) = &self.variant {
data.field(index)
} else {
None
}
}
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
if let DynamicVariant::Struct(data) = &mut self.variant {
data.field_mut(name)
} else {
None
}
}
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
if let DynamicVariant::Tuple(data) = &mut self.variant {
data.field_mut(index)
} else {
None
}
}
fn index_of(&self, name: &str) -> Option<usize> {
if let DynamicVariant::Struct(data) = &self.variant {
data.index_of(name)
} else {
None
}
}
fn name_at(&self, index: usize) -> Option<&str> {
if let DynamicVariant::Struct(data) = &self.variant {
data.name_at(index)
} else {
None
}
}
fn iter_fields(&self) -> VariantFieldIter {
VariantFieldIter::new(self)
}
fn field_len(&self) -> usize {
match &self.variant {
DynamicVariant::Unit => 0,
DynamicVariant::Tuple(data) => data.field_len(),
DynamicVariant::Struct(data) => data.field_len(),
}
}
fn variant_name(&self) -> &str {
&self.variant_name
}
fn variant_index(&self) -> usize {
self.variant_index
}
fn variant_type(&self) -> VariantType {
match &self.variant {
DynamicVariant::Unit => VariantType::Unit,
DynamicVariant::Tuple(..) => VariantType::Tuple,
DynamicVariant::Struct(..) => VariantType::Struct,
}
}
fn clone_dynamic(&self) -> DynamicEnum {
Self {
represented_type: self.represented_type,
variant_index: self.variant_index,
variant_name: self.variant_name.clone(),
variant: self.variant.clone(),
}
}
}
impl PartialReflect for DynamicEnum {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
#[inline]
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
let value = value.reflect_ref().as_enum()?;
if Enum::variant_name(self) == value.variant_name() {
// Same variant -> just update fields
match value.variant_type() {
VariantType::Struct => {
for field in value.iter_fields() {
let name = field.name().unwrap();
if let Some(v) = Enum::field_mut(self, name) {
v.try_apply(field.value())?;
}
}
}
VariantType::Tuple => {
for (index, field) in value.iter_fields().enumerate() {
if let Some(v) = Enum::field_at_mut(self, index) {
v.try_apply(field.value())?;
}
}
}
_ => {}
}
} else {
// New variant -> perform a switch
let dyn_variant = match value.variant_type() {
VariantType::Unit => DynamicVariant::Unit,
VariantType::Tuple => {
let mut dyn_tuple = DynamicTuple::default();
for field in value.iter_fields() {
dyn_tuple.insert_boxed(field.value().to_dynamic());
}
DynamicVariant::Tuple(dyn_tuple)
}
VariantType::Struct => {
let mut dyn_struct = DynamicStruct::default();
for field in value.iter_fields() {
dyn_struct.insert_boxed(field.name().unwrap(), field.value().to_dynamic());
}
DynamicVariant::Struct(dyn_struct)
}
};
self.set_variant(value.variant_name(), dyn_variant);
}
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Enum
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Enum(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Enum(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Enum(self)
}
#[inline]
fn reflect_hash(&self) -> Option<u64> {
enum_hash(self)
}
#[inline]
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
enum_partial_eq(self, value)
}
#[inline]
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicEnum(")?;
enum_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicEnum);

View File

@@ -0,0 +1,376 @@
use crate::generics::impl_generic_info_methods;
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
DynamicEnum, Generics, PartialReflect, Type, TypePath, VariantInfo, VariantType,
};
use alloc::{boxed::Box, format, string::String};
use bevy_platform::collections::HashMap;
use bevy_platform::sync::Arc;
use core::slice::Iter;
/// A trait used to power [enum-like] operations via [reflection].
///
/// This allows enums to be processed and modified dynamically at runtime without
/// necessarily knowing the actual type.
/// Enums are much more complex than their struct counterparts.
/// As a result, users will need to be mindful of conventions, considerations,
/// and complications when working with this trait.
///
/// # Variants
///
/// An enum is a set of choices called _variants_.
/// An instance of an enum can only exist as one of these choices at any given time.
/// Consider Rust's [`Option<T>`]. It's an enum with two variants: [`None`] and [`Some`].
/// If you're `None`, you can't be `Some` and vice versa.
///
/// > ⚠️ __This is very important:__
/// > The [`Enum`] trait represents an enum _as one of its variants_.
/// > It does not represent the entire enum since that's not true to how enums work.
///
/// Variants come in a few [flavors](VariantType):
///
/// | Variant Type | Syntax |
/// | ------------ | ------------------------------ |
/// | Unit | `MyEnum::Foo` |
/// | Tuple | `MyEnum::Foo( i32, i32 )` |
/// | Struct | `MyEnum::Foo{ value: String }` |
///
/// As you can see, a unit variant contains no fields, while tuple and struct variants
/// can contain one or more fields.
/// The fields in a tuple variant is defined by their _order_ within the variant.
/// Index `0` represents the first field in the variant and so on.
/// Fields in struct variants (excluding tuple structs), on the other hand, are
/// represented by a _name_.
///
/// # Implementation
///
/// > 💡 This trait can be automatically implemented using [`#[derive(Reflect)]`](derive@crate::Reflect)
/// > on an enum definition.
///
/// Despite the fact that enums can represent multiple states, traits only exist in one state
/// and must be applied to the entire enum rather than a particular variant.
/// Because of this limitation, the [`Enum`] trait must not only _represent_ any of the
/// three variant types, but also define the _methods_ for all three as well.
///
/// What does this mean? It means that even though a unit variant contains no fields, a
/// representation of that variant using the [`Enum`] trait will still contain methods for
/// accessing fields!
/// Again, this is to account for _all three_ variant types.
///
/// We recommend using the built-in [`#[derive(Reflect)]`](derive@crate::Reflect) macro to automatically handle all the
/// implementation details for you.
/// However, if you _must_ implement this trait manually, there are a few things to keep in mind...
///
/// ## Field Order
///
/// While tuple variants identify their fields by the order in which they are defined, struct
/// variants identify fields by their name.
/// However, both should allow access to fields by their defined order.
///
/// The reason all fields, regardless of variant type, need to be accessible by their order is
/// due to field iteration.
/// We need a way to iterate through each field in a variant, and the easiest way of achieving
/// that is through the use of field order.
///
/// The derive macro adds proper struct variant handling for [`Enum::index_of`], [`Enum::name_at`]
/// and [`Enum::field_at[_mut]`](Enum::field_at) methods.
/// The first two methods are __required__ for all struct variant types.
/// By convention, implementors should also handle the last method as well, but this is not
/// a strict requirement.
///
/// ## Field Names
///
/// Implementors may choose to handle [`Enum::index_of`], [`Enum::name_at`], and
/// [`Enum::field[_mut]`](Enum::field) for tuple variants by considering stringified `usize`s to be
/// valid names (such as `"3"`).
/// This isn't wrong to do, but the convention set by the derive macro is that it isn't supported.
/// It's preferred that these strings be converted to their proper `usize` representations and
/// the [`Enum::field_at[_mut]`](Enum::field_at) methods be used instead.
///
/// [enum-like]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
/// [reflection]: crate
/// [`None`]: Option<T>::None
/// [`Some`]: Option<T>::Some
/// [`Reflect`]: bevy_reflect_derive::Reflect
pub trait Enum: PartialReflect {
/// Returns a reference to the value of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
/// Returns a reference to the value of the field (in the current variant) at the given index.
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
/// Returns a mutable reference to the value of the field (in the current variant) at the given index.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the index of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn index_of(&self, name: &str) -> Option<usize>;
/// Returns the name of the field (in the current variant) with the given index.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn name_at(&self, index: usize) -> Option<&str>;
/// Returns an iterator over the values of the current variant's fields.
fn iter_fields(&self) -> VariantFieldIter;
/// Returns the number of fields in the current variant.
fn field_len(&self) -> usize;
/// The name of the current variant.
fn variant_name(&self) -> &str;
/// The index of the current variant.
fn variant_index(&self) -> usize;
/// The type of the current variant.
fn variant_type(&self) -> VariantType;
// Clones the enum into a [`DynamicEnum`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_enum` instead")]
fn clone_dynamic(&self) -> DynamicEnum {
self.to_dynamic_enum()
}
/// Creates a new [`DynamicEnum`] from this enum.
fn to_dynamic_enum(&self) -> DynamicEnum {
DynamicEnum::from_ref(self)
}
/// Returns true if the current variant's type matches the given one.
fn is_variant(&self, variant_type: VariantType) -> bool {
self.variant_type() == variant_type
}
/// Returns the full path to the current variant.
fn variant_path(&self) -> String {
format!("{}::{}", self.reflect_type_path(), self.variant_name())
}
/// Will return `None` if [`TypeInfo`] is not available.
///
/// [`TypeInfo`]: crate::TypeInfo
fn get_represented_enum_info(&self) -> Option<&'static EnumInfo> {
self.get_represented_type_info()?.as_enum().ok()
}
}
/// A container for compile-time enum info, used by [`TypeInfo`](crate::TypeInfo).
#[derive(Clone, Debug)]
pub struct EnumInfo {
ty: Type,
generics: Generics,
variants: Box<[VariantInfo]>,
variant_names: Box<[&'static str]>,
variant_indices: HashMap<&'static str, usize>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl EnumInfo {
/// Create a new [`EnumInfo`].
///
/// # Arguments
///
/// * `variants`: The variants of this enum in the order they are defined
pub fn new<TEnum: Enum + TypePath>(variants: &[VariantInfo]) -> Self {
let variant_indices = variants
.iter()
.enumerate()
.map(|(index, variant)| (variant.name(), index))
.collect::<HashMap<_, _>>();
let variant_names = variants.iter().map(VariantInfo::name).collect();
Self {
ty: Type::of::<TEnum>(),
generics: Generics::new(),
variants: variants.to_vec().into_boxed_slice(),
variant_names,
variant_indices,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this enum.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this enum.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// A slice containing the names of all variants in order.
pub fn variant_names(&self) -> &[&'static str] {
&self.variant_names
}
/// Get a variant with the given name.
pub fn variant(&self, name: &str) -> Option<&VariantInfo> {
self.variant_indices
.get(name)
.map(|index| &self.variants[*index])
}
/// Get a variant at the given index.
pub fn variant_at(&self, index: usize) -> Option<&VariantInfo> {
self.variants.get(index)
}
/// Get the index of the variant with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.variant_indices.get(name).copied()
}
/// Returns the full path to the given variant.
///
/// This does _not_ check if the given variant exists.
pub fn variant_path(&self, name: &str) -> String {
format!("{}::{name}", self.type_path())
}
/// Checks if a variant with the given name exists within this enum.
pub fn contains_variant(&self, name: &str) -> bool {
self.variant_indices.contains_key(name)
}
/// Iterate over the variants of this enum.
pub fn iter(&self) -> Iter<'_, VariantInfo> {
self.variants.iter()
}
/// The number of variants in this enum.
pub fn variant_len(&self) -> usize {
self.variants.len()
}
impl_type_methods!(ty);
/// The docstring of this enum, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "enum");
impl_generic_info_methods!(generics);
}
/// An iterator over the fields in the current enum variant.
pub struct VariantFieldIter<'a> {
container: &'a dyn Enum,
index: usize,
}
impl<'a> VariantFieldIter<'a> {
pub fn new(container: &'a dyn Enum) -> Self {
Self {
container,
index: 0,
}
}
}
impl<'a> Iterator for VariantFieldIter<'a> {
type Item = VariantField<'a>;
fn next(&mut self) -> Option<Self::Item> {
let value = match self.container.variant_type() {
VariantType::Unit => None,
VariantType::Tuple => Some(VariantField::Tuple(self.container.field_at(self.index)?)),
VariantType::Struct => {
let name = self.container.name_at(self.index)?;
Some(VariantField::Struct(name, self.container.field(name)?))
}
};
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.container.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for VariantFieldIter<'a> {}
pub enum VariantField<'a> {
Struct(&'a str, &'a dyn PartialReflect),
Tuple(&'a dyn PartialReflect),
}
impl<'a> VariantField<'a> {
pub fn name(&self) -> Option<&'a str> {
if let Self::Struct(name, ..) = self {
Some(*name)
} else {
None
}
}
pub fn value(&self) -> &'a dyn PartialReflect {
match *self {
Self::Struct(_, value) | Self::Tuple(value) => value,
}
}
}
// Tests that need access to internal fields have to go here rather than in mod.rs
#[cfg(test)]
mod tests {
use crate::*;
#[derive(Reflect, Debug, PartialEq)]
enum MyEnum {
A,
B(usize, i32),
C { foo: f32, bar: bool },
}
#[test]
fn next_index_increment() {
// unit enums always return none, so index should stay at 0
let unit_enum = MyEnum::A;
let mut iter = unit_enum.iter_fields();
let size = iter.len();
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
// tuple enums we iter over each value (unnamed fields), stop after that
let tuple_enum = MyEnum::B(0, 1);
let mut iter = tuple_enum.iter_fields();
let size = iter.len();
for _ in 0..2 {
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
}
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
// struct enums, we iterate over each field in the struct
let struct_enum = MyEnum::C {
foo: 0.,
bar: false,
};
let mut iter = struct_enum.iter_fields();
let size = iter.len();
for _ in 0..2 {
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
}
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}
}

121
vendor/bevy_reflect/src/enums/helpers.rs vendored Normal file
View File

@@ -0,0 +1,121 @@
use crate::{utility::reflect_hasher, Enum, PartialReflect, ReflectRef, VariantType};
use core::{
fmt::Debug,
hash::{Hash, Hasher},
};
/// Returns the `u64` hash of the given [enum](Enum).
#[inline]
pub fn enum_hash<TEnum: Enum>(value: &TEnum) -> Option<u64> {
let mut hasher = reflect_hasher();
core::any::Any::type_id(value).hash(&mut hasher);
value.variant_name().hash(&mut hasher);
value.variant_type().hash(&mut hasher);
for field in value.iter_fields() {
hasher.write_u64(field.value().reflect_hash()?);
}
Some(hasher.finish())
}
/// Compares an [`Enum`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is an enum;
/// - `b` is the same variant as `a`;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
#[inline]
pub fn enum_partial_eq<TEnum: Enum + ?Sized>(a: &TEnum, b: &dyn PartialReflect) -> Option<bool> {
// Both enums?
let ReflectRef::Enum(b) = b.reflect_ref() else {
return Some(false);
};
// Same variant name?
if a.variant_name() != b.variant_name() {
return Some(false);
}
// Same variant type?
if !a.is_variant(b.variant_type()) {
return Some(false);
}
match a.variant_type() {
VariantType::Struct => {
// Same struct fields?
for field in a.iter_fields() {
let field_name = field.name().unwrap();
if let Some(field_value) = b.field(field_name) {
if let Some(false) | None = field_value.reflect_partial_eq(field.value()) {
// Fields failed comparison
return Some(false);
}
} else {
// Field does not exist
return Some(false);
}
}
Some(true)
}
VariantType::Tuple => {
// Same tuple fields?
for (i, field) in a.iter_fields().enumerate() {
if let Some(field_value) = b.field_at(i) {
if let Some(false) | None = field_value.reflect_partial_eq(field.value()) {
// Fields failed comparison
return Some(false);
}
} else {
// Field does not exist
return Some(false);
}
}
Some(true)
}
_ => Some(true),
}
}
/// The default debug formatter for [`Enum`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
/// #[derive(Reflect)]
/// enum MyEnum {
/// A,
/// B (usize),
/// C {value: i32}
/// }
///
/// let my_enum: &dyn Reflect = &MyEnum::B(123);
/// println!("{:#?}", my_enum);
///
/// // Output:
///
/// // B (
/// // 123,
/// // )
/// ```
#[inline]
pub fn enum_debug(dyn_enum: &dyn Enum, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match dyn_enum.variant_type() {
VariantType::Unit => f.write_str(dyn_enum.variant_name()),
VariantType::Tuple => {
let mut debug = f.debug_tuple(dyn_enum.variant_name());
for field in dyn_enum.iter_fields() {
debug.field(&field.value() as &dyn Debug);
}
debug.finish()
}
VariantType::Struct => {
let mut debug = f.debug_struct(dyn_enum.variant_name());
for field in dyn_enum.iter_fields() {
debug.field(field.name().unwrap(), &field.value() as &dyn Debug);
}
debug.finish()
}
}
}

693
vendor/bevy_reflect/src/enums/mod.rs vendored Normal file
View File

@@ -0,0 +1,693 @@
mod dynamic_enum;
mod enum_trait;
mod helpers;
mod variants;
pub use dynamic_enum::*;
pub use enum_trait::*;
pub use helpers::*;
pub use variants::*;
#[cfg(test)]
mod tests {
use crate::*;
use alloc::boxed::Box;
#[derive(Reflect, Debug, PartialEq)]
enum MyEnum {
A,
B(usize, i32),
C { foo: f32, bar: bool },
}
#[test]
fn should_get_enum_type_info() {
let info = MyEnum::type_info();
if let TypeInfo::Enum(info) = info {
assert!(info.is::<MyEnum>(), "expected type to be `MyEnum`");
assert_eq!(MyEnum::type_path(), info.type_path());
assert_eq!(MyEnum::type_path(), info.type_path_table().path());
assert_eq!(MyEnum::type_ident(), info.type_path_table().ident());
assert_eq!(MyEnum::module_path(), info.type_path_table().module_path());
assert_eq!(MyEnum::crate_name(), info.type_path_table().crate_name());
assert_eq!(
MyEnum::short_type_path(),
info.type_path_table().short_path()
);
// === MyEnum::A === //
assert_eq!("A", info.variant_at(0).unwrap().name());
assert_eq!("A", info.variant("A").unwrap().name());
if let VariantInfo::Unit(variant) = info.variant("A").unwrap() {
assert_eq!("A", variant.name());
} else {
panic!("Expected `VariantInfo::Unit`");
}
// === MyEnum::B === //
assert_eq!("B", info.variant_at(1).unwrap().name());
assert_eq!("B", info.variant("B").unwrap().name());
if let VariantInfo::Tuple(variant) = info.variant("B").unwrap() {
assert!(variant.field_at(0).unwrap().is::<usize>());
assert!(variant.field_at(1).unwrap().is::<i32>());
assert!(variant
.field_at(0)
.unwrap()
.type_info()
.unwrap()
.is::<usize>());
assert!(variant
.field_at(1)
.unwrap()
.type_info()
.unwrap()
.is::<i32>());
} else {
panic!("Expected `VariantInfo::Tuple`");
}
// === MyEnum::C === //
assert_eq!("C", info.variant_at(2).unwrap().name());
assert_eq!("C", info.variant("C").unwrap().name());
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
assert!(variant.field_at(0).unwrap().is::<f32>());
assert!(variant.field("foo").unwrap().is::<f32>());
assert!(variant
.field("foo")
.unwrap()
.type_info()
.unwrap()
.is::<f32>());
} else {
panic!("Expected `VariantInfo::Struct`");
}
} else {
panic!("Expected `TypeInfo::Enum`");
}
}
#[test]
fn dynamic_enum_should_set_variant_fields() {
// === Unit === //
let mut value = MyEnum::A;
let dyn_enum = DynamicEnum::from(MyEnum::A);
value.apply(&dyn_enum);
assert_eq!(MyEnum::A, value);
// === Tuple === //
let mut value = MyEnum::B(0, 0);
let dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 321), value);
// === Struct === //
let mut value = MyEnum::C {
foo: 0.0,
bar: false,
};
let dyn_enum = DynamicEnum::from(MyEnum::C {
foo: 1.23,
bar: true,
});
value.apply(&dyn_enum);
assert_eq!(
MyEnum::C {
foo: 1.23,
bar: true,
},
value
);
}
#[test]
fn partial_dynamic_enum_should_set_variant_fields() {
// === Tuple === //
let mut value = MyEnum::B(0, 0);
let mut data = DynamicTuple::default();
data.insert(123usize);
let mut dyn_enum = DynamicEnum::default();
dyn_enum.set_variant("B", data);
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 0), value);
// === Struct === //
let mut value = MyEnum::C {
foo: 1.23,
bar: false,
};
let mut data = DynamicStruct::default();
data.insert("bar", true);
let mut dyn_enum = DynamicEnum::default();
dyn_enum.set_variant("C", data);
value.apply(&dyn_enum);
assert_eq!(
MyEnum::C {
foo: 1.23,
bar: true,
},
value
);
}
#[test]
fn dynamic_enum_should_apply_dynamic_enum() {
let mut a = DynamicEnum::from(MyEnum::B(123, 321));
let b = DynamicEnum::from(MyEnum::B(123, 321));
// Sanity check that equality check works
assert!(
a.reflect_partial_eq(&b).unwrap_or_default(),
"dynamic enums should be equal"
);
a.set_variant("A", ());
assert!(
!a.reflect_partial_eq(&b).unwrap_or_default(),
"dynamic enums should not be equal"
);
a.apply(&b);
assert!(a.reflect_partial_eq(&b).unwrap_or_default());
}
#[test]
fn dynamic_enum_should_change_variant() {
let mut value = MyEnum::A;
// === MyEnum::A -> MyEnum::B === //
let mut dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 321), value);
// === MyEnum::B -> MyEnum::C === //
let mut data = DynamicStruct::default();
data.insert("foo", 1.23_f32);
data.insert("bar", true);
dyn_enum.set_variant("C", data);
value.apply(&dyn_enum);
assert_eq!(
MyEnum::C {
foo: 1.23,
bar: true
},
value
);
// === MyEnum::C -> MyEnum::B === //
let mut data = DynamicTuple::default();
data.insert(123_usize);
data.insert(321_i32);
dyn_enum.set_variant("B", data);
value.apply(&dyn_enum);
assert_eq!(MyEnum::B(123, 321), value);
// === MyEnum::B -> MyEnum::A === //
dyn_enum.set_variant("A", ());
value.apply(&dyn_enum);
assert_eq!(MyEnum::A, value);
}
#[test]
fn dynamic_enum_should_return_is_dynamic() {
let dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
assert!(dyn_enum.is_dynamic());
}
#[test]
fn enum_should_iterate_fields() {
// === Unit === //
let value: &dyn Enum = &MyEnum::A;
assert_eq!(0, value.field_len());
let mut iter = value.iter_fields();
assert!(iter.next().is_none());
// === Tuple === //
let value: &dyn Enum = &MyEnum::B(123, 321);
assert_eq!(2, value.field_len());
let mut iter = value.iter_fields();
assert!(iter
.next()
.and_then(|field| field.value().reflect_partial_eq(&123_usize))
.unwrap_or_default());
assert!(iter
.next()
.and_then(|field| field.value().reflect_partial_eq(&321_i32))
.unwrap_or_default());
// === Struct === //
let value: &dyn Enum = &MyEnum::C {
foo: 1.23,
bar: true,
};
assert_eq!(2, value.field_len());
let mut iter = value.iter_fields();
assert!(iter
.next()
.and_then(|field| field
.value()
.reflect_partial_eq(&1.23_f32)
.and(field.name().map(|name| name == "foo")))
.unwrap_or_default());
assert!(iter
.next()
.and_then(|field| field
.value()
.reflect_partial_eq(&true)
.and(field.name().map(|name| name == "bar")))
.unwrap_or_default());
}
#[test]
fn enum_should_return_correct_variant_type() {
// === Unit === //
let value = MyEnum::A;
assert_eq!(VariantType::Unit, value.variant_type());
// === Tuple === //
let value = MyEnum::B(0, 0);
assert_eq!(VariantType::Tuple, value.variant_type());
// === Struct === //
let value = MyEnum::C {
foo: 1.23,
bar: true,
};
assert_eq!(VariantType::Struct, value.variant_type());
}
#[test]
fn enum_should_return_correct_variant_path() {
// === Unit === //
let value = MyEnum::A;
assert_eq!(
"bevy_reflect::enums::tests::MyEnum::A",
value.variant_path()
);
// === Tuple === //
let value = MyEnum::B(0, 0);
assert_eq!(
"bevy_reflect::enums::tests::MyEnum::B",
value.variant_path()
);
// === Struct === //
let value = MyEnum::C {
foo: 1.23,
bar: true,
};
assert_eq!(
"bevy_reflect::enums::tests::MyEnum::C",
value.variant_path()
);
}
#[test]
#[should_panic(
expected = "called `Result::unwrap()` on an `Err` value: MismatchedKinds { from_kind: Tuple, to_kind: Enum }"
)]
fn applying_non_enum_should_panic() {
let mut value = MyEnum::B(0, 0);
let mut dyn_tuple = DynamicTuple::default();
dyn_tuple.insert((123_usize, 321_i32));
value.apply(&dyn_tuple);
}
#[test]
fn enum_try_apply_should_detect_type_mismatch() {
#[derive(Reflect, Debug, PartialEq)]
enum MyEnumAnalogue {
A(u32),
B(usize, usize),
C { foo: f32, bar: u8 },
}
let mut target = MyEnumAnalogue::A(0);
// === Tuple === //
let result = target.try_apply(&MyEnum::B(0, 1));
assert!(
matches!(result, Err(ApplyError::MismatchedTypes { .. })),
"`result` was {result:?}"
);
// === Struct === //
target = MyEnumAnalogue::C { foo: 0.0, bar: 1 };
let result = target.try_apply(&MyEnum::C {
foo: 1.0,
bar: true,
});
assert!(
matches!(result, Err(ApplyError::MismatchedTypes { .. })),
"`result` was {result:?}"
);
// Type mismatch should occur after partial application.
assert_eq!(target, MyEnumAnalogue::C { foo: 1.0, bar: 1 });
}
#[test]
fn should_skip_ignored_fields() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum {
A,
B,
C {
#[reflect(ignore)]
foo: f32,
bar: bool,
},
}
if let TypeInfo::Enum(info) = TestEnum::type_info() {
assert_eq!(3, info.variant_len());
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
assert_eq!(
1,
variant.field_len(),
"expected one of the fields to be ignored"
);
assert!(variant.field_at(0).unwrap().is::<bool>());
} else {
panic!("expected `VariantInfo::Struct`");
}
} else {
panic!("expected `TypeInfo::Enum`");
}
}
#[test]
fn enum_should_allow_generics() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum<T: FromReflect> {
A,
B(T),
C { value: T },
}
if let TypeInfo::Enum(info) = TestEnum::<f32>::type_info() {
if let VariantInfo::Tuple(variant) = info.variant("B").unwrap() {
assert!(variant.field_at(0).unwrap().is::<f32>());
} else {
panic!("expected `VariantInfo::Struct`");
}
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
assert!(variant.field("value").unwrap().is::<f32>());
} else {
panic!("expected `VariantInfo::Struct`");
}
} else {
panic!("expected `TypeInfo::Enum`");
}
let mut value = TestEnum::<f32>::A;
// === Tuple === //
let mut data = DynamicTuple::default();
data.insert(1.23_f32);
let dyn_enum = DynamicEnum::new("B", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(1.23), value);
// === Struct === //
let mut data = DynamicStruct::default();
data.insert("value", 1.23_f32);
let dyn_enum = DynamicEnum::new("C", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::C { value: 1.23 }, value);
}
#[test]
fn enum_should_allow_struct_fields() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum {
A,
B(TestStruct),
C { value: TestStruct },
}
#[derive(Reflect, Debug, PartialEq)]
struct TestStruct(usize);
let mut value = TestEnum::A;
// === Tuple === //
let mut data = DynamicTuple::default();
data.insert(TestStruct(123));
let dyn_enum = DynamicEnum::new("B", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(TestStruct(123)), value);
// === Struct === //
let mut data = DynamicStruct::default();
data.insert("value", TestStruct(123));
let dyn_enum = DynamicEnum::new("C", data);
value.apply(&dyn_enum);
assert_eq!(
TestEnum::C {
value: TestStruct(123)
},
value
);
}
#[test]
fn enum_should_allow_nesting_enums() {
#[derive(Reflect, Debug, PartialEq)]
enum TestEnum {
A,
B(OtherEnum),
C { value: OtherEnum },
}
#[derive(Reflect, Debug, PartialEq)]
enum OtherEnum {
A,
B(usize),
C { value: f32 },
}
let mut value = TestEnum::A;
// === Tuple === //
let mut data = DynamicTuple::default();
data.insert(OtherEnum::B(123));
let dyn_enum = DynamicEnum::new("B", data);
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(OtherEnum::B(123)), value);
// === Struct === //
let mut data = DynamicStruct::default();
data.insert("value", OtherEnum::C { value: 1.23 });
let dyn_enum = DynamicEnum::new("C", data);
value.apply(&dyn_enum);
assert_eq!(
TestEnum::C {
value: OtherEnum::C { value: 1.23 }
},
value
);
}
#[test]
fn enum_should_apply() {
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
// === MyEnum::A -> MyEnum::A === //
value.apply(&MyEnum::A);
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
// === MyEnum::A -> MyEnum::B === //
value.apply(&MyEnum::B(123, 321));
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::B === //
value.apply(&MyEnum::B(321, 123));
assert!(value
.reflect_partial_eq(&MyEnum::B(321, 123))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::C === //
value.apply(&MyEnum::C {
foo: 1.23,
bar: true,
});
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 1.23,
bar: true
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::C === //
value.apply(&MyEnum::C {
foo: 3.21,
bar: false,
});
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 3.21,
bar: false
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::B === //
value.apply(&MyEnum::B(123, 321));
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::A === //
value.apply(&MyEnum::A);
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
}
#[test]
fn enum_should_set() {
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
// === MyEnum::A -> MyEnum::A === //
value.set(Box::new(MyEnum::A)).unwrap();
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
// === MyEnum::A -> MyEnum::B === //
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::B === //
value.set(Box::new(MyEnum::B(321, 123))).unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::B(321, 123))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::C === //
value
.set(Box::new(MyEnum::C {
foo: 1.23,
bar: true,
}))
.unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 1.23,
bar: true
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::C === //
value
.set(Box::new(MyEnum::C {
foo: 3.21,
bar: false,
}))
.unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::C {
foo: 3.21,
bar: false
})
.unwrap_or_default());
// === MyEnum::C -> MyEnum::B === //
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
assert!(value
.reflect_partial_eq(&MyEnum::B(123, 321))
.unwrap_or_default());
// === MyEnum::B -> MyEnum::A === //
value.set(Box::new(MyEnum::A)).unwrap();
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
}
#[test]
fn enum_should_partial_eq() {
#[derive(Reflect)]
enum TestEnum {
A,
A1,
B(usize),
B1(usize),
B2(usize, usize),
C { value: i32 },
C1 { value: i32 },
C2 { value: f32 },
}
let a: &dyn PartialReflect = &TestEnum::A;
let b: &dyn PartialReflect = &TestEnum::A;
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::A == TestEnum::A"
);
let a: &dyn PartialReflect = &TestEnum::A;
let b: &dyn PartialReflect = &TestEnum::A1;
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::A != TestEnum::A1"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B(123);
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) == TestEnum::B(123)"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B(321);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B(321)"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B1(123);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B1(123)"
);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B2(123, 123);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B2(123, 123)"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C { value: 123 };
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} == TestEnum::C{{value: 123}}"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C { value: 321 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C{{value: 321}}"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C1 { value: 123 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C1{{value: 123}}"
);
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C2 { value: 1.23 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C2{{value: 1.23}}"
);
}
}

View File

@@ -0,0 +1,381 @@
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
NamedField, UnnamedField,
};
use alloc::boxed::Box;
use bevy_platform::collections::HashMap;
use bevy_platform::sync::Arc;
use core::slice::Iter;
use thiserror::Error;
/// Describes the form of an enum variant.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum VariantType {
/// Struct enums take the form:
///
/// ```
/// enum MyEnum {
/// A {
/// foo: usize
/// }
/// }
/// ```
Struct,
/// Tuple enums take the form:
///
/// ```
/// enum MyEnum {
/// A(usize)
/// }
/// ```
Tuple,
/// Unit enums take the form:
///
/// ```
/// enum MyEnum {
/// A
/// }
/// ```
Unit,
}
/// A [`VariantInfo`]-specific error.
#[derive(Debug, Error)]
pub enum VariantInfoError {
/// Caused when a variant was expected to be of a certain [type], but was not.
///
/// [type]: VariantType
#[error("variant type mismatch: expected {expected:?}, received {received:?}")]
TypeMismatch {
expected: VariantType,
received: VariantType,
},
}
/// A container for compile-time enum variant info.
#[derive(Clone, Debug)]
pub enum VariantInfo {
/// Struct enums take the form:
///
/// ```
/// enum MyEnum {
/// A {
/// foo: usize
/// }
/// }
/// ```
Struct(StructVariantInfo),
/// Tuple enums take the form:
///
/// ```
/// enum MyEnum {
/// A(usize)
/// }
/// ```
Tuple(TupleVariantInfo),
/// Unit enums take the form:
///
/// ```
/// enum MyEnum {
/// A
/// }
/// ```
Unit(UnitVariantInfo),
}
impl VariantInfo {
pub fn name(&self) -> &'static str {
match self {
Self::Struct(info) => info.name(),
Self::Tuple(info) => info.name(),
Self::Unit(info) => info.name(),
}
}
/// The docstring of the underlying variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&str> {
match self {
Self::Struct(info) => info.docs(),
Self::Tuple(info) => info.docs(),
Self::Unit(info) => info.docs(),
}
}
/// Returns the [type] of this variant.
///
/// [type]: VariantType
pub fn variant_type(&self) -> VariantType {
match self {
Self::Struct(_) => VariantType::Struct,
Self::Tuple(_) => VariantType::Tuple,
Self::Unit(_) => VariantType::Unit,
}
}
impl_custom_attribute_methods!(
self,
match self {
Self::Struct(info) => info.custom_attributes(),
Self::Tuple(info) => info.custom_attributes(),
Self::Unit(info) => info.custom_attributes(),
},
"variant"
);
}
macro_rules! impl_cast_method {
($name:ident : $kind:ident => $info:ident) => {
#[doc = concat!("Attempts a cast to [`", stringify!($info), "`].")]
#[doc = concat!("\n\nReturns an error if `self` is not [`VariantInfo::", stringify!($kind), "`].")]
pub fn $name(&self) -> Result<&$info, VariantInfoError> {
match self {
Self::$kind(info) => Ok(info),
_ => Err(VariantInfoError::TypeMismatch {
expected: VariantType::$kind,
received: self.variant_type(),
}),
}
}
};
}
/// Conversion convenience methods for [`VariantInfo`].
impl VariantInfo {
impl_cast_method!(as_struct_variant: Struct => StructVariantInfo);
impl_cast_method!(as_tuple_variant: Tuple => TupleVariantInfo);
impl_cast_method!(as_unit_variant: Unit => UnitVariantInfo);
}
/// Type info for struct variants.
#[derive(Clone, Debug)]
pub struct StructVariantInfo {
name: &'static str,
fields: Box<[NamedField]>,
field_names: Box<[&'static str]>,
field_indices: HashMap<&'static str, usize>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl StructVariantInfo {
/// Create a new [`StructVariantInfo`].
pub fn new(name: &'static str, fields: &[NamedField]) -> Self {
let field_indices = Self::collect_field_indices(fields);
let field_names = fields.iter().map(NamedField::name).collect();
Self {
name,
fields: fields.to_vec().into_boxed_slice(),
field_names,
field_indices,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this variant.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this variant.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of this variant.
pub fn name(&self) -> &'static str {
self.name
}
/// A slice containing the names of all fields in order.
pub fn field_names(&self) -> &[&'static str] {
&self.field_names
}
/// Get the field with the given name.
pub fn field(&self, name: &str) -> Option<&NamedField> {
self.field_indices
.get(name)
.map(|index| &self.fields[*index])
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&NamedField> {
self.fields.get(index)
}
/// Get the index of the field with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
/// Iterate over the fields of this variant.
pub fn iter(&self) -> Iter<'_, NamedField> {
self.fields.iter()
}
/// The total number of fields in this variant.
pub fn field_len(&self) -> usize {
self.fields.len()
}
fn collect_field_indices(fields: &[NamedField]) -> HashMap<&'static str, usize> {
fields
.iter()
.enumerate()
.map(|(index, field)| (field.name(), index))
.collect()
}
/// The docstring of this variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "variant");
}
/// Type info for tuple variants.
#[derive(Clone, Debug)]
pub struct TupleVariantInfo {
name: &'static str,
fields: Box<[UnnamedField]>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl TupleVariantInfo {
/// Create a new [`TupleVariantInfo`].
pub fn new(name: &'static str, fields: &[UnnamedField]) -> Self {
Self {
name,
fields: fields.to_vec().into_boxed_slice(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this variant.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this variant.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of this variant.
pub fn name(&self) -> &'static str {
self.name
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {
self.fields.get(index)
}
/// Iterate over the fields of this variant.
pub fn iter(&self) -> Iter<'_, UnnamedField> {
self.fields.iter()
}
/// The total number of fields in this variant.
pub fn field_len(&self) -> usize {
self.fields.len()
}
/// The docstring of this variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "variant");
}
/// Type info for unit variants.
#[derive(Clone, Debug)]
pub struct UnitVariantInfo {
name: &'static str,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl UnitVariantInfo {
/// Create a new [`UnitVariantInfo`].
pub fn new(name: &'static str) -> Self {
Self {
name,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this variant.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this variant.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of this variant.
pub fn name(&self) -> &'static str {
self.name
}
/// The docstring of this variant, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "variant");
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Reflect, Typed};
#[test]
fn should_return_error_on_invalid_cast() {
#[derive(Reflect)]
enum Foo {
Bar,
}
let info = Foo::type_info().as_enum().unwrap();
let variant = info.variant_at(0).unwrap();
assert!(matches!(
variant.as_tuple_variant(),
Err(VariantInfoError::TypeMismatch {
expected: VariantType::Tuple,
received: VariantType::Unit
})
));
}
}

61
vendor/bevy_reflect/src/error.rs vendored Normal file
View File

@@ -0,0 +1,61 @@
use crate::FieldId;
use alloc::{borrow::Cow, format};
use thiserror::Error;
/// An error that occurs when cloning a type via [`PartialReflect::reflect_clone`].
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum ReflectCloneError {
/// The type does not have a custom implementation for [`PartialReflect::reflect_clone`].
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
#[error("`PartialReflect::reflect_clone` not implemented for `{type_path}`")]
NotImplemented { type_path: Cow<'static, str> },
/// The type cannot be cloned via [`PartialReflect::reflect_clone`].
///
/// This type should be returned when a type is intentionally opting out of reflection cloning.
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
#[error("`{type_path}` cannot be made cloneable for `PartialReflect::reflect_clone`")]
NotCloneable { type_path: Cow<'static, str> },
/// The field cannot be cloned via [`PartialReflect::reflect_clone`].
///
/// When [deriving `Reflect`], this usually means that a field marked with `#[reflect(ignore)]`
/// is missing a `#[reflect(clone)]` attribute.
///
/// This may be intentional if the field is not meant/able to be cloned.
///
/// [`PartialReflect::reflect_clone`]: crate::PartialReflect::reflect_clone
/// [deriving `Reflect`]: derive@crate::Reflect
#[error(
"field `{}` cannot be made cloneable for `PartialReflect::reflect_clone` (are you missing a `#[reflect(clone)]` attribute?)",
full_path(.field, .variant.as_deref(), .container_type_path)
)]
FieldNotCloneable {
field: FieldId,
variant: Option<Cow<'static, str>>,
container_type_path: Cow<'static, str>,
},
/// Could not downcast to the expected type.
///
/// Realistically this should only occur when a type has incorrectly implemented [`Reflect`].
///
/// [`Reflect`]: crate::Reflect
#[error("expected downcast to `{expected}`, but received `{received}`")]
FailedDowncast {
expected: Cow<'static, str>,
received: Cow<'static, str>,
},
}
fn full_path(
field: &FieldId,
variant: Option<&str>,
container_type_path: &str,
) -> alloc::string::String {
match variant {
Some(variant) => format!("{}::{}::{}", container_type_path, variant, field),
None => format!("{}::{}", container_type_path, field),
}
}

149
vendor/bevy_reflect/src/fields.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
MaybeTyped, PartialReflect, Type, TypeInfo, TypePath,
};
use alloc::borrow::Cow;
use bevy_platform::sync::Arc;
use core::fmt::{Display, Formatter};
/// The named field of a reflected struct.
#[derive(Clone, Debug)]
pub struct NamedField {
name: &'static str,
type_info: fn() -> Option<&'static TypeInfo>,
ty: Type,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl NamedField {
/// Create a new [`NamedField`].
pub fn new<T: PartialReflect + MaybeTyped + TypePath>(name: &'static str) -> Self {
Self {
name,
type_info: T::maybe_type_info,
ty: Type::of::<T>(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this field.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this field.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// The name of the field.
pub fn name(&self) -> &'static str {
self.name
}
/// The [`TypeInfo`] of the field.
///
///
/// Returns `None` if the field does not contain static type information,
/// such as for dynamic types.
pub fn type_info(&self) -> Option<&'static TypeInfo> {
(self.type_info)()
}
impl_type_methods!(ty);
/// The docstring of this field, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "field");
}
/// The unnamed field of a reflected tuple or tuple struct.
#[derive(Clone, Debug)]
pub struct UnnamedField {
index: usize,
type_info: fn() -> Option<&'static TypeInfo>,
ty: Type,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl UnnamedField {
pub fn new<T: PartialReflect + MaybeTyped + TypePath>(index: usize) -> Self {
Self {
index,
type_info: T::maybe_type_info,
ty: Type::of::<T>(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this field.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this field.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// Returns the index of the field.
pub fn index(&self) -> usize {
self.index
}
/// The [`TypeInfo`] of the field.
///
///
/// Returns `None` if the field does not contain static type information,
/// such as for dynamic types.
pub fn type_info(&self) -> Option<&'static TypeInfo> {
(self.type_info)()
}
impl_type_methods!(ty);
/// The docstring of this field, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "field");
}
/// A representation of a field's accessor.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FieldId {
Named(Cow<'static, str>),
Unnamed(usize),
}
impl Display for FieldId {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::Named(name) => Display::fmt(name, f),
Self::Unnamed(index) => Display::fmt(index, f),
}
}
}

128
vendor/bevy_reflect/src/from_reflect.rs vendored Normal file
View File

@@ -0,0 +1,128 @@
use crate::{FromType, PartialReflect, Reflect};
use alloc::boxed::Box;
/// A trait that enables types to be dynamically constructed from reflected data.
///
/// It's recommended to use the [derive macro] rather than manually implementing this trait.
///
/// `FromReflect` allows dynamic proxy types, like [`DynamicStruct`], to be used to generate
/// their concrete counterparts.
/// It can also be used to partially or fully clone a type (depending on whether it has
/// ignored fields or not).
///
/// In some cases, this trait may even be required.
/// Deriving [`Reflect`] on an enum requires all its fields to implement `FromReflect`.
/// Additionally, some complex types like `Vec<T>` require that their element types
/// implement this trait.
/// The reason for such requirements is that some operations require new data to be constructed,
/// such as swapping to a new variant or pushing data to a homogeneous list.
///
/// See the [crate-level documentation] to see how this trait can be used.
///
/// [derive macro]: bevy_reflect_derive::FromReflect
/// [`DynamicStruct`]: crate::DynamicStruct
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `FromReflect` so cannot be created through reflection",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait FromReflect: Reflect + Sized {
/// Constructs a concrete instance of `Self` from a reflected value.
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self>;
/// Attempts to downcast the given value to `Self` using,
/// constructing the value using [`from_reflect`] if that fails.
///
/// This method is more efficient than using [`from_reflect`] for cases where
/// the given value is likely a boxed instance of `Self` (i.e. `Box<Self>`)
/// rather than a boxed dynamic type (e.g. [`DynamicStruct`], [`DynamicList`], etc.).
///
/// [`from_reflect`]: Self::from_reflect
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
fn take_from_reflect(
reflect: Box<dyn PartialReflect>,
) -> Result<Self, Box<dyn PartialReflect>> {
match reflect.try_take::<Self>() {
Ok(value) => Ok(value),
Err(value) => match Self::from_reflect(value.as_ref()) {
None => Err(value),
Some(value) => Ok(value),
},
}
}
}
/// Type data that represents the [`FromReflect`] trait and allows it to be used dynamically.
///
/// `FromReflect` allows dynamic types (e.g. [`DynamicStruct`], [`DynamicEnum`], etc.) to be converted
/// to their full, concrete types. This is most important when it comes to deserialization where it isn't
/// guaranteed that every field exists when trying to construct the final output.
///
/// However, to do this, you normally need to specify the exact concrete type:
///
/// ```
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect};
/// #[derive(Reflect, PartialEq, Eq, Debug)]
/// struct Foo(#[reflect(default = "default_value")] usize);
///
/// fn default_value() -> usize { 123 }
///
/// let reflected = DynamicTupleStruct::default();
///
/// let concrete: Foo = <Foo as FromReflect>::from_reflect(&reflected).unwrap();
///
/// assert_eq!(Foo(123), concrete);
/// ```
///
/// In a dynamic context where the type might not be known at compile-time, this is nearly impossible to do.
/// That is why this type data struct exists— it allows us to construct the full type without knowing
/// what the actual type is.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{DynamicTupleStruct, Reflect, ReflectFromReflect, Typed, TypeRegistry, TypePath};
/// # #[derive(Reflect, PartialEq, Eq, Debug)]
/// # struct Foo(#[reflect(default = "default_value")] usize);
/// # fn default_value() -> usize { 123 }
/// # let mut registry = TypeRegistry::new();
/// # registry.register::<Foo>();
///
/// let mut reflected = DynamicTupleStruct::default();
/// reflected.set_represented_type(Some(<Foo as Typed>::type_info()));
///
/// let registration = registry.get_with_type_path(<Foo as TypePath>::type_path()).unwrap();
/// let rfr = registration.data::<ReflectFromReflect>().unwrap();
///
/// let concrete: Box<dyn Reflect> = rfr.from_reflect(&reflected).unwrap();
///
/// assert_eq!(Foo(123), concrete.take::<Foo>().unwrap());
/// ```
///
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicEnum`]: crate::DynamicEnum
#[derive(Clone)]
pub struct ReflectFromReflect {
from_reflect: fn(&dyn PartialReflect) -> Option<Box<dyn Reflect>>,
}
impl ReflectFromReflect {
/// Perform a [`FromReflect::from_reflect`] conversion on the given reflection object.
///
/// This will convert the object to a concrete type if it wasn't already, and return
/// the value as `Box<dyn Reflect>`.
pub fn from_reflect(&self, reflect_value: &dyn PartialReflect) -> Option<Box<dyn Reflect>> {
(self.from_reflect)(reflect_value)
}
}
impl<T: FromReflect> FromType<T> for ReflectFromReflect {
fn from_type() -> Self {
Self {
from_reflect: |reflect_value| {
T::from_reflect(reflect_value).map(|value| Box::new(value) as Box<dyn Reflect>)
},
}
}
}

214
vendor/bevy_reflect/src/func/args/arg.rs vendored Normal file
View File

@@ -0,0 +1,214 @@
use crate::{
func::args::{ArgError, FromArg, Ownership},
PartialReflect, Reflect, TypePath,
};
use alloc::{boxed::Box, string::ToString};
use core::ops::Deref;
/// Represents an argument that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug)]
pub struct Arg<'a> {
index: usize,
value: ArgValue<'a>,
}
impl<'a> Arg<'a> {
/// Create a new [`Arg`] with the given index and value.
pub fn new(index: usize, value: ArgValue<'a>) -> Self {
Self { index, value }
}
/// The index of the argument.
pub fn index(&self) -> usize {
self.index
}
/// Set the index of the argument.
pub(crate) fn set_index(&mut self, index: usize) {
self.index = index;
}
/// The value of the argument.
pub fn value(&self) -> &ArgValue<'a> {
&self.value
}
/// Take the value of the argument.
pub fn take_value(self) -> ArgValue<'a> {
self.value
}
/// Take the value of the argument and attempt to convert it to a concrete value, `T`.
///
/// This is a convenience method for calling [`FromArg::from_arg`] on the argument.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let a = 1u32;
/// let b = 2u32;
/// let mut c = 3u32;
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
///
/// let a = args.take::<u32>().unwrap();
/// assert_eq!(a, 1);
///
/// let b = args.take::<&u32>().unwrap();
/// assert_eq!(*b, 2);
///
/// let c = args.take::<&mut u32>().unwrap();
/// assert_eq!(*c, 3);
/// ```
pub fn take<T: FromArg>(self) -> Result<T::This<'a>, ArgError> {
T::from_arg(self)
}
/// Returns `Ok(T)` if the argument is [`ArgValue::Owned`].
///
/// If the argument is not owned, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_owned(value);
/// let value = args.take_owned::<u32>().unwrap();
/// assert_eq!(value, 123);
/// ```
pub fn take_owned<T: Reflect + TypePath>(self) -> Result<T, ArgError> {
match self.value {
ArgValue::Owned(arg) => arg.try_take().map_err(|arg| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
}),
ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Owned,
received: Ownership::Ref,
}),
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Owned,
received: Ownership::Mut,
}),
}
}
/// Returns `Ok(&T)` if the argument is [`ArgValue::Ref`].
///
/// If the argument is not a reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_ref(&value);
/// let value = args.take_ref::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_ref<T: Reflect + TypePath>(self) -> Result<&'a T, ArgError> {
match self.value {
ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Ref,
received: Ownership::Owned,
}),
ArgValue::Ref(arg) => {
Ok(arg
.try_downcast_ref()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
})?)
}
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Ref,
received: Ownership::Mut,
}),
}
}
/// Returns `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
///
/// If the argument is not a mutable reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let mut value = 123u32;
/// let mut args = ArgList::new().with_mut(&mut value);
/// let value = args.take_mut::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_mut<T: Reflect + TypePath>(self) -> Result<&'a mut T, ArgError> {
match self.value {
ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Mut,
received: Ownership::Owned,
}),
ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Mut,
received: Ownership::Ref,
}),
ArgValue::Mut(arg) => {
let received = alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string());
Ok(arg
.try_downcast_mut()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received,
})?)
}
}
}
/// Returns `true` if the argument is of type `T`.
pub fn is<T: TypePath>(&self) -> bool {
self.value
.try_as_reflect()
.map(<dyn Reflect>::is::<T>)
.unwrap_or_default()
}
}
/// Represents an argument that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug)]
pub enum ArgValue<'a> {
Owned(Box<dyn PartialReflect>),
Ref(&'a dyn PartialReflect),
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Deref for ArgValue<'a> {
type Target = dyn PartialReflect;
fn deref(&self) -> &Self::Target {
match self {
ArgValue::Owned(arg) => arg.as_ref(),
ArgValue::Ref(arg) => *arg,
ArgValue::Mut(arg) => *arg,
}
}
}

View File

@@ -0,0 +1,311 @@
use crate::func::args::ArgCountOutOfBoundsError;
use core::fmt::{Debug, Formatter};
/// A container for zero or more argument counts for a function.
///
/// For most functions, this will contain a single count,
/// however, overloaded functions may contain more.
///
/// # Maximum Argument Count
///
/// The maximum number of arguments that can be represented by this struct is 63,
/// as given by [`ArgCount::MAX_COUNT`].
/// The reason for this is that all counts are stored internally as a single `u64`
/// with each bit representing a specific count based on its bit index.
///
/// This allows for a smaller memory footprint and faster lookups compared to a
/// `HashSet` or `Vec` of possible counts.
/// It's also more appropriate for representing the argument counts of a function
/// given that most functions will not have more than a few arguments.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArgCount {
/// The bits representing the argument counts.
///
/// Each bit represents a specific count based on its bit index.
bits: u64,
/// The total number of argument counts.
len: u8,
}
impl ArgCount {
/// The maximum number of arguments that can be represented by this struct.
pub const MAX_COUNT: usize = u64::BITS as usize - 1;
/// Create a new [`ArgCount`] with the given count.
///
/// # Errors
///
/// Returns an error if the count is greater than [`Self::MAX_COUNT`].
pub fn new(count: usize) -> Result<Self, ArgCountOutOfBoundsError> {
Ok(Self {
bits: 1 << Self::try_to_u8(count)?,
len: 1,
})
}
/// Adds the given count to this [`ArgCount`].
///
/// # Panics
///
/// Panics if the count is greater than [`Self::MAX_COUNT`].
pub fn add(&mut self, count: usize) {
self.try_add(count).unwrap();
}
/// Attempts to add the given count to this [`ArgCount`].
///
/// # Errors
///
/// Returns an error if the count is greater than [`Self::MAX_COUNT`].
pub fn try_add(&mut self, count: usize) -> Result<(), ArgCountOutOfBoundsError> {
let count = Self::try_to_u8(count)?;
if !self.contains_unchecked(count) {
self.len += 1;
self.bits |= 1 << count;
}
Ok(())
}
/// Removes the given count from this [`ArgCount`].
pub fn remove(&mut self, count: usize) {
self.try_remove(count).unwrap();
}
/// Attempts to remove the given count from this [`ArgCount`].
///
/// # Errors
///
/// Returns an error if the count is greater than [`Self::MAX_COUNT`].
pub fn try_remove(&mut self, count: usize) -> Result<(), ArgCountOutOfBoundsError> {
let count = Self::try_to_u8(count)?;
if self.contains_unchecked(count) {
self.len -= 1;
self.bits &= !(1 << count);
}
Ok(())
}
/// Checks if this [`ArgCount`] contains the given count.
pub fn contains(&self, count: usize) -> bool {
count < usize::BITS as usize && (self.bits >> count) & 1 == 1
}
/// Returns the total number of argument counts that this [`ArgCount`] contains.
pub fn len(&self) -> usize {
self.len as usize
}
/// Returns true if this [`ArgCount`] contains no argument counts.
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns an iterator over the argument counts in this [`ArgCount`].
pub fn iter(&self) -> ArgCountIter {
ArgCountIter {
count: *self,
index: 0,
found: 0,
}
}
/// Checks if this [`ArgCount`] contains the given count without any bounds checking.
///
/// # Panics
///
/// Panics if the count is greater than [`Self::MAX_COUNT`].
fn contains_unchecked(&self, count: u8) -> bool {
(self.bits >> count) & 1 == 1
}
/// Attempts to convert the given count to a `u8` within the bounds of the [maximum count].
///
/// [maximum count]: Self::MAX_COUNT
fn try_to_u8(count: usize) -> Result<u8, ArgCountOutOfBoundsError> {
if count > Self::MAX_COUNT {
Err(ArgCountOutOfBoundsError(count))
} else {
Ok(count as u8)
}
}
}
/// Defaults this [`ArgCount`] to empty.
///
/// This means that it contains no argument counts, including zero.
impl Default for ArgCount {
fn default() -> Self {
Self { bits: 0, len: 0 }
}
}
impl Debug for ArgCount {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
/// An iterator for the argument counts in an [`ArgCount`].
pub struct ArgCountIter {
count: ArgCount,
index: u8,
found: u8,
}
impl Iterator for ArgCountIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.index as usize > ArgCount::MAX_COUNT {
return None;
}
if self.found == self.count.len {
// All counts have been found
return None;
}
if self.count.contains_unchecked(self.index) {
self.index += 1;
self.found += 1;
return Some(self.index as usize - 1);
}
self.index += 1;
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.count.len(), Some(self.count.len()))
}
}
impl ExactSizeIterator for ArgCountIter {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_default_to_empty() {
let count = ArgCount::default();
assert_eq!(count.len(), 0);
assert!(count.is_empty());
assert!(!count.contains(0));
}
#[test]
fn should_construct_with_count() {
let count = ArgCount::new(3).unwrap();
assert_eq!(count.len(), 1);
assert!(!count.is_empty());
assert!(count.contains(3));
}
#[test]
fn should_add_count() {
let mut count = ArgCount::default();
count.add(3);
assert_eq!(count.len(), 1);
assert!(count.contains(3));
}
#[test]
fn should_add_multiple_counts() {
let mut count = ArgCount::default();
count.add(3);
count.add(5);
count.add(7);
assert_eq!(count.len(), 3);
assert!(!count.contains(0));
assert!(!count.contains(1));
assert!(!count.contains(2));
assert!(count.contains(3));
assert!(count.contains(5));
assert!(count.contains(7));
}
#[test]
fn should_add_idempotently() {
let mut count = ArgCount::default();
count.add(3);
count.add(3);
assert_eq!(count.len(), 1);
assert!(count.contains(3));
}
#[test]
fn should_remove_count() {
let mut count = ArgCount::default();
count.add(3);
assert_eq!(count.len(), 1);
assert!(count.contains(3));
count.remove(3);
assert_eq!(count.len(), 0);
assert!(!count.contains(3));
}
#[test]
fn should_allow_removing_nonexistent_count() {
let mut count = ArgCount::default();
assert_eq!(count.len(), 0);
assert!(!count.contains(3));
count.remove(3);
assert_eq!(count.len(), 0);
assert!(!count.contains(3));
}
#[test]
fn should_iterate_over_counts() {
let mut count = ArgCount::default();
count.add(3);
count.add(5);
count.add(7);
let mut iter = count.iter();
assert_eq!(iter.len(), 3);
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), Some(5));
assert_eq!(iter.next(), Some(7));
assert_eq!(iter.next(), None);
}
#[test]
fn should_return_error_for_out_of_bounds_count() {
let count = ArgCount::new(64);
assert_eq!(count, Err(ArgCountOutOfBoundsError(64)));
let mut count = ArgCount::default();
assert_eq!(count.try_add(64), Err(ArgCountOutOfBoundsError(64)));
assert_eq!(count.try_remove(64), Err(ArgCountOutOfBoundsError(64)));
}
#[test]
fn should_return_false_for_out_of_bounds_contains() {
let count = ArgCount::default();
assert!(!count.contains(64));
}
}

View File

@@ -0,0 +1,36 @@
use alloc::borrow::Cow;
use thiserror::Error;
use crate::func::args::Ownership;
/// An error that occurs when converting an [argument].
///
/// [argument]: crate::func::args::Arg
#[derive(Debug, Error, PartialEq)]
pub enum ArgError {
/// The argument is not the expected type.
#[error("expected `{expected}` but received `{received}` (@ argument index {index})")]
UnexpectedType {
index: usize,
expected: Cow<'static, str>,
received: Cow<'static, str>,
},
/// The argument has the wrong ownership.
#[error("expected {expected} value but received {received} value (@ argument index {index})")]
InvalidOwnership {
index: usize,
expected: Ownership,
received: Ownership,
},
/// Occurs when attempting to access an argument from an empty [`ArgList`].
///
/// [`ArgList`]: crate::func::args::ArgList
#[error("expected an argument but received none")]
EmptyArgList,
}
/// The given argument count is out of bounds.
#[derive(Debug, Error, PartialEq)]
#[error("argument count out of bounds: {0}")]
pub struct ArgCountOutOfBoundsError(pub usize);

View File

@@ -0,0 +1,104 @@
use crate::func::args::{Arg, ArgError};
/// A trait for types that can be created from an [`Arg`].
///
/// This trait exists so that types can be automatically converted into an [`Arg`]
/// so they can be put into an [`ArgList`] and passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// This trait is used instead of a blanket [`From`] implementation due to coherence issues:
/// we can't implement `From<T>` for both `T` and `&T`/`&mut T`.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`ArgList`]: crate::func::args::ArgList
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
/// [derive macro]: derive@crate::Reflect
pub trait FromArg {
/// The type to convert into.
///
/// This should almost always be the same as `Self`, but with the lifetime `'a`.
///
/// The reason we use a separate associated type is to allow for the lifetime
/// to be tied to the argument, rather than the type itself.
type This<'a>;
/// Creates an item from an argument.
///
/// The argument must be of the expected type and ownership.
fn from_arg(arg: Arg) -> Result<Self::This<'_>, ArgError>;
}
/// Implements the [`FromArg`] trait for the given type.
///
/// This will implement it for `$ty`, `&$ty`, and `&mut $ty`.
///
/// See [`impl_function_traits`] for details on syntax.
///
/// [`impl_function_traits`]: crate::func::macros::impl_function_traits
macro_rules! impl_from_arg {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_owned()
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for &'static $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = &'from_arg $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_ref()
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for &'static mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = &'from_arg mut $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_mut()
}
}
};
}
pub(crate) use impl_from_arg;

View File

@@ -0,0 +1,101 @@
use alloc::borrow::Cow;
use crate::{
func::args::{GetOwnership, Ownership},
type_info::impl_type_methods,
Type, TypePath,
};
/// Type information for an [`Arg`] used in a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`Arg`]: crate::func::args::Arg
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)]
pub struct ArgInfo {
/// The index of the argument within its function.
index: usize,
/// The name of the argument (if provided).
name: Option<Cow<'static, str>>,
/// The ownership of the argument.
ownership: Ownership,
/// The [type] of the argument.
///
/// [type]: Type
ty: Type,
}
impl ArgInfo {
/// Create a new [`ArgInfo`] with the given argument index and type `T`.
///
/// To set the name of the argument, use [`Self::with_name`].
pub fn new<T: TypePath + GetOwnership>(index: usize) -> Self {
Self {
index,
name: None,
ownership: T::ownership(),
ty: Type::of::<T>(),
}
}
/// Set the name of the argument.
///
/// Reflected arguments are not required to have a name and by default are not given one,
/// so this method must be called manually to set the name.
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.name = Some(name.into());
self
}
/// The index of the argument within its function.
pub fn index(&self) -> usize {
self.index
}
/// The name of the argument, if it was given one.
///
/// Note that this may return `None` even if the argument has a name.
/// This is because the name needs to be manually set using [`Self::with_name`]
/// since the name can't be inferred from the function type alone.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`]
/// and [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the name will always be `None`.
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
/// The ownership of the argument.
pub fn ownership(&self) -> Ownership {
self.ownership
}
impl_type_methods!(ty);
/// Get an ID representing the argument.
///
/// This will return `ArgId::Name` if the argument has a name,
/// otherwise `ArgId::Index`.
pub fn id(&self) -> ArgId {
self.name
.clone()
.map(ArgId::Name)
.unwrap_or_else(|| ArgId::Index(self.index))
}
}
/// A representation of an argument.
///
/// This is primarily used for error reporting and debugging.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArgId {
/// The index of the argument within its function.
Index(usize),
/// The name of the argument.
Name(Cow<'static, str>),
}

View File

@@ -0,0 +1,458 @@
use crate::{
func::{
args::{Arg, ArgValue, FromArg},
ArgError,
},
PartialReflect, Reflect, TypePath,
};
use alloc::{
boxed::Box,
collections::vec_deque::{Iter, VecDeque},
};
/// A list of arguments that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgValue, ArgList};
/// let foo = 123;
/// let bar = 456;
/// let mut baz = 789;
/// let args = ArgList::new()
/// // Push an owned argument
/// .with_owned(foo)
/// // Push an owned and boxed argument
/// .with_boxed(Box::new(foo))
/// // Push a reference argument
/// .with_ref(&bar)
/// // Push a mutable reference argument
/// .with_mut(&mut baz)
/// // Push a manually constructed argument
/// .with_arg(ArgValue::Ref(&3.14));
/// ```
///
/// [arguments]: Arg
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Default, Debug)]
pub struct ArgList<'a> {
list: VecDeque<Arg<'a>>,
/// A flag that indicates if the list needs to be re-indexed.
///
/// This flag should be set when an argument is removed from the beginning of the list,
/// so that any future push operations will re-index the arguments.
needs_reindex: bool,
}
impl<'a> ArgList<'a> {
/// Create a new empty list of arguments.
pub fn new() -> Self {
Self {
list: VecDeque::new(),
needs_reindex: false,
}
}
/// Push an [`ArgValue`] onto the list.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_arg(&mut self, arg: ArgValue<'a>) {
if self.needs_reindex {
for (index, arg) in self.list.iter_mut().enumerate() {
arg.set_index(index);
}
self.needs_reindex = false;
}
let index = self.list.len();
self.list.push_back(Arg::new(index, arg));
}
/// Push an [`ArgValue::Ref`] onto the list with the given reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_ref(&mut self, arg: &'a dyn PartialReflect) {
self.push_arg(ArgValue::Ref(arg));
}
/// Push an [`ArgValue::Mut`] onto the list with the given mutable reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_mut(&mut self, arg: &'a mut dyn PartialReflect) {
self.push_arg(ArgValue::Mut(arg));
}
/// Push an [`ArgValue::Owned`] onto the list with the given owned value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_owned(&mut self, arg: impl PartialReflect) {
self.push_arg(ArgValue::Owned(Box::new(arg)));
}
/// Push an [`ArgValue::Owned`] onto the list with the given boxed value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_boxed(&mut self, arg: Box<dyn PartialReflect>) {
self.push_arg(ArgValue::Owned(arg));
}
/// Push an [`ArgValue`] onto the list.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_arg(mut self, arg: ArgValue<'a>) -> Self {
self.push_arg(arg);
self
}
/// Push an [`ArgValue::Ref`] onto the list with the given reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_ref(self, arg: &'a dyn PartialReflect) -> Self {
self.with_arg(ArgValue::Ref(arg))
}
/// Push an [`ArgValue::Mut`] onto the list with the given mutable reference.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_mut(self, arg: &'a mut dyn PartialReflect) -> Self {
self.with_arg(ArgValue::Mut(arg))
}
/// Push an [`ArgValue::Owned`] onto the list with the given owned value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_owned(self, arg: impl PartialReflect) -> Self {
self.with_arg(ArgValue::Owned(Box::new(arg)))
}
/// Push an [`ArgValue::Owned`] onto the list with the given boxed value.
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn with_boxed(self, arg: Box<dyn PartialReflect>) -> Self {
self.with_arg(ArgValue::Owned(arg))
}
/// Remove the first argument in the list and return it.
///
/// It's generally preferred to use [`Self::take`] instead of this method
/// as it provides a more ergonomic way to immediately downcast the argument.
pub fn take_arg(&mut self) -> Result<Arg<'a>, ArgError> {
self.needs_reindex = true;
self.list.pop_front().ok_or(ArgError::EmptyArgList)
}
/// Remove the first argument in the list and return `Ok(T::This)`.
///
/// If the list is empty or the [`FromArg::from_arg`] call fails, returns an error.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let a = 1u32;
/// let b = 2u32;
/// let mut c = 3u32;
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
///
/// let a = args.take::<u32>().unwrap();
/// assert_eq!(a, 1);
///
/// let b = args.take::<&u32>().unwrap();
/// assert_eq!(*b, 2);
///
/// let c = args.take::<&mut u32>().unwrap();
/// assert_eq!(*c, 3);
/// ```
pub fn take<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
self.take_arg()?.take::<T>()
}
/// Remove the first argument in the list and return `Ok(T)` if the argument is [`ArgValue::Owned`].
///
/// If the list is empty or the argument is not owned, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_owned(value);
/// let value = args.take_owned::<u32>().unwrap();
/// assert_eq!(value, 123);
/// ```
pub fn take_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
self.take_arg()?.take_owned()
}
/// Remove the first argument in the list and return `Ok(&T)` if the argument is [`ArgValue::Ref`].
///
/// If the list is empty or the argument is not a reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_ref(&value);
/// let value = args.take_ref::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
self.take_arg()?.take_ref()
}
/// Remove the first argument in the list and return `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
///
/// If the list is empty or the argument is not a mutable reference, returns an error.
///
/// It's generally preferred to use [`Self::take`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let mut value = 123u32;
/// let mut args = ArgList::new().with_mut(&mut value);
/// let value = args.take_mut::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn take_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
self.take_arg()?.take_mut()
}
/// Remove the last argument in the list and return it.
///
/// It's generally preferred to use [`Self::pop`] instead of this method
/// as it provides a more ergonomic way to immediately downcast the argument.
pub fn pop_arg(&mut self) -> Result<Arg<'a>, ArgError> {
self.list.pop_back().ok_or(ArgError::EmptyArgList)
}
/// Remove the last argument in the list and return `Ok(T::This)`.
///
/// If the list is empty or the [`FromArg::from_arg`] call fails, returns an error.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let a = 1u32;
/// let b = 2u32;
/// let mut c = 3u32;
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
///
/// let c = args.pop::<&mut u32>().unwrap();
/// assert_eq!(*c, 3);
///
/// let b = args.pop::<&u32>().unwrap();
/// assert_eq!(*b, 2);
///
/// let a = args.pop::<u32>().unwrap();
/// assert_eq!(a, 1);
/// ```
pub fn pop<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
self.pop_arg()?.take::<T>()
}
/// Remove the last argument in the list and return `Ok(T)` if the argument is [`ArgValue::Owned`].
///
/// If the list is empty or the argument is not owned, returns an error.
///
/// It's generally preferred to use [`Self::pop`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_owned(value);
/// let value = args.pop_owned::<u32>().unwrap();
/// assert_eq!(value, 123);
/// ```
pub fn pop_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
self.pop_arg()?.take_owned()
}
/// Remove the last argument in the list and return `Ok(&T)` if the argument is [`ArgValue::Ref`].
///
/// If the list is empty or the argument is not a reference, returns an error.
///
/// It's generally preferred to use [`Self::pop`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let value = 123u32;
/// let mut args = ArgList::new().with_ref(&value);
/// let value = args.pop_ref::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn pop_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
self.pop_arg()?.take_ref()
}
/// Remove the last argument in the list and return `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
///
/// If the list is empty or the argument is not a mutable reference, returns an error.
///
/// It's generally preferred to use [`Self::pop`] instead of this method.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::ArgList;
/// let mut value = 123u32;
/// let mut args = ArgList::new().with_mut(&mut value);
/// let value = args.pop_mut::<u32>().unwrap();
/// assert_eq!(*value, 123);
/// ```
pub fn pop_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
self.pop_arg()?.take_mut()
}
/// Returns an iterator over the arguments in the list.
pub fn iter(&self) -> Iter<'_, Arg<'a>> {
self.list.iter()
}
/// Returns the number of arguments in the list.
pub fn len(&self) -> usize {
self.list.len()
}
/// Returns `true` if the list of arguments is empty.
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
#[test]
fn should_push_arguments_in_order() {
let args = ArgList::new()
.with_owned(123)
.with_owned(456)
.with_owned(789);
assert_eq!(args.len(), 3);
assert_eq!(args.list[0].index(), 0);
assert_eq!(args.list[1].index(), 1);
assert_eq!(args.list[2].index(), 2);
}
#[test]
fn should_push_arg_with_correct_ownership() {
let a = String::from("a");
let b = String::from("b");
let mut c = String::from("c");
let d = String::from("d");
let e = String::from("e");
let f = String::from("f");
let mut g = String::from("g");
let args = ArgList::new()
.with_arg(ArgValue::Owned(Box::new(a)))
.with_arg(ArgValue::Ref(&b))
.with_arg(ArgValue::Mut(&mut c))
.with_owned(d)
.with_boxed(Box::new(e))
.with_ref(&f)
.with_mut(&mut g);
assert!(matches!(args.list[0].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[1].value(), &ArgValue::Ref(_)));
assert!(matches!(args.list[2].value(), &ArgValue::Mut(_)));
assert!(matches!(args.list[3].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[4].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[5].value(), &ArgValue::Ref(_)));
assert!(matches!(args.list[6].value(), &ArgValue::Mut(_)));
}
#[test]
fn should_take_args_in_order() {
let a = String::from("a");
let b = 123_i32;
let c = 456_usize;
let mut d = 5.78_f32;
let mut args = ArgList::new()
.with_owned(a)
.with_ref(&b)
.with_ref(&c)
.with_mut(&mut d);
assert_eq!(args.len(), 4);
assert_eq!(args.take_owned::<String>().unwrap(), String::from("a"));
assert_eq!(args.take::<&i32>().unwrap(), &123);
assert_eq!(args.take_ref::<usize>().unwrap(), &456);
assert_eq!(args.take_mut::<f32>().unwrap(), &mut 5.78);
assert_eq!(args.len(), 0);
}
#[test]
fn should_pop_args_in_reverse_order() {
let a = String::from("a");
let b = 123_i32;
let c = 456_usize;
let mut d = 5.78_f32;
let mut args = ArgList::new()
.with_owned(a)
.with_ref(&b)
.with_ref(&c)
.with_mut(&mut d);
assert_eq!(args.len(), 4);
assert_eq!(args.pop_mut::<f32>().unwrap(), &mut 5.78);
assert_eq!(args.pop_ref::<usize>().unwrap(), &456);
assert_eq!(args.pop::<&i32>().unwrap(), &123);
assert_eq!(args.pop_owned::<String>().unwrap(), String::from("a"));
assert_eq!(args.len(), 0);
}
#[test]
fn should_reindex_on_push_after_take() {
let mut args = ArgList::new()
.with_owned(123)
.with_owned(456)
.with_owned(789);
assert!(!args.needs_reindex);
args.take_arg().unwrap();
assert!(args.needs_reindex);
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
assert_eq!(args.list[0].index(), 1);
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
assert_eq!(args.list[1].index(), 2);
let args = args.with_owned(123);
assert!(!args.needs_reindex);
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
assert_eq!(args.list[0].index(), 0);
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
assert_eq!(args.list[1].index(), 1);
assert!(args.list[2].value().reflect_partial_eq(&123).unwrap());
assert_eq!(args.list[2].index(), 2);
}
}

View File

@@ -0,0 +1,20 @@
//! Argument types and utilities for working with [`DynamicFunction`] and [`DynamicFunctionMut`].
//!
//! [`DynamicFunction`]: crate::func::DynamicFunction
//! [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
pub use arg::*;
pub use count::*;
pub use error::*;
pub use from_arg::*;
pub use info::*;
pub use list::*;
pub use ownership::*;
mod arg;
mod count;
mod error;
mod from_arg;
mod info;
mod list;
mod ownership;

View File

@@ -0,0 +1,109 @@
use core::fmt::{Display, Formatter};
/// A trait for getting the ownership of a type.
///
/// This trait exists so that [`TypedFunction`] can automatically generate
/// [`FunctionInfo`] containing the proper [`Ownership`] for its [argument] types.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`TypedFunction`]: crate::func::TypedFunction
/// [`FunctionInfo`]: crate::func::FunctionInfo
/// [argument]: crate::func::args::Arg
/// [derive macro]: derive@crate::Reflect
pub trait GetOwnership {
/// Returns the ownership of [`Self`].
fn ownership() -> Ownership;
}
/// The ownership of a type.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Ownership {
/// The type is a reference (i.e. `&T`).
Ref,
/// The type is a mutable reference (i.e. `&mut T`).
Mut,
/// The type is owned (i.e. `T`).
Owned,
}
impl Display for Ownership {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::Ref => write!(f, "reference"),
Self::Mut => write!(f, "mutable reference"),
Self::Owned => write!(f, "owned"),
}
}
}
/// Implements the [`GetOwnership`] trait for the given type.
///
/// This will implement it for `$ty`, `&$ty`, and `&mut $ty`.
///
/// See [`impl_function_traits`] for details on syntax.
///
/// [`impl_function_traits`]: crate::func::macros::impl_function_traits
macro_rules! impl_get_ownership {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Owned
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for &'_ $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Ref
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for &'_ mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Mut
}
}
};
}
pub(crate) use impl_get_ownership;

View File

@@ -0,0 +1,805 @@
use crate::{
__macro_exports::RegisterForReflection,
func::{
args::{ArgCount, ArgList},
dynamic_function_internal::DynamicFunctionInternal,
info::FunctionInfo,
DynamicFunctionMut, Function, FunctionOverloadError, FunctionResult, IntoFunction,
IntoFunctionMut,
},
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo, TypePath,
};
use alloc::{borrow::Cow, boxed::Box};
use bevy_platform::sync::Arc;
use bevy_reflect_derive::impl_type_path;
use core::fmt::{Debug, Formatter};
/// An [`Arc`] containing a callback to a reflected function.
///
/// The `Arc` is used to both ensure that it is `Send + Sync`
/// and to allow for the callback to be cloned.
///
/// Note that cloning is okay since we only ever need an immutable reference
/// to call a `dyn Fn` function.
/// If we were to contain a `dyn FnMut` instead, cloning would be a lot more complicated.
type ArcFn<'env> = Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>;
/// A dynamic representation of a function.
///
/// This type can be used to represent any callable that satisfies [`Fn`]
/// (or the reflection-based equivalent, [`ReflectFn`]).
/// That is, any function or closure that does not mutably borrow data from its environment.
///
/// For functions that do need to capture their environment mutably (i.e. mutable closures),
/// see [`DynamicFunctionMut`].
///
/// See the [module-level documentation] for more information.
///
/// You will generally not need to construct this manually.
/// Instead, many functions and closures can be automatically converted using the [`IntoFunction`] trait.
///
/// # Example
///
/// Most of the time, a [`DynamicFunction`] can be created using the [`IntoFunction`] trait:
///
/// ```
/// # use bevy_reflect::func::{ArgList, DynamicFunction, IntoFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// // Convert the function into a dynamic function using `IntoFunction::into_function`:
/// let mut func: DynamicFunction = add.into_function();
///
/// // Dynamically call it:
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
/// ```
///
/// [`ReflectFn`]: crate::func::ReflectFn
/// [module-level documentation]: crate::func
#[derive(Clone)]
pub struct DynamicFunction<'env> {
pub(super) internal: DynamicFunctionInternal<ArcFn<'env>>,
}
impl<'env> DynamicFunction<'env> {
/// Create a new [`DynamicFunction`].
///
/// The given function can be used to call out to any other callable,
/// including functions, closures, or methods.
///
/// It's important that the function signature matches the provided [`FunctionInfo`].
/// as this will be used to validate arguments when [calling] the function.
/// This is also required in order for [function overloading] to work correctly.
///
/// # Panics
///
/// This function may panic for any of the following reasons:
/// - No [`SignatureInfo`] is provided.
/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].
/// - The conversion to [`FunctionInfo`] fails.
///
/// [calling]: crate::func::dynamic_function::DynamicFunction::call
/// [`SignatureInfo`]: crate::func::SignatureInfo
/// [function overloading]: Self::with_overload
pub fn new<F: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>(
func: F,
info: impl TryInto<FunctionInfo, Error: Debug>,
) -> Self {
let arc = Arc::new(func);
#[cfg(not(target_has_atomic = "ptr"))]
#[expect(
unsafe_code,
reason = "unsized coercion is an unstable feature for non-std types"
)]
// SAFETY:
// - Coercion from `T` to `dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`
// is valid as `T: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
let arc = unsafe { ArcFn::<'env>::from_raw(Arc::into_raw(arc) as *const _) };
Self {
internal: DynamicFunctionInternal::new(arc, info.try_into().unwrap()),
}
}
/// Set the name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctions`]: DynamicFunction
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.internal = self.internal.with_name(name);
self
}
/// Add an overload to this function.
///
/// Overloads allow a single [`DynamicFunction`] to represent multiple functions of different signatures.
///
/// This can be used to handle multiple monomorphizations of a generic function
/// or to allow functions with a variable number of arguments.
///
/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.
/// For example, if the existing function had the signature `(i32, i32) -> i32`,
/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,
/// the one from `F` would replace the one from the existing function.
///
/// Overloaded functions retain the [name] of the original function.
///
/// # Panics
///
/// Panics if the function, `F`, contains a signature already found in this function.
///
/// For a non-panicking version, see [`try_with_overload`].
///
/// # Examples
///
/// ```
/// # use std::ops::Add;
/// # use bevy_reflect::func::{ArgList, IntoFunction};
/// #
/// fn add<T: Add<Output = T>>(a: T, b: T) -> T {
/// a + b
/// }
///
/// // Currently, the only generic type `func` supports is `i32`:
/// let mut func = add::<i32>.into_function();
///
/// // However, we can add an overload to handle `f32` as well:
/// func = func.with_overload(add::<f32>);
///
/// // Test `i32`:
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
///
/// // Test `f32`:
/// let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
///```
///
/// ```
/// # use bevy_reflect::func::{ArgList, IntoFunction};
/// #
/// fn add_2(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// fn add_3(a: i32, b: i32, c: i32) -> i32 {
/// a + b + c
/// }
///
/// // Currently, `func` only supports two arguments.
/// let mut func = add_2.into_function();
///
/// // However, we can add an overload to handle three arguments as well.
/// func = func.with_overload(add_3);
///
/// // Test two arguments:
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
///
/// // Test three arguments:
/// let args = ArgList::default()
/// .with_owned(25_i32)
/// .with_owned(75_i32)
/// .with_owned(100_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 200);
/// ```
///
///```should_panic
/// # use bevy_reflect::func::IntoFunction;
///
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// fn sub(a: i32, b: i32) -> i32 {
/// a - b
/// }
///
/// let mut func = add.into_function();
///
/// // This will panic because the function already has an argument signature for `(i32, i32)`:
/// func = func.with_overload(sub);
/// ```
///
/// [argument signature]: crate::func::signature::ArgumentSignature
/// [name]: Self::name
/// [`try_with_overload`]: Self::try_with_overload
pub fn with_overload<'a, F: IntoFunction<'a, Marker>, Marker>(
self,
function: F,
) -> DynamicFunction<'a>
where
'env: 'a,
{
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
panic!("{}", err);
})
}
/// Attempt to add an overload to this function.
///
/// If the function, `F`, contains a signature already found in this function,
/// an error will be returned along with the original function.
///
/// For a panicking version, see [`with_overload`].
///
/// [`with_overload`]: Self::with_overload
pub fn try_with_overload<F: IntoFunction<'env, Marker>, Marker>(
mut self,
function: F,
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
let function = function.into_function();
match self.internal.merge(function.internal) {
Ok(_) => Ok(self),
Err(err) => Err((Box::new(self), err)),
}
}
/// Call the function with the given arguments.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunction, ArgList};
/// let c = 23;
/// let add = |a: i32, b: i32| -> i32 {
/// a + b + c
/// };
///
/// let mut func = add.into_function().with_name("add");
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 123);
/// ```
///
/// # Errors
///
/// This method will return an error if the number of arguments provided does not match
/// the number of arguments expected by the function's [`FunctionInfo`].
///
/// The function itself may also return any errors it needs to.
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
self.internal.validate_args(&args)?;
let func = self.internal.get(&args)?;
func(args)
}
/// Returns the function info.
pub fn info(&self) -> &FunctionInfo {
self.internal.info()
}
/// The name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// This can be overridden using [`with_name`].
///
/// If the function was [overloaded], it will retain its original name if it had one.
///
/// [`DynamicFunctions`]: DynamicFunction
/// [`with_name`]: Self::with_name
/// [overloaded]: Self::with_overload
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.internal.name()
}
/// Returns `true` if the function is [overloaded].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunction;
/// let add = (|a: i32, b: i32| a + b).into_function();
/// assert!(!add.is_overloaded());
///
/// let add = add.with_overload(|a: f32, b: f32| a + b);
/// assert!(add.is_overloaded());
/// ```
///
/// [overloaded]: Self::with_overload
pub fn is_overloaded(&self) -> bool {
self.internal.is_overloaded()
}
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunction;
/// let add = (|a: i32, b: i32| a + b).into_function();
/// assert!(add.arg_count().contains(2));
///
/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);
/// assert!(add.arg_count().contains(2));
/// assert!(add.arg_count().contains(3));
/// ```
///
/// [overloaded]: Self::with_overload
pub fn arg_count(&self) -> ArgCount {
self.internal.arg_count()
}
}
impl Function for DynamicFunction<'static> {
fn name(&self) -> Option<&Cow<'static, str>> {
self.internal.name()
}
fn info(&self) -> &FunctionInfo {
self.internal.info()
}
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
self.call(args)
}
fn to_dynamic_function(&self) -> DynamicFunction<'static> {
self.clone()
}
}
impl PartialReflect for DynamicFunction<'static> {
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
None
}
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
match value.reflect_ref() {
ReflectRef::Function(func) => {
*self = func.to_dynamic_function();
Ok(())
}
_ => Err(ApplyError::MismatchedTypes {
from_type: value.reflect_type_path().into(),
to_type: Self::type_path().into(),
}),
}
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Function
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Function(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Function(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Function(self)
}
fn reflect_hash(&self) -> Option<u64> {
None
}
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
None
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Debug::fmt(self, f)
}
fn is_dynamic(&self) -> bool {
true
}
}
impl MaybeTyped for DynamicFunction<'static> {}
impl RegisterForReflection for DynamicFunction<'static> {}
impl_type_path!((in bevy_reflect) DynamicFunction<'env>);
/// Outputs the function's signature.
///
/// This takes the format: `DynamicFunction(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.
///
/// Names for arguments and the function itself are optional and will default to `_` if not provided.
///
/// If the function is [overloaded], the output will include the signatures of all overloads as a set.
/// For example, `DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.
///
/// [overloaded]: DynamicFunction::with_overload
impl<'env> Debug for DynamicFunction<'env> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicFunction({:?})", &self.internal)
}
}
impl<'env> IntoFunction<'env, ()> for DynamicFunction<'env> {
#[inline]
fn into_function(self) -> DynamicFunction<'env> {
self
}
}
impl<'env> IntoFunctionMut<'env, ()> for DynamicFunction<'env> {
#[inline]
fn into_function_mut(self) -> DynamicFunctionMut<'env> {
DynamicFunctionMut::from(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::signature::ArgumentSignature;
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
use crate::Type;
use alloc::{format, string::String, vec, vec::Vec};
use bevy_platform::collections::HashSet;
use core::ops::Add;
#[test]
fn should_overwrite_function_name() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
assert!(func.name().is_none());
let func = func.with_name("my_function");
assert_eq!(func.name().unwrap(), "my_function");
}
#[test]
fn should_convert_dynamic_function_with_into_function() {
fn make_closure<'env, F: IntoFunction<'env, M>, M>(f: F) -> DynamicFunction<'env> {
f.into_function()
}
let c = 23;
let function: DynamicFunction = make_closure(|a: i32, b: i32| a + b + c);
let _: DynamicFunction = make_closure(function);
}
#[test]
fn should_return_error_on_arg_count_mismatch() {
let func = (|a: i32, b: i32| a + b).into_function();
let args = ArgList::default().with_owned(25_i32);
let error = func.call(args).unwrap_err();
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: ArgCount::new(2).unwrap(),
received: 1
}
);
}
#[test]
fn should_return_error_on_arg_count_mismatch_overloaded() {
let func = (|a: i32, b: i32| a + b)
.into_function()
.with_overload(|a: i32, b: i32, c: i32| a + b + c);
let args = ArgList::default()
.with_owned(1_i32)
.with_owned(2_i32)
.with_owned(3_i32)
.with_owned(4_i32);
let error = func.call(args).unwrap_err();
let mut expected_count = ArgCount::new(2).unwrap();
expected_count.add(3);
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: expected_count,
received: 4
}
);
}
#[test]
fn should_clone_dynamic_function() {
let hello = String::from("Hello");
let greet = |name: &String| -> String { format!("{}, {}!", hello, name) };
let greet = greet.into_function().with_name("greet");
let clone = greet.clone();
assert_eq!(greet.name().unwrap(), "greet");
assert_eq!(clone.name().unwrap(), "greet");
let cloned_value = clone
.call(ArgList::default().with_ref(&String::from("world")))
.unwrap()
.unwrap_owned()
.try_take::<String>()
.unwrap();
assert_eq!(cloned_value, "Hello, world!");
}
#[test]
fn should_apply_function() {
let mut func: Box<dyn Function> = Box::new((|a: i32, b: i32| a + b).into_function());
func.apply(&((|a: i32, b: i32| a * b).into_function()));
let args = ArgList::new().with_owned(5_i32).with_owned(5_i32);
let result = func.reflect_call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 25);
}
#[test]
fn should_allow_recursive_dynamic_function() {
let factorial = DynamicFunction::new(
|mut args| {
let curr = args.pop::<i32>()?;
if curr == 0 {
return Ok(1_i32.into_return());
}
let arg = args.pop_arg()?;
let this = arg.value();
match this.reflect_ref() {
ReflectRef::Function(func) => {
let result = func.reflect_call(
ArgList::new()
.with_ref(this.as_partial_reflect())
.with_owned(curr - 1),
);
let value = result.unwrap().unwrap_owned().try_take::<i32>().unwrap();
Ok((curr * value).into_return())
}
_ => panic!("expected function"),
}
},
// The `FunctionInfo` doesn't really matter for this test
// so we can just give it dummy information.
SignatureInfo::anonymous()
.with_arg::<i32>("curr")
.with_arg::<()>("this"),
);
let args = ArgList::new().with_ref(&factorial).with_owned(5_i32);
let value = factorial.call(args).unwrap().unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 120);
}
#[test]
fn should_allow_creating_manual_generic_dynamic_function() {
let func = DynamicFunction::new(
|mut args| {
let a = args.take_arg()?;
let b = args.take_arg()?;
if a.is::<i32>() {
let a = a.take::<i32>()?;
let b = b.take::<i32>()?;
Ok((a + b).into_return())
} else {
let a = a.take::<f32>()?;
let b = b.take::<f32>()?;
Ok((a + b).into_return())
}
},
vec![
SignatureInfo::named("add::<i32>")
.with_arg::<i32>("a")
.with_arg::<i32>("b")
.with_return::<i32>(),
SignatureInfo::named("add::<f32>")
.with_arg::<f32>("a")
.with_arg::<f32>("b")
.with_return::<f32>(),
],
);
assert_eq!(func.name().unwrap(), "add::<i32>");
let func = func.with_name("add");
assert_eq!(func.name().unwrap(), "add");
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
}
#[test]
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: MissingSignature")]
fn should_panic_on_missing_function_info() {
let _ = DynamicFunction::new(|_| Ok(().into_return()), Vec::new());
}
#[test]
fn should_allow_function_overloading() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let func = add::<i32>.into_function().with_overload(add::<f32>);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
}
#[test]
fn should_allow_variable_arguments_via_overloading() {
fn add_2(a: i32, b: i32) -> i32 {
a + b
}
fn add_3(a: i32, b: i32, c: i32) -> i32 {
a + b + c
}
let func = add_2.into_function().with_overload(add_3);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default()
.with_owned(25_i32)
.with_owned(75_i32)
.with_owned(100_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 200);
}
#[test]
fn should_allow_function_overloading_with_manual_overload() {
let manual = DynamicFunction::new(
|mut args| {
let a = args.take_arg()?;
let b = args.take_arg()?;
if a.is::<i32>() {
let a = a.take::<i32>()?;
let b = b.take::<i32>()?;
Ok((a + b).into_return())
} else {
let a = a.take::<f32>()?;
let b = b.take::<f32>()?;
Ok((a + b).into_return())
}
},
vec![
SignatureInfo::named("add::<i32>")
.with_arg::<i32>("a")
.with_arg::<i32>("b")
.with_return::<i32>(),
SignatureInfo::named("add::<f32>")
.with_arg::<f32>("a")
.with_arg::<f32>("b")
.with_return::<f32>(),
],
);
let func = manual.with_overload(|a: u32, b: u32| a + b);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<u32>().unwrap(), 100);
}
#[test]
fn should_return_error_on_unknown_overload() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let func = add::<i32>.into_function().with_overload(add::<f32>);
let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::NoOverload {
expected: [
ArgumentSignature::from_iter(vec![Type::of::<i32>(), Type::of::<i32>()]),
ArgumentSignature::from_iter(vec![Type::of::<f32>(), Type::of::<f32>()])
]
.into_iter()
.collect::<HashSet<_>>(),
received: ArgumentSignature::from_iter(vec![Type::of::<u32>(), Type::of::<u32>()]),
}
);
}
#[test]
fn should_debug_dynamic_function() {
fn greet(name: &String) -> String {
format!("Hello, {}!", name)
}
let function = greet.into_function();
let debug = format!("{:?}", function);
assert_eq!(debug, "DynamicFunction(fn bevy_reflect::func::dynamic_function::tests::should_debug_dynamic_function::greet(_: &alloc::string::String) -> alloc::string::String)");
}
#[test]
fn should_debug_anonymous_dynamic_function() {
let function = (|a: i32, b: i32| a + b).into_function();
let debug = format!("{:?}", function);
assert_eq!(debug, "DynamicFunction(fn _(_: i32, _: i32) -> i32)");
}
#[test]
fn should_debug_overloaded_dynamic_function() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let func = add::<i32>
.into_function()
.with_overload(add::<f32>)
.with_name("add");
let debug = format!("{:?}", func);
assert_eq!(
debug,
"DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})"
);
}
}

View File

@@ -0,0 +1,378 @@
use crate::func::args::ArgCount;
use crate::func::signature::{ArgListSignature, ArgumentSignature};
use crate::func::{ArgList, FunctionError, FunctionInfo, FunctionOverloadError};
use alloc::{borrow::Cow, vec, vec::Vec};
use bevy_platform::collections::HashMap;
use core::fmt::{Debug, Formatter};
/// An internal structure for storing a function and its corresponding [function information].
///
/// This is used to facilitate the sharing of functionality between [`DynamicFunction`]
/// and [`DynamicFunctionMut`].
///
/// [function information]: FunctionInfo
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Clone)]
pub(super) struct DynamicFunctionInternal<F> {
functions: Vec<F>,
info: FunctionInfo,
arg_map: HashMap<ArgumentSignature, usize>,
}
impl<F> DynamicFunctionInternal<F> {
/// Create a new instance of [`DynamicFunctionInternal`] with the given function
/// and its corresponding information.
pub fn new(func: F, info: FunctionInfo) -> Self {
let arg_map = info
.signatures()
.iter()
.map(|sig| (ArgumentSignature::from(sig), 0))
.collect();
Self {
functions: vec![func],
info,
arg_map,
}
}
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.info = self.info.with_name(Some(name.into()));
self
}
/// The name of the function.
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.info.name()
}
/// Returns `true` if the function is overloaded.
pub fn is_overloaded(&self) -> bool {
self.info.is_overloaded()
}
/// Get an immutable reference to the function.
///
/// If the function is not overloaded, it will always be returned regardless of the arguments.
/// Otherwise, the function will be selected based on the arguments provided.
///
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
pub fn get(&self, args: &ArgList) -> Result<&F, FunctionError> {
if !self.info.is_overloaded() {
return Ok(&self.functions[0]);
}
let signature = ArgListSignature::from(args);
self.arg_map
.get(&signature)
.map(|index| &self.functions[*index])
.ok_or_else(|| FunctionError::NoOverload {
expected: self.arg_map.keys().cloned().collect(),
received: ArgumentSignature::from(args),
})
}
/// Get a mutable reference to the function.
///
/// If the function is not overloaded, it will always be returned regardless of the arguments.
/// Otherwise, the function will be selected based on the arguments provided.
///
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
pub fn get_mut(&mut self, args: &ArgList) -> Result<&mut F, FunctionError> {
if !self.info.is_overloaded() {
return Ok(&mut self.functions[0]);
}
let signature = ArgListSignature::from(args);
self.arg_map
.get(&signature)
.map(|index| &mut self.functions[*index])
.ok_or_else(|| FunctionError::NoOverload {
expected: self.arg_map.keys().cloned().collect(),
received: ArgumentSignature::from(args),
})
}
/// Returns the function information contained in the map.
#[inline]
pub fn info(&self) -> &FunctionInfo {
&self.info
}
/// Returns the number of arguments the function expects.
///
/// For overloaded functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
pub fn arg_count(&self) -> ArgCount {
self.info.arg_count()
}
/// Helper method for validating that a given set of arguments are _potentially_ valid for this function.
///
/// Currently, this validates:
/// - The number of arguments is within the expected range
pub fn validate_args(&self, args: &ArgList) -> Result<(), FunctionError> {
let expected_arg_count = self.arg_count();
let received_arg_count = args.len();
if !expected_arg_count.contains(received_arg_count) {
Err(FunctionError::ArgCountMismatch {
expected: expected_arg_count,
received: received_arg_count,
})
} else {
Ok(())
}
}
/// Merge another [`DynamicFunctionInternal`] into this one.
///
/// If `other` contains any functions with the same signature as this one,
/// an error will be returned along with the original, unchanged instance.
///
/// Therefore, this method should always return an overloaded function if the merge is successful.
///
/// Additionally, if the merge succeeds, it should be guaranteed that the order
/// of the functions in the map will be preserved.
/// For example, merging `[func_a, func_b]` (self) with `[func_c, func_d]` (other) should result in
/// `[func_a, func_b, func_c, func_d]`.
/// And merging `[func_c, func_d]` (self) with `[func_a, func_b]` (other) should result in
/// `[func_c, func_d, func_a, func_b]`.
pub fn merge(&mut self, mut other: Self) -> Result<(), FunctionOverloadError> {
// Keep a separate map of the new indices to avoid mutating the existing one
// until we can be sure the merge will be successful.
let mut new_signatures = <HashMap<_, _>>::default();
for (sig, index) in other.arg_map {
if self.arg_map.contains_key(&sig) {
return Err(FunctionOverloadError::DuplicateSignature(sig));
}
new_signatures.insert(sig, self.functions.len() + index);
}
self.arg_map.reserve(new_signatures.len());
for (sig, index) in new_signatures {
self.arg_map.insert(sig, index);
}
self.functions.append(&mut other.functions);
self.info.extend_unchecked(other.info);
Ok(())
}
/// Maps the internally stored function(s) from type `F` to type `G`.
pub fn map_functions<G>(self, f: fn(F) -> G) -> DynamicFunctionInternal<G> {
DynamicFunctionInternal {
functions: self.functions.into_iter().map(f).collect(),
info: self.info,
arg_map: self.arg_map,
}
}
}
impl<F> Debug for DynamicFunctionInternal<F> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.info
.pretty_printer()
.include_fn_token()
.include_name()
.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{FunctionInfo, SignatureInfo};
use crate::Type;
#[test]
fn should_merge_single_into_single() {
let mut func_a = DynamicFunctionInternal::new(
'a',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
);
let func_b = DynamicFunctionInternal::new(
'b',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
);
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b']);
assert_eq!(func_a.info.signatures().len(), 2);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
])
);
}
#[test]
fn should_merge_single_into_overloaded() {
let mut func_a = DynamicFunctionInternal::new(
'a',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
);
let func_b = DynamicFunctionInternal {
functions: vec!['b', 'c'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
]),
};
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
assert_eq!(func_a.info.signatures().len(), 3);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 2),
])
);
}
#[test]
fn should_merge_overload_into_single() {
let mut func_a = DynamicFunctionInternal {
functions: vec!['a', 'b'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
]),
};
let func_b = DynamicFunctionInternal::new(
'c',
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
);
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
assert_eq!(func_a.info.signatures().len(), 3);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),
])
);
}
#[test]
fn should_merge_overloaded_into_overloaded() {
let mut func_a = DynamicFunctionInternal {
functions: vec!['a', 'b'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
]),
};
let func_b = DynamicFunctionInternal {
functions: vec!['c', 'd'],
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
.unwrap(),
arg_map: HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
]),
};
func_a.merge(func_b).unwrap();
assert_eq!(func_a.functions, vec!['a', 'b', 'c', 'd']);
assert_eq!(func_a.info.signatures().len(), 4);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),
(ArgumentSignature::from_iter([Type::of::<u16>()]), 3),
])
);
}
#[test]
fn should_return_error_on_duplicate_signature() {
let mut func_a = DynamicFunctionInternal::new(
'a',
FunctionInfo::new(
SignatureInfo::anonymous()
.with_arg::<i8>("arg0")
.with_arg::<i16>("arg1"),
),
);
let func_b = DynamicFunctionInternal {
functions: vec!['b', 'c'],
info: FunctionInfo::new(
SignatureInfo::anonymous()
.with_arg::<u8>("arg0")
.with_arg::<u16>("arg1"),
)
.with_overload(
SignatureInfo::anonymous()
.with_arg::<i8>("arg0")
.with_arg::<i16>("arg1"),
)
.unwrap(),
arg_map: HashMap::from_iter([
(
ArgumentSignature::from_iter([Type::of::<u8>(), Type::of::<u16>()]),
0,
),
(
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
1,
),
]),
};
let FunctionOverloadError::DuplicateSignature(duplicate) =
func_a.merge(func_b).unwrap_err()
else {
panic!("Expected `FunctionOverloadError::DuplicateSignature`");
};
assert_eq!(
duplicate,
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()])
);
// Assert the original remains unchanged:
assert!(!func_a.is_overloaded());
assert_eq!(func_a.functions, vec!['a']);
assert_eq!(func_a.info.signatures().len(), 1);
assert_eq!(
func_a.arg_map,
HashMap::from_iter([(
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
0
),])
);
}
}

View File

@@ -0,0 +1,488 @@
use alloc::{borrow::Cow, boxed::Box};
use bevy_platform::sync::Arc;
use core::fmt::{Debug, Formatter};
use crate::func::{
args::{ArgCount, ArgList},
dynamic_function_internal::DynamicFunctionInternal,
DynamicFunction, FunctionInfo, FunctionOverloadError, FunctionResult, IntoFunctionMut,
};
/// A [`Box`] containing a callback to a reflected function.
type BoxFnMut<'env> = Box<dyn for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>;
/// A dynamic representation of a function.
///
/// This type can be used to represent any callable that satisfies [`FnMut`]
/// (or the reflection-based equivalent, [`ReflectFnMut`]).
/// That is, any function or closure.
///
/// For functions that do not need to capture their environment mutably,
/// it's recommended to use [`DynamicFunction`] instead.
///
/// This type can be seen as a superset of [`DynamicFunction`].
///
/// See the [module-level documentation] for more information.
///
/// You will generally not need to construct this manually.
/// Instead, many functions and closures can be automatically converted using the [`IntoFunctionMut`] trait.
///
/// # Example
///
/// Most of the time, a [`DynamicFunctionMut`] can be created using the [`IntoFunctionMut`] trait:
///
/// ```
/// # use bevy_reflect::func::{ArgList, DynamicFunctionMut, FunctionInfo, IntoFunctionMut};
/// #
/// let mut list: Vec<i32> = vec![1, 2, 3];
///
/// // `replace` is a closure that captures a mutable reference to `list`
/// let mut replace = |index: usize, value: i32| -> i32 {
/// let old_value = list[index];
/// list[index] = value;
/// old_value
/// };
///
/// // Since this closure mutably borrows data, we can't convert it into a regular `DynamicFunction`,
/// // as doing so would result in a compile-time error:
/// // let mut func: DynamicFunction = replace.into_function();
///
/// // Instead, we convert it into a `DynamicFunctionMut` using `IntoFunctionMut::into_function_mut`:
/// let mut func: DynamicFunctionMut = replace.into_function_mut();
///
/// // Dynamically call it:
/// let args = ArgList::default().with_owned(1_usize).with_owned(-2_i32);
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.try_take::<i32>().unwrap(), 2);
///
/// // Note that `func` still has a reference to `list`,
/// // so we need to drop it before we can access `list` again.
/// // Alternatively, we could have invoked `func` with
/// // `DynamicFunctionMut::call_once` to immediately consume it.
/// drop(func);
/// assert_eq!(list, vec![1, -2, 3]);
/// ```
///
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
/// [module-level documentation]: crate::func
pub struct DynamicFunctionMut<'env> {
internal: DynamicFunctionInternal<BoxFnMut<'env>>,
}
impl<'env> DynamicFunctionMut<'env> {
/// Create a new [`DynamicFunctionMut`].
///
/// The given function can be used to call out to any other callable,
/// including functions, closures, or methods.
///
/// It's important that the function signature matches the provided [`FunctionInfo`].
/// as this will be used to validate arguments when [calling] the function.
/// This is also required in order for [function overloading] to work correctly.
///
/// # Panics
///
/// This function may panic for any of the following reasons:
/// - No [`SignatureInfo`] is provided.
/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].
/// - The conversion to [`FunctionInfo`] fails.
///
/// [calling]: crate::func::dynamic_function_mut::DynamicFunctionMut::call
/// [`SignatureInfo`]: crate::func::SignatureInfo
/// [function overloading]: Self::with_overload
pub fn new<F: for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>(
func: F,
info: impl TryInto<FunctionInfo, Error: Debug>,
) -> Self {
Self {
internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),
}
}
/// Set the name of the function.
///
/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.internal = self.internal.with_name(name);
self
}
/// Add an overload to this function.
///
/// Overloads allow a single [`DynamicFunctionMut`] to represent multiple functions of different signatures.
///
/// This can be used to handle multiple monomorphizations of a generic function
/// or to allow functions with a variable number of arguments.
///
/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.
/// For example, if the existing function had the signature `(i32, i32) -> i32`,
/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,
/// the one from `F` would replace the one from the existing function.
///
/// Overloaded functions retain the [name] of the original function.
///
/// Note that it may be impossible to overload closures that mutably borrow from their environment
/// due to Rust's borrowing rules.
/// However, it's still possible to overload functions that do not capture their environment mutably,
/// or those that maintain mutually exclusive mutable references to their environment.
///
/// # Panics
///
/// Panics if the function, `F`, contains a signature already found in this function.
///
/// For a non-panicking version, see [`try_with_overload`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunctionMut;
/// let mut total_i32 = 0;
/// let mut add_i32 = |a: i32| total_i32 += a;
///
/// let mut total_f32 = 0.0;
/// let mut add_f32 = |a: f32| total_f32 += a;
///
/// // Currently, the only generic type `func` supports is `i32`.
/// let mut func = add_i32.into_function_mut();
///
/// // However, we can add an overload to handle `f32` as well:
/// func = func.with_overload(add_f32);
///
/// // Test `i32`:
/// let args = bevy_reflect::func::ArgList::new().with_owned(123_i32);
/// func.call(args).unwrap();
///
/// // Test `f32`:
/// let args = bevy_reflect::func::ArgList::new().with_owned(1.23_f32);
/// func.call(args).unwrap();
///
/// drop(func);
/// assert_eq!(total_i32, 123);
/// assert_eq!(total_f32, 1.23);
/// ```
///
/// [argument signature]: crate::func::signature::ArgumentSignature
/// [name]: Self::name
/// [`try_with_overload`]: Self::try_with_overload
pub fn with_overload<'a, F: IntoFunctionMut<'a, Marker>, Marker>(
self,
function: F,
) -> DynamicFunctionMut<'a>
where
'env: 'a,
{
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
panic!("{}", err);
})
}
/// Attempt to add an overload to this function.
///
/// If the function, `F`, contains a signature already found in this function,
/// an error will be returned along with the original function.
///
/// For a panicking version, see [`with_overload`].
///
/// [`with_overload`]: Self::with_overload
pub fn try_with_overload<F: IntoFunctionMut<'env, Marker>, Marker>(
mut self,
function: F,
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
let function = function.into_function_mut();
match self.internal.merge(function.internal) {
Ok(_) => Ok(self),
Err(err) => Err((Box::new(self), err)),
}
}
/// Call the function with the given arguments.
///
/// Variables that are captured mutably by this function
/// won't be usable until this function is dropped.
/// Consider using [`call_once`] if you want to consume the function
/// immediately after calling it.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};
/// let mut total = 0;
/// let add = |a: i32, b: i32| -> i32 {
/// total = a + b;
/// total
/// };
///
/// let mut func = add.into_function_mut().with_name("add");
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
/// ```
///
/// # Errors
///
/// This method will return an error if the number of arguments provided does not match
/// the number of arguments expected by the function's [`FunctionInfo`].
///
/// The function itself may also return any errors it needs to.
///
/// [`call_once`]: DynamicFunctionMut::call_once
pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {
self.internal.validate_args(&args)?;
let func = self.internal.get_mut(&args)?;
func(args)
}
/// Call the function with the given arguments and consume it.
///
/// This is useful for functions that capture their environment mutably
/// because otherwise any captured variables would still be borrowed by it.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};
/// let mut count = 0;
/// let increment = |amount: i32| count += amount;
///
/// let increment_function = increment.into_function_mut();
/// let args = ArgList::new().with_owned(5_i32);
///
/// // We need to drop `increment_function` here so that we
/// // can regain access to `count`.
/// // `call_once` does this automatically for us.
/// increment_function.call_once(args).unwrap();
/// assert_eq!(count, 5);
/// ```
///
/// # Errors
///
/// This method will return an error if the number of arguments provided does not match
/// the number of arguments expected by the function's [`FunctionInfo`].
///
/// The function itself may also return any errors it needs to.
pub fn call_once(mut self, args: ArgList) -> FunctionResult {
self.call(args)
}
/// Returns the function info.
pub fn info(&self) -> &FunctionInfo {
self.internal.info()
}
/// The name of the function.
///
/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// This can be overridden using [`with_name`].
///
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
/// [`with_name`]: Self::with_name
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.internal.name()
}
/// Returns `true` if the function is [overloaded].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunctionMut;
/// let mut total_i32 = 0;
/// let increment = (|value: i32| total_i32 += value).into_function_mut();
/// assert!(!increment.is_overloaded());
///
/// let mut total_f32 = 0.0;
/// let increment = increment.with_overload(|value: f32| total_f32 += value);
/// assert!(increment.is_overloaded());
/// ```
///
/// [overloaded]: Self::with_overload
pub fn is_overloaded(&self) -> bool {
self.internal.is_overloaded()
}
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::IntoFunctionMut;
/// let add = (|a: i32, b: i32| a + b).into_function_mut();
/// assert!(add.arg_count().contains(2));
///
/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);
/// assert!(add.arg_count().contains(2));
/// assert!(add.arg_count().contains(3));
/// ```
///
/// [overloaded]: Self::with_overload
pub fn arg_count(&self) -> ArgCount {
self.internal.arg_count()
}
}
/// Outputs the function's signature.
///
/// This takes the format: `DynamicFunctionMut(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.
///
/// Names for arguments and the function itself are optional and will default to `_` if not provided.
///
/// If the function is [overloaded], the output will include the signatures of all overloads as a set.
/// For example, `DynamicFunctionMut(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.
///
/// [overloaded]: DynamicFunctionMut::with_overload
impl<'env> Debug for DynamicFunctionMut<'env> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicFunctionMut({:?})", &self.internal)
}
}
impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {
#[inline]
fn from(function: DynamicFunction<'env>) -> Self {
Self {
internal: function.internal.map_functions(arc_to_box),
}
}
}
/// Helper function from converting an [`Arc`] function to a [`Box`] function.
///
/// This is needed to help the compiler infer the correct types.
fn arc_to_box<'env>(
f: Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>,
) -> BoxFnMut<'env> {
Box::new(move |args| f(args))
}
impl<'env> IntoFunctionMut<'env, ()> for DynamicFunctionMut<'env> {
#[inline]
fn into_function_mut(self) -> DynamicFunctionMut<'env> {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
use alloc::vec;
use core::ops::Add;
#[test]
fn should_overwrite_function_name() {
let mut total = 0;
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
assert!(func.name().is_none());
let func = func.with_name("my_function");
assert_eq!(func.name().unwrap(), "my_function");
}
#[test]
fn should_convert_dynamic_function_mut_with_into_function() {
fn make_closure<'env, F: IntoFunctionMut<'env, M>, M>(f: F) -> DynamicFunctionMut<'env> {
f.into_function_mut()
}
let mut total = 0;
let closure: DynamicFunctionMut = make_closure(|a: i32, b: i32| total = a + b);
let _: DynamicFunctionMut = make_closure(closure);
}
#[test]
fn should_return_error_on_arg_count_mismatch() {
let mut total = 0;
let mut func = (|a: i32, b: i32| total = a + b).into_function_mut();
let args = ArgList::default().with_owned(25_i32);
let error = func.call(args).unwrap_err();
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: ArgCount::new(2).unwrap(),
received: 1
}
);
let args = ArgList::default().with_owned(25_i32);
let error = func.call_once(args).unwrap_err();
assert_eq!(
error,
FunctionError::ArgCountMismatch {
expected: ArgCount::new(2).unwrap(),
received: 1
}
);
}
#[test]
fn should_allow_creating_manual_generic_dynamic_function_mut() {
let mut total = 0_i32;
let func = DynamicFunctionMut::new(
|mut args| {
let value = args.take_arg()?;
if value.is::<i32>() {
let value = value.take::<i32>()?;
total += value;
} else {
let value = value.take::<i16>()?;
total += value as i32;
}
Ok(().into_return())
},
vec![
SignatureInfo::named("add::<i32>").with_arg::<i32>("value"),
SignatureInfo::named("add::<i16>").with_arg::<i16>("value"),
],
);
assert_eq!(func.name().unwrap(), "add::<i32>");
let mut func = func.with_name("add");
assert_eq!(func.name().unwrap(), "add");
let args = ArgList::default().with_owned(25_i32);
func.call(args).unwrap();
let args = ArgList::default().with_owned(75_i16);
func.call(args).unwrap();
drop(func);
assert_eq!(total, 100);
}
// Closures that mutably borrow from their environment cannot realistically
// be overloaded since that would break Rust's borrowing rules.
// However, we still need to verify overloaded functions work since a
// `DynamicFunctionMut` can also be made from a non-mutably borrowing closure/function.
#[test]
fn should_allow_function_overloading() {
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let mut func = add::<i32>.into_function_mut().with_overload(add::<f32>);
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<i32>().unwrap(), 100);
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
}
}

71
vendor/bevy_reflect/src/func/error.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
use crate::func::signature::ArgumentSignature;
use crate::func::{
args::{ArgCount, ArgError},
Return,
};
use alloc::borrow::Cow;
use bevy_platform::collections::HashSet;
use thiserror::Error;
/// An error that occurs when calling a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Error, PartialEq)]
pub enum FunctionError {
/// An error occurred while converting an argument.
#[error(transparent)]
ArgError(#[from] ArgError),
/// The number of arguments provided does not match the expected number.
#[error("received {received} arguments but expected one of {expected:?}")]
ArgCountMismatch { expected: ArgCount, received: usize },
/// No overload was found for the given set of arguments.
#[error("no overload found for arguments with signature `{received:?}`, expected one of `{expected:?}`")]
NoOverload {
expected: HashSet<ArgumentSignature>,
received: ArgumentSignature,
},
}
/// The result of calling a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// Returns `Ok(value)` if the function was called successfully,
/// where `value` is the [`Return`] value of the function.
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
pub type FunctionResult<'a> = Result<Return<'a>, FunctionError>;
/// An error that occurs when attempting to add a function overload.
#[derive(Debug, Error, PartialEq)]
pub enum FunctionOverloadError {
/// A [`SignatureInfo`] was expected, but none was found.
///
/// [`SignatureInfo`]: crate::func::info::SignatureInfo
#[error("expected at least one `SignatureInfo` but found none")]
MissingSignature,
/// An error that occurs when attempting to add a function overload with a duplicate signature.
#[error("could not add function overload: duplicate found for signature `{0:?}`")]
DuplicateSignature(ArgumentSignature),
#[error(
"argument signature `{:?}` has too many arguments (max {})",
0,
ArgCount::MAX_COUNT
)]
TooManyArguments(ArgumentSignature),
}
/// An error that occurs when registering a function into a [`FunctionRegistry`].
///
/// [`FunctionRegistry`]: crate::func::FunctionRegistry
#[derive(Debug, Error, PartialEq)]
pub enum FunctionRegistrationError {
/// A function with the given name has already been registered.
///
/// Contains the duplicate function name.
#[error("a function has already been registered with name {0:?}")]
DuplicateName(Cow<'static, str>),
/// The function is missing a name by which it can be registered.
#[error("function name is missing")]
MissingName,
}

View File

@@ -0,0 +1,93 @@
use crate::{
func::{
args::{ArgCount, ArgList},
DynamicFunction, FunctionInfo, FunctionResult,
},
PartialReflect,
};
use alloc::borrow::Cow;
use core::fmt::Debug;
/// A trait used to power [function-like] operations via [reflection].
///
/// This trait allows types to be called like regular functions
/// with [`Reflect`]-based [arguments] and return values.
///
/// By default, this trait is currently only implemented for [`DynamicFunction`],
/// however, it is possible to implement this trait for custom function-like types.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{IntoFunction, ArgList, Function};
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let func: Box<dyn Function> = Box::new(add.into_function());
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
/// let value = func.reflect_call(args).unwrap().unwrap_owned();
/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
/// ```
///
/// [function-like]: crate::func
/// [reflection]: crate::Reflect
/// [`Reflect`]: crate::Reflect
/// [arguments]: crate::func::args
/// [`DynamicFunction`]: crate::func::DynamicFunction
pub trait Function: PartialReflect + Debug {
/// The name of the function, if any.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
fn name(&self) -> Option<&Cow<'static, str>>;
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// [overloaded]: crate::func#overloading-functions
fn arg_count(&self) -> ArgCount {
self.info().arg_count()
}
/// The [`FunctionInfo`] for this function.
fn info(&self) -> &FunctionInfo;
/// Call this function with the given arguments.
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
/// Clone this function into a [`DynamicFunction`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_function` instead")]
fn clone_dynamic(&self) -> DynamicFunction<'static> {
self.to_dynamic_function()
}
/// Creates a new [`DynamicFunction`] from this function.
fn to_dynamic_function(&self) -> DynamicFunction<'static>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::IntoFunction;
use alloc::boxed::Box;
#[test]
fn should_call_dyn_function() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let func: Box<dyn Function> = Box::new(add.into_function());
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let value = func.reflect_call(args).unwrap().unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 100);
}
}

841
vendor/bevy_reflect/src/func/info.rs vendored Normal file
View File

@@ -0,0 +1,841 @@
use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec};
use core::fmt::{Debug, Formatter};
use crate::{
func::args::{ArgCount, ArgCountOutOfBoundsError, ArgInfo, GetOwnership, Ownership},
func::signature::ArgumentSignature,
func::FunctionOverloadError,
type_info::impl_type_methods,
Type, TypePath,
};
use variadics_please::all_tuples;
/// Type information for a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// This information can be retrieved directly from certain functions and closures
/// using the [`TypedFunction`] trait, and manually constructed otherwise.
///
/// It is compromised of one or more [`SignatureInfo`] structs,
/// allowing it to represent functions with multiple sets of arguments (i.e. "overloaded functions").
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)]
pub struct FunctionInfo {
name: Option<Cow<'static, str>>,
arg_count: ArgCount,
signatures: Box<[SignatureInfo]>,
}
impl FunctionInfo {
/// Create a new [`FunctionInfo`] for a function with the given signature.
///
/// # Panics
///
/// Panics if the given signature has more than the maximum number of arguments
/// as specified by [`ArgCount::MAX_COUNT`].
pub fn new(signature: SignatureInfo) -> Self {
Self {
name: signature.name.clone(),
arg_count: ArgCount::new(signature.arg_count()).unwrap(),
signatures: vec![signature].into(),
}
}
/// Create a new [`FunctionInfo`] from a set of signatures.
///
/// Returns an error if the given iterator is empty or contains duplicate signatures.
pub fn try_from_iter(
signatures: impl IntoIterator<Item = SignatureInfo>,
) -> Result<Self, FunctionOverloadError> {
let mut iter = signatures.into_iter();
let base = iter.next().ok_or(FunctionOverloadError::MissingSignature)?;
if base.arg_count() > ArgCount::MAX_COUNT {
return Err(FunctionOverloadError::TooManyArguments(
ArgumentSignature::from(&base),
));
}
let mut info = Self::new(base);
for signature in iter {
if signature.arg_count() > ArgCount::MAX_COUNT {
return Err(FunctionOverloadError::TooManyArguments(
ArgumentSignature::from(&signature),
));
}
info = info.with_overload(signature).map_err(|sig| {
FunctionOverloadError::DuplicateSignature(ArgumentSignature::from(&sig))
})?;
}
Ok(info)
}
/// The base signature for this function.
///
/// All functions—including overloaded functions—are guaranteed to have at least one signature.
/// The first signature used to define the [`FunctionInfo`] is considered the base signature.
pub fn base(&self) -> &SignatureInfo {
&self.signatures[0]
}
/// Whether this function is overloaded.
///
/// This is determined by the existence of multiple signatures.
pub fn is_overloaded(&self) -> bool {
self.signatures.len() > 1
}
/// Set the name of the function.
pub fn with_name(mut self, name: Option<impl Into<Cow<'static, str>>>) -> Self {
self.name = name.map(Into::into);
self
}
/// The name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`std::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// For overloaded functions, this will be the name of the base signature,
/// unless manually overwritten using [`Self::with_name`].
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.name.as_ref()
}
/// Add a signature to this function.
///
/// If a signature with the same [`ArgumentSignature`] already exists,
/// an error is returned with the given signature.
///
/// # Panics
///
/// Panics if the given signature has more than the maximum number of arguments
/// as specified by [`ArgCount::MAX_COUNT`].
pub fn with_overload(mut self, signature: SignatureInfo) -> Result<Self, SignatureInfo> {
let is_duplicate = self.signatures.iter().any(|s| {
s.arg_count() == signature.arg_count()
&& ArgumentSignature::from(s) == ArgumentSignature::from(&signature)
});
if is_duplicate {
return Err(signature);
}
self.arg_count.add(signature.arg_count());
self.signatures = IntoIterator::into_iter(self.signatures)
.chain(Some(signature))
.collect();
Ok(self)
}
/// Returns the number of arguments the function expects.
///
/// For [overloaded] functions that can have a variable number of arguments,
/// this will contain the full set of counts for all signatures.
///
/// [overloaded]: crate::func#overloading-functions
pub fn arg_count(&self) -> ArgCount {
self.arg_count
}
/// The signatures of the function.
///
/// This is guaranteed to always contain at least one signature.
/// Overloaded functions will contain two or more.
pub fn signatures(&self) -> &[SignatureInfo] {
&self.signatures
}
/// Returns a wrapper around this info that implements [`Debug`] for pretty-printing the function.
///
/// This can be useful for more readable debugging and logging.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{FunctionInfo, TypedFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let info = add.get_function_info();
///
/// let pretty = info.pretty_printer();
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
/// ```
pub fn pretty_printer(&self) -> PrettyPrintFunctionInfo {
PrettyPrintFunctionInfo::new(self)
}
/// Extend this [`FunctionInfo`] with another without checking for duplicates.
///
/// # Panics
///
/// Panics if the given signature has more than the maximum number of arguments
/// as specified by [`ArgCount::MAX_COUNT`].
pub(super) fn extend_unchecked(&mut self, other: FunctionInfo) {
if self.name.is_none() {
self.name = other.name;
}
let signatures = core::mem::take(&mut self.signatures);
self.signatures = IntoIterator::into_iter(signatures)
.chain(IntoIterator::into_iter(other.signatures))
.collect();
self.arg_count = self
.signatures
.iter()
.fold(ArgCount::default(), |mut count, sig| {
count.add(sig.arg_count());
count
});
}
}
impl TryFrom<SignatureInfo> for FunctionInfo {
type Error = ArgCountOutOfBoundsError;
fn try_from(signature: SignatureInfo) -> Result<Self, Self::Error> {
let count = signature.arg_count();
if count > ArgCount::MAX_COUNT {
return Err(ArgCountOutOfBoundsError(count));
}
Ok(Self::new(signature))
}
}
impl TryFrom<Vec<SignatureInfo>> for FunctionInfo {
type Error = FunctionOverloadError;
fn try_from(signatures: Vec<SignatureInfo>) -> Result<Self, Self::Error> {
Self::try_from_iter(signatures)
}
}
impl<const N: usize> TryFrom<[SignatureInfo; N]> for FunctionInfo {
type Error = FunctionOverloadError;
fn try_from(signatures: [SignatureInfo; N]) -> Result<Self, Self::Error> {
Self::try_from_iter(signatures)
}
}
#[derive(Debug, Clone)]
pub struct SignatureInfo {
name: Option<Cow<'static, str>>,
args: Box<[ArgInfo]>,
return_info: ReturnInfo,
}
impl SignatureInfo {
/// Create a new [`SignatureInfo`] for a function with the given name.
pub fn named(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: Some(name.into()),
args: Box::new([]),
return_info: ReturnInfo::new::<()>(),
}
}
/// Create a new [`SignatureInfo`] with no name.
///
/// For the purposes of debugging and [registration],
/// it's recommended to use [`Self::named`] instead.
///
/// [registration]: crate::func::FunctionRegistry
pub fn anonymous() -> Self {
Self {
name: None,
args: Box::new([]),
return_info: ReturnInfo::new::<()>(),
}
}
/// Set the name of the function.
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.name = Some(name.into());
self
}
/// Push an argument onto the function's argument list.
///
/// The order in which this method is called matters as it will determine the index of the argument
/// based on the current number of arguments.
pub fn with_arg<T: TypePath + GetOwnership>(
mut self,
name: impl Into<Cow<'static, str>>,
) -> Self {
let index = self.args.len();
self.args = IntoIterator::into_iter(self.args)
.chain(Some(ArgInfo::new::<T>(index).with_name(name)))
.collect();
self
}
/// Set the arguments of the function.
///
/// This will completely replace any existing arguments.
///
/// It's preferable to use [`Self::with_arg`] to add arguments to the function
/// as it will automatically set the index of the argument.
pub fn with_args(mut self, args: Vec<ArgInfo>) -> Self {
self.args = IntoIterator::into_iter(self.args).chain(args).collect();
self
}
/// Set the [return information] of the function.
///
/// To manually set the [`ReturnInfo`] of the function, see [`Self::with_return_info`].
///
/// [return information]: ReturnInfo
pub fn with_return<T: TypePath + GetOwnership>(mut self) -> Self {
self.return_info = ReturnInfo::new::<T>();
self
}
/// Set the [return information] of the function.
///
/// This will completely replace any existing return information.
///
/// For a simpler, static version of this method, see [`Self::with_return`].
///
/// [return information]: ReturnInfo
pub fn with_return_info(mut self, return_info: ReturnInfo) -> Self {
self.return_info = return_info;
self
}
/// The name of the function.
///
/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
/// unless the function is a closure, anonymous function, or function pointer,
/// in which case the name will be `None`.
///
/// [`DynamicFunctions`]: crate::func::DynamicFunction
/// [`IntoFunction`]: crate::func::IntoFunction
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.name.as_ref()
}
/// The arguments of the function.
pub fn args(&self) -> &[ArgInfo] {
&self.args
}
/// The number of arguments the function takes.
pub fn arg_count(&self) -> usize {
self.args.len()
}
/// The return information of the function.
pub fn return_info(&self) -> &ReturnInfo {
&self.return_info
}
}
/// Information about the return type of a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)]
pub struct ReturnInfo {
ty: Type,
ownership: Ownership,
}
impl ReturnInfo {
/// Create a new [`ReturnInfo`] representing the given type, `T`.
pub fn new<T: TypePath + GetOwnership>() -> Self {
Self {
ty: Type::of::<T>(),
ownership: T::ownership(),
}
}
impl_type_methods!(ty);
/// The ownership of this type.
pub fn ownership(&self) -> Ownership {
self.ownership
}
}
/// A wrapper around [`FunctionInfo`] that implements [`Debug`] for pretty-printing function information.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintFunctionInfo, TypedFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let info = add.get_function_info();
///
/// let pretty = PrettyPrintFunctionInfo::new(&info);
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
/// ```
pub struct PrettyPrintFunctionInfo<'a> {
info: &'a FunctionInfo,
include_fn_token: bool,
include_name: bool,
}
impl<'a> PrettyPrintFunctionInfo<'a> {
/// Create a new pretty-printer for the given [`FunctionInfo`].
pub fn new(info: &'a FunctionInfo) -> Self {
Self {
info,
include_fn_token: false,
include_name: false,
}
}
/// Include the function name in the pretty-printed output.
pub fn include_name(mut self) -> Self {
self.include_name = true;
self
}
/// Include the `fn` token in the pretty-printed output.
pub fn include_fn_token(mut self) -> Self {
self.include_fn_token = true;
self
}
}
impl<'a> Debug for PrettyPrintFunctionInfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
if self.include_fn_token {
write!(f, "fn")?;
if self.include_name {
write!(f, " ")?;
}
}
match (self.include_name, self.info.name()) {
(true, Some(name)) => write!(f, "{}", name)?,
(true, None) => write!(f, "_")?,
_ => {}
}
if self.info.is_overloaded() {
// `{(arg0: i32, arg1: i32) -> (), (arg0: f32, arg1: f32) -> ()}`
let mut set = f.debug_set();
for signature in self.info.signatures() {
set.entry(&PrettyPrintSignatureInfo::new(signature));
}
set.finish()
} else {
// `(arg0: i32, arg1: i32) -> ()`
PrettyPrintSignatureInfo::new(self.info.base()).fmt(f)
}
}
}
/// A wrapper around [`SignatureInfo`] that implements [`Debug`] for pretty-printing function signature information.
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintSignatureInfo, TypedFunction};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let info = add.get_function_info();
///
/// let pretty = PrettyPrintSignatureInfo::new(info.base());
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
/// ```
pub struct PrettyPrintSignatureInfo<'a> {
info: &'a SignatureInfo,
include_fn_token: bool,
include_name: bool,
}
impl<'a> PrettyPrintSignatureInfo<'a> {
/// Create a new pretty-printer for the given [`SignatureInfo`].
pub fn new(info: &'a SignatureInfo) -> Self {
Self {
info,
include_fn_token: false,
include_name: false,
}
}
/// Include the function name in the pretty-printed output.
pub fn include_name(mut self) -> Self {
self.include_name = true;
self
}
/// Include the `fn` token in the pretty-printed output.
pub fn include_fn_token(mut self) -> Self {
self.include_fn_token = true;
self
}
}
impl<'a> Debug for PrettyPrintSignatureInfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
if self.include_fn_token {
write!(f, "fn")?;
if self.include_name {
write!(f, " ")?;
}
}
match (self.include_name, self.info.name()) {
(true, Some(name)) => write!(f, "{}", name)?,
(true, None) => write!(f, "_")?,
_ => {}
}
write!(f, "(")?;
// We manually write the args instead of using `DebugTuple` to avoid trailing commas
// and (when used with `{:#?}`) unnecessary newlines
for (index, arg) in self.info.args().iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
let name = arg.name().unwrap_or("_");
let ty = arg.type_path();
write!(f, "{name}: {ty}")?;
}
let ret = self.info.return_info().type_path();
write!(f, ") -> {ret}")
}
}
/// A static accessor to compile-time type information for functions.
///
/// This is the equivalent of [`Typed`], but for function.
///
/// # Blanket Implementation
///
/// This trait has a blanket implementation that covers:
/// - Functions and methods defined with the `fn` keyword
/// - Anonymous functions
/// - Function pointers
/// - Closures that capture immutable references to their environment
/// - Closures that capture mutable references to their environment
/// - Closures that take ownership of captured variables
///
/// For each of the above cases, the function signature may only have up to 15 arguments,
/// not including an optional receiver argument (often `&self` or `&mut self`).
/// This optional receiver argument may be either a mutable or immutable reference to a type.
/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
///
/// See the [module-level documentation] for more information on valid signatures.
///
/// Arguments and the return type are expected to implement both [`GetOwnership`] and [`TypePath`].
/// By default, these traits are automatically implemented when using the `Reflect` [derive macro].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgList, ReflectFnMut, TypedFunction};
/// #
/// fn print(value: String) {
/// println!("{}", value);
/// }
///
/// let info = print.get_function_info();
/// assert!(info.name().unwrap().ends_with("print"));
/// assert!(info.arg_count().contains(1));
/// assert_eq!(info.base().args()[0].type_path(), "alloc::string::String");
/// assert_eq!(info.base().return_info().type_path(), "()");
/// ```
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// [module-level documentation]: crate::func
/// [`Typed`]: crate::Typed
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait TypedFunction<Marker> {
/// Get the [`FunctionInfo`] for this type.
fn function_info() -> FunctionInfo;
/// Get the [`FunctionInfo`] for this type.
fn get_function_info(&self) -> FunctionInfo {
Self::function_info()
}
}
/// Helper macro for implementing [`TypedFunction`] on Rust functions.
///
/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
/// - `FnMut(arg0, arg1, ..., argN) -> R`
/// - `FnMut(&Receiver, arg0, arg1, ..., argN) -> &R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &R`
macro_rules! impl_typed_function {
($(($Arg:ident, $arg:ident)),*) => {
// === (...) -> ReturnType === //
impl<$($Arg,)* ReturnType, Function> TypedFunction<fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: TypePath + GetOwnership,)*
ReturnType: TypePath + GetOwnership,
Function: FnMut($($Arg),*) -> ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 0;
vec![
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<ReturnType>())
)
}
}
// === (&self, ...) -> &ReturnType === //
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
for<'a> &'a Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&Receiver>(0),
$($crate::func::args::ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&ReturnType>())
)
}
}
// === (&mut self, ...) -> &mut ReturnType === //
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
for<'a> &'a mut Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a mut ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&mut Receiver>(0),
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&mut ReturnType>())
)
}
}
// === (&mut self, ...) -> &ReturnType === //
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
for<'a> &'a mut Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&mut Receiver>(0),
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&ReturnType>())
)
}
}
};
}
all_tuples!(impl_typed_function, 0, 15, Arg, arg);
/// Helper function for creating [`FunctionInfo`] with the proper name value.
///
/// Names are only given if:
/// - The function is not a closure
/// - The function is not a function pointer
/// - The function is not an anonymous function
///
/// This function relies on the [`type_name`] of `F` to determine this.
/// The following table describes the behavior for different types of functions:
///
/// | Category | `type_name` | `FunctionInfo::name` |
/// | ------------------ | ----------------------- | ----------------------- |
/// | Named function | `foo::bar::baz` | `Some("foo::bar::baz")` |
/// | Closure | `foo::bar::{{closure}}` | `None` |
/// | Anonymous function | `foo::bar::{{closure}}` | `None` |
/// | Function pointer | `fn() -> String` | `None` |
///
/// [`type_name`]: core::any::type_name
fn create_info<F>() -> SignatureInfo {
let name = core::any::type_name::<F>();
if name.ends_with("{{closure}}") || name.starts_with("fn(") {
SignatureInfo::anonymous()
} else {
SignatureInfo::named(name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_create_function_info() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
// Sanity check:
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_function_info::add"
);
let info = add.get_function_info();
assert_eq!(
info.name().unwrap(),
"bevy_reflect::func::info::tests::should_create_function_info::add"
);
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "i32");
}
#[test]
fn should_create_function_pointer_info() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let add = add as fn(i32, i32) -> i32;
// Sanity check:
assert_eq!(core::any::type_name_of_val(&add), "fn(i32, i32) -> i32");
let info = add.get_function_info();
assert!(info.name().is_none());
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "i32");
}
#[test]
fn should_create_anonymous_function_info() {
let add = |a: i32, b: i32| a + b;
// Sanity check:
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_anonymous_function_info::{{closure}}"
);
let info = add.get_function_info();
assert!(info.name().is_none());
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "i32");
}
#[test]
fn should_create_closure_info() {
let mut total = 0;
let add = |a: i32, b: i32| total = a + b;
// Sanity check:
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_closure_info::{{closure}}"
);
let info = add.get_function_info();
assert!(info.name().is_none());
assert_eq!(info.base().arg_count(), 2);
assert_eq!(info.base().args()[0].type_path(), "i32");
assert_eq!(info.base().args()[1].type_path(), "i32");
assert_eq!(info.base().return_info().type_path(), "()");
}
#[test]
fn should_pretty_print_info() {
// fn add(a: i32, b: i32) -> i32 {
// a + b
// }
//
// let info = add.get_function_info().with_name("add");
//
// let pretty = info.pretty_printer();
// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
//
// let pretty = info.pretty_printer().include_fn_token();
// assert_eq!(format!("{:?}", pretty), "fn(_: i32, _: i32) -> i32");
//
// let pretty = info.pretty_printer().include_name();
// assert_eq!(format!("{:?}", pretty), "add(_: i32, _: i32) -> i32");
//
// let pretty = info.pretty_printer().include_fn_token().include_name();
// assert_eq!(format!("{:?}", pretty), "fn add(_: i32, _: i32) -> i32");
}
}

View File

@@ -0,0 +1,68 @@
use crate::func::{DynamicFunction, ReflectFn, TypedFunction};
/// A trait for types that can be converted into a [`DynamicFunction`].
///
/// This trait is automatically implemented for any type that implements
/// [`ReflectFn`] and [`TypedFunction`].
///
/// See the [module-level documentation] for more information.
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [module-level documentation]: crate::func
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait IntoFunction<'env, Marker> {
/// Converts [`Self`] into a [`DynamicFunction`].
fn into_function(self) -> DynamicFunction<'env>;
}
impl<'env, F, Marker1, Marker2> IntoFunction<'env, (Marker1, Marker2)> for F
where
F: ReflectFn<'env, Marker1> + TypedFunction<Marker2> + Send + Sync + 'env,
{
fn into_function(self) -> DynamicFunction<'env> {
DynamicFunction::new(move |args| self.reflect_call(args), Self::function_info())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::ArgList;
#[test]
fn should_create_dynamic_function_from_closure() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_create_dynamic_function_from_function() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let func = add.into_function();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
fn should_default_closure_name_to_none() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
assert!(func.name().is_none());
}
}

View File

@@ -0,0 +1,83 @@
use crate::func::{DynamicFunctionMut, ReflectFnMut, TypedFunction};
/// A trait for types that can be converted into a [`DynamicFunctionMut`].
///
/// This trait is automatically implemented for any type that implements
/// [`ReflectFnMut`] and [`TypedFunction`].
///
/// This trait can be seen as a superset of [`IntoFunction`].
///
/// See the [module-level documentation] for more information.
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [`IntoFunction`]: crate::func::IntoFunction
/// [module-level documentation]: crate::func
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait IntoFunctionMut<'env, Marker> {
/// Converts [`Self`] into a [`DynamicFunctionMut`].
fn into_function_mut(self) -> DynamicFunctionMut<'env>;
}
impl<'env, F, Marker1, Marker2> IntoFunctionMut<'env, (Marker1, Marker2)> for F
where
F: ReflectFnMut<'env, Marker1> + TypedFunction<Marker2> + 'env,
{
fn into_function_mut(mut self) -> DynamicFunctionMut<'env> {
DynamicFunctionMut::new(
move |args| self.reflect_call_mut(args),
Self::function_info(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{ArgList, IntoFunction};
#[test]
fn should_create_dynamic_function_mut_from_closure() {
let c = 23;
let func = (|a: i32, b: i32| a + b + c).into_function();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_create_dynamic_function_mut_from_closure_with_mutable_capture() {
let mut total = 0;
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
func.call_once(args).unwrap();
assert_eq!(total, 100);
}
#[test]
fn should_create_dynamic_function_mut_from_function() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let mut func = add.into_function_mut();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
fn should_default_closure_name_to_none() {
let mut total = 0;
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
assert!(func.name().is_none());
}
}

112
vendor/bevy_reflect/src/func/macros.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
/// Helper macro to implement the necessary traits for function reflection.
///
/// This macro calls the following macros:
/// - [`impl_get_ownership`](crate::func::args::impl_get_ownership)
/// - [`impl_from_arg`](crate::func::args::impl_from_arg)
/// - [`impl_into_return`](crate::func::impl_into_return)
///
/// # Syntax
///
/// For non-generic types, the macro simply expects the type:
///
/// ```ignore
/// impl_function_traits!(foo::bar::Baz);
/// ```
///
/// For generic types, however, the generic type parameters must also be given in angle brackets (`<` and `>`):
///
/// ```ignore
/// impl_function_traits!(foo::bar::Baz<T, U>; <T: Clone, U>);
/// ```
///
/// For generic const parameters, they must be given in square brackets (`[` and `]`):
///
/// ```ignore
/// impl_function_traits!(foo::bar::Baz<T, N>; <T> [const N: usize]);
/// ```
macro_rules! impl_function_traits {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
$crate::func::args::impl_get_ownership!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
)?
$(
[
$(const $N : $size),*
]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
);
$crate::func::args::impl_from_arg!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
)?
$(
[
$(const $N : $size),*
]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
);
$crate::func::impl_into_return!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
)?
$(
[
$(const $N : $size),*
]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
);
};
}
pub(crate) use impl_function_traits;
/// Helper macro that returns the number of tokens it receives.
///
/// See [here] for details.
///
/// [here]: https://veykril.github.io/tlborm/decl-macros/building-blocks/counting.html#bit-twiddling
macro_rules! count_tokens {
() => { 0 };
($odd:tt $($a:tt $b:tt)*) => { ($crate::func::macros::count_tokens!($($a)*) << 1) | 1 };
($($a:tt $even:tt)*) => { $crate::func::macros::count_tokens!($($a)*) << 1 };
}
pub(crate) use count_tokens;

266
vendor/bevy_reflect/src/func/mod.rs vendored Normal file
View File

@@ -0,0 +1,266 @@
//! Reflection-based dynamic functions.
//!
//! This module provides a way to pass around and call functions dynamically
//! using the [`DynamicFunction`] and [`DynamicFunctionMut`] types.
//!
//! Many simple functions and closures can be automatically converted to these types
//! using the [`IntoFunction`] and [`IntoFunctionMut`] traits, respectively.
//!
//! Once this dynamic representation is created, it can be called with a set of arguments provided
//! via an [`ArgList`].
//!
//! This returns a [`FunctionResult`] containing the [`Return`] value,
//! which can be used to extract a [`PartialReflect`] trait object.
//!
//! # Example
//!
//! ```
//! # use bevy_reflect::PartialReflect;
//! # use bevy_reflect::func::args::ArgList;
//! # use bevy_reflect::func::{DynamicFunction, FunctionResult, IntoFunction, Return};
//! fn add(a: i32, b: i32) -> i32 {
//! a + b
//! }
//!
//! let mut func: DynamicFunction = add.into_function();
//! let args: ArgList = ArgList::default()
//! // Pushing a known type with owned ownership
//! .with_owned(25_i32)
//! // Pushing a reflected type with owned ownership
//! .with_boxed(Box::new(75_i32) as Box<dyn PartialReflect>);
//! let result: FunctionResult = func.call(args);
//! let value: Return = result.unwrap();
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&100));
//! ```
//!
//! # Types of Functions
//!
//! For simplicity, this module uses the umbrella term "function" to refer to any Rust callable:
//! code that can be invoked with a set of arguments to perform some action.
//!
//! In Rust, there are two main categories of callables: functions and closures.
//!
//! A "function" is a callable that does not capture its environment.
//! These are typically defined with the `fn` keyword, which are referred to as _named_ functions.
//! But they are also _anonymous_ functions, which are unnamed and defined with anonymous function syntax.
//!
//! ```rust
//! // This is a named function:
//! fn add(a: i32, b: i32) -> i32 {
//! a + b
//! }
//!
//! // This is an anonymous function:
//! let add = |a: i32, b: i32| a + b;
//! ```
//!
//! Closures, on the other hand, are special functions that do capture their environment.
//! These are always defined with anonymous function syntax.
//!
//! ```
//! // A closure that captures an immutable reference to a variable
//! let c = 123;
//! let add = |a: i32, b: i32| a + b + c;
//!
//! // A closure that captures a mutable reference to a variable
//! let mut total = 0;
//! let add = |a: i32, b: i32| total += a + b;
//!
//! // A closure that takes ownership of its captured variables by moving them
//! let c = 123;
//! let add = move |a: i32, b: i32| a + b + c;
//! ```
//!
//! # Valid Signatures
//!
//! Many of the traits in this module have default blanket implementations over a specific set of function signatures.
//!
//! These signatures are:
//! - `(...) -> R`
//! - `for<'a> (&'a arg, ...) -> &'a R`
//! - `for<'a> (&'a mut arg, ...) -> &'a R`
//! - `for<'a> (&'a mut arg, ...) -> &'a mut R`
//!
//! Where `...` represents 0 to 15 arguments (inclusive) of the form `T`, `&T`, or `&mut T`.
//! The lifetime of any reference to the return type `R`, must be tied to a "receiver" argument
//! (i.e. the first argument in the signature, normally `self`).
//!
//! Each trait will also have its own requirements for what traits are required for both arguments and return types,
//! but a good rule-of-thumb is that all types should derive [`Reflect`].
//!
//! The reason for such a small subset of valid signatures is due to limitations in Rust—
//! namely the [lack of variadic generics] and certain [coherence issues].
//!
//! For other functions that don't conform to one of the above signatures,
//! [`DynamicFunction`] and [`DynamicFunctionMut`] can instead be created manually.
//!
//! # Generic Functions
//!
//! In Rust, generic functions are [monomorphized] by the compiler,
//! which means that a separate copy of the function is generated for each concrete set of type parameters.
//!
//! When converting a generic function to a [`DynamicFunction`] or [`DynamicFunctionMut`],
//! the function must be manually monomorphized with concrete types.
//! In other words, you cannot write `add<T>.into_function()`.
//! Instead, you will need to write `add::<i32>.into_function()`.
//!
//! This means that reflected functions cannot be generic themselves.
//! To get around this limitation, you can consider [overloading] your function with multiple concrete types.
//!
//! # Overloading Functions
//!
//! Both [`DynamicFunction`] and [`DynamicFunctionMut`] support [function overloading].
//!
//! Function overloading allows one function to handle multiple types of arguments.
//! This is useful for simulating generic functions by having an overload for each known concrete type.
//! Additionally, it can also simulate [variadic functions]: functions that can be called with a variable number of arguments.
//!
//! Internally, this works by storing multiple functions in a map,
//! where each function is associated with a specific argument signature.
//!
//! To learn more, see the docs on [`DynamicFunction::with_overload`].
//!
//! # Function Registration
//!
//! This module also provides a [`FunctionRegistry`] that can be used to register functions and closures
//! by name so that they may be retrieved and called dynamically.
//!
//! ```
//! # use bevy_reflect::func::{ArgList, FunctionRegistry};
//! fn add(a: i32, b: i32) -> i32 {
//! a + b
//! }
//!
//! let mut registry = FunctionRegistry::default();
//!
//! // You can register functions and methods by their `core::any::type_name`:
//! registry.register(add).unwrap();
//!
//! // Or you can register them by a custom name:
//! registry.register_with_name("mul", |a: i32, b: i32| a * b).unwrap();
//!
//! // You can then retrieve and call these functions by name:
//! let reflect_add = registry.get(core::any::type_name_of_val(&add)).unwrap();
//! let value = reflect_add.call(ArgList::default().with_owned(10_i32).with_owned(5_i32)).unwrap();
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&15));
//!
//! let reflect_mul = registry.get("mul").unwrap();
//! let value = reflect_mul.call(ArgList::default().with_owned(10_i32).with_owned(5_i32)).unwrap();
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&50));
//! ```
//!
//! [`PartialReflect`]: crate::PartialReflect
//! [`Reflect`]: crate::Reflect
//! [lack of variadic generics]: https://poignardazur.github.io/2024/05/25/report-on-rustnl-variadics/
//! [coherence issues]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#coherence-leak-check
//! [monomorphized]: https://en.wikipedia.org/wiki/Monomorphization
//! [overloading]: #overloading-functions
//! [function overloading]: https://en.wikipedia.org/wiki/Function_overloading
//! [variadic functions]: https://en.wikipedia.org/wiki/Variadic_function
pub use args::{ArgError, ArgList, ArgValue};
pub use dynamic_function::*;
pub use dynamic_function_mut::*;
pub use error::*;
pub use function::*;
pub use info::*;
pub use into_function::*;
pub use into_function_mut::*;
pub use reflect_fn::*;
pub use reflect_fn_mut::*;
pub use registry::*;
pub use return_type::*;
pub mod args;
mod dynamic_function;
mod dynamic_function_internal;
mod dynamic_function_mut;
mod error;
mod function;
mod info;
mod into_function;
mod into_function_mut;
pub(crate) mod macros;
mod reflect_fn;
mod reflect_fn_mut;
mod registry;
mod return_type;
pub mod signature;
#[cfg(test)]
mod tests {
use alloc::borrow::Cow;
use super::*;
use crate::func::args::ArgCount;
use crate::{
func::args::{ArgError, ArgList, Ownership},
TypePath,
};
#[test]
fn should_error_on_missing_args() {
fn foo(_: i32) {}
let func = foo.into_function();
let args = ArgList::new();
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgCountMismatch {
expected: ArgCount::new(1).unwrap(),
received: 0
}
);
}
#[test]
fn should_error_on_too_many_args() {
fn foo() {}
let func = foo.into_function();
let args = ArgList::new().with_owned(123_i32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgCountMismatch {
expected: ArgCount::new(0).unwrap(),
received: 1
}
);
}
#[test]
fn should_error_on_invalid_arg_type() {
fn foo(_: i32) {}
let func = foo.into_function();
let args = ArgList::new().with_owned(123_u32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgError(ArgError::UnexpectedType {
index: 0,
expected: Cow::Borrowed(i32::type_path()),
received: Cow::Borrowed(u32::type_path())
})
);
}
#[test]
fn should_error_on_invalid_arg_ownership() {
fn foo(_: &i32) {}
let func = foo.into_function();
let args = ArgList::new().with_owned(123_i32);
let result = func.call(args);
assert_eq!(
result.unwrap_err(),
FunctionError::ArgError(ArgError::InvalidOwnership {
index: 0,
expected: Ownership::Ref,
received: Ownership::Owned
})
);
}
}

View File

@@ -0,0 +1,208 @@
use variadics_please::all_tuples;
use crate::{
func::{
args::{ArgCount, FromArg},
macros::count_tokens,
ArgList, FunctionError, FunctionResult, IntoReturn, ReflectFnMut,
},
Reflect, TypePath,
};
/// A reflection-based version of the [`Fn`] trait.
///
/// This allows functions to be called dynamically through [reflection].
///
/// # Blanket Implementation
///
/// This trait has a blanket implementation that covers:
/// - Functions and methods defined with the `fn` keyword
/// - Anonymous functions
/// - Function pointers
/// - Closures that capture immutable references to their environment
/// - Closures that take ownership of captured variables
///
/// For each of the above cases, the function signature may only have up to 15 arguments,
/// not including an optional receiver argument (often `&self` or `&mut self`).
/// This optional receiver argument may be either a mutable or immutable reference to a type.
/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
///
/// See the [module-level documentation] for more information on valid signatures.
///
/// To handle functions that capture mutable references to their environment,
/// see the [`ReflectFnMut`] trait instead.
///
/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].
/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFn};
/// #
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
///
/// let value = add.reflect_call(args).unwrap().unwrap_owned();
/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
/// ```
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [reflection]: crate
/// [module-level documentation]: crate::func
/// [derive macro]: derive@crate::Reflect
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait ReflectFn<'env, Marker>: ReflectFnMut<'env, Marker> {
/// Call the function with the given arguments and return the result.
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
}
/// Helper macro for implementing [`ReflectFn`] on Rust functions.
///
/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
/// - `Fn(arg0, arg1, ..., argN) -> R`
/// - `Fn(&Receiver, arg0, arg1, ..., argN) -> &R`
/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &R`
macro_rules! impl_reflect_fn {
($(($Arg:ident, $arg:ident)),*) => {
// === (...) -> ReturnType === //
impl<'env, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: FromArg,)*
// This clause allows us to convert `ReturnType` into `Return`
ReturnType: IntoReturn + Reflect,
Function: Fn($($Arg),*) -> ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn($($Arg::This<'a>),*) -> ReturnType + 'env,
{
#[expect(
clippy::allow_attributes,
reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."
)]
#[allow(
unused_mut,
reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."
)]
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!($($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)($($arg,)*).into_return())
}
}
// === (&self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> Fn(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_ref::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &mut ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&mut ReturnType` into `Return`
for<'a> &'a mut ReturnType: IntoReturn,
Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
};
}
all_tuples!(impl_reflect_fn, 0, 15, Arg, arg);

View File

@@ -0,0 +1,215 @@
use variadics_please::all_tuples;
use crate::{
func::{
args::{ArgCount, FromArg},
macros::count_tokens,
ArgList, FunctionError, FunctionResult, IntoReturn,
},
Reflect, TypePath,
};
/// A reflection-based version of the [`FnMut`] trait.
///
/// This allows functions to be called dynamically through [reflection].
///
/// This is a supertrait of [`ReflectFn`], and is used for functions that may mutate their environment,
/// such as closures that capture mutable references.
///
/// # Blanket Implementation
///
/// This trait has a blanket implementation that covers everything that [`ReflectFn`] does:
/// - Functions and methods defined with the `fn` keyword
/// - Anonymous functions
/// - Function pointers
/// - Closures that capture immutable references to their environment
/// - Closures that take ownership of captured variables
///
/// But also allows for:
/// - Closures that capture mutable references to their environment
///
/// For each of the above cases, the function signature may only have up to 15 arguments,
/// not including an optional receiver argument (often `&self` or `&mut self`).
/// This optional receiver argument may be either a mutable or immutable reference to a type.
/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
///
/// See the [module-level documentation] for more information on valid signatures.
///
/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].
/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].
///
/// # Example
///
/// ```
/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFnMut};
/// #
/// let mut list: Vec<i32> = vec![1, 3];
///
/// // `insert` is a closure that captures a mutable reference to `list`
/// let mut insert = |index: usize, value: i32| {
/// list.insert(index, value);
/// };
///
/// let args = ArgList::new().with_owned(1_usize).with_owned(2_i32);
///
/// insert.reflect_call_mut(args).unwrap();
/// assert_eq!(list, vec![1, 2, 3]);
/// ```
///
/// # Trait Parameters
///
/// This trait has a `Marker` type parameter that is used to get around issues with
/// [unconstrained type parameters] when defining impls with generic arguments or return types.
/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
///
/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
/// For named functions and some closures, this will end up just being `'static`,
/// however, closures that borrow from their environment will have a lifetime bound to that environment.
///
/// [reflection]: crate
/// [`ReflectFn`]: crate::func::ReflectFn
/// [module-level documentation]: crate::func
/// [derive macro]: derive@crate::Reflect
/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
pub trait ReflectFnMut<'env, Marker> {
/// Call the function with the given arguments and return the result.
fn reflect_call_mut<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a>;
}
/// Helper macro for implementing [`ReflectFnMut`] on Rust functions.
///
/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
/// - `FnMut(arg0, arg1, ..., argN) -> R`
/// - `FnMut(&Receiver, arg0, arg1, ..., argN) -> &R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &R`
macro_rules! impl_reflect_fn_mut {
($(($Arg:ident, $arg:ident)),*) => {
// === (...) -> ReturnType === //
impl<'env, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: FromArg,)*
// This clause allows us to convert `ReturnType` into `Return`
ReturnType: IntoReturn + Reflect,
Function: FnMut($($Arg),*) -> ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut($($Arg::This<'a>),*) -> ReturnType + 'env,
{
#[expect(
clippy::allow_attributes,
reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."
)]
#[allow(
unused_mut,
reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."
)]
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!($($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)($($arg,)*).into_return())
}
}
// === (&self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_ref::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &mut ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&mut ReturnType` into `Return`
for<'a> &'a mut ReturnType: IntoReturn,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,
{
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
// === (&mut self, ...) -> &ReturnType === //
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
// This clause allows us to convert `&ReturnType` into `Return`
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,
// This clause essentially asserts that `Arg::This` is the same type as `Arg`
Function: for<'a> FnMut(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
// Extract all arguments (in order)
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
};
}
all_tuples!(impl_reflect_fn_mut, 0, 15, Arg, arg);

526
vendor/bevy_reflect/src/func/registry.rs vendored Normal file
View File

@@ -0,0 +1,526 @@
use alloc::borrow::Cow;
use bevy_platform::{
collections::HashMap,
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use core::fmt::Debug;
use crate::func::{
ArgList, DynamicFunction, FunctionRegistrationError, FunctionResult, IntoFunction,
};
/// A registry of [reflected functions].
///
/// This is the function-equivalent to the [`TypeRegistry`].
///
/// All functions must be `'static` as they are stored as [`DynamicFunction<'static>`].
///
/// [reflected functions]: crate::func
/// [`TypeRegistry`]: crate::TypeRegistry
#[derive(Default)]
pub struct FunctionRegistry {
/// Maps function [names] to their respective [`DynamicFunctions`].
///
/// [names]: DynamicFunction::name
/// [`DynamicFunctions`]: DynamicFunction
functions: HashMap<Cow<'static, str>, DynamicFunction<'static>>,
}
impl FunctionRegistry {
/// Attempts to register the given function.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// and mapped according to its [name].
///
/// Because the function must have a name,
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
/// be registered using [`register_with_name`] or manually converted to a [`DynamicFunction`]
/// and named using [`DynamicFunction::with_name`].
/// Failure to do so will result in an error being returned.
///
/// If a registered function with the same name already exists,
/// it will not be registered again and an error will be returned.
/// To register the function anyway, overwriting any existing registration,
/// use [`overwrite_registration`] instead.
///
/// # Examples
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry};
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// # fn main() -> Result<(), FunctionRegistrationError> {
/// let mut registry = FunctionRegistry::default();
/// registry.register(add)?;
/// # Ok(())
/// # }
/// ```
///
/// Functions cannot be registered more than once.
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry, IntoFunction};
/// fn add(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let mut registry = FunctionRegistry::default();
/// registry.register(add).unwrap();
///
/// let result = registry.register(add);
/// assert!(matches!(result, Err(FunctionRegistrationError::DuplicateName(_))));
///
/// // Note that this simply relies on the name of the function to determine uniqueness.
/// // You can rename the function to register a separate instance of it.
/// let result = registry.register(add.into_function().with_name("add2"));
/// assert!(result.is_ok());
/// ```
///
/// Anonymous functions and closures should be registered using [`register_with_name`] or given a name using [`DynamicFunction::with_name`].
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry, IntoFunction};
///
/// let anonymous = || -> i32 { 123 };
///
/// let mut registry = FunctionRegistry::default();
///
/// let result = registry.register(|a: i32, b: i32| a + b);
/// assert!(matches!(result, Err(FunctionRegistrationError::MissingName)));
///
/// let result = registry.register_with_name("my_crate::add", |a: i32, b: i32| a + b);
/// assert!(result.is_ok());
///
/// let result = registry.register((|a: i32, b: i32| a * b).into_function().with_name("my_crate::mul"));
/// assert!(result.is_ok());
/// ```
///
/// [name]: DynamicFunction::name
/// [`register_with_name`]: Self::register_with_name
/// [`overwrite_registration`]: Self::overwrite_registration
pub fn register<F, Marker>(
&mut self,
function: F,
) -> Result<&mut Self, FunctionRegistrationError>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function();
let name = function
.name()
.ok_or(FunctionRegistrationError::MissingName)?
.clone();
self.functions
.try_insert(name, function.into_function())
.map_err(|err| FunctionRegistrationError::DuplicateName(err.entry.key().clone()))?;
Ok(self)
}
/// Attempts to register the given function with the given name.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// with its [name] set to the given name.
///
/// For named functions (e.g. `fn add(a: i32, b: i32) -> i32 { a + b }`) where a custom name is not needed,
/// it's recommended to use [`register`] instead as the generated name is guaranteed to be unique.
///
/// If a registered function with the same name already exists,
/// it will not be registered again and an error will be returned.
/// To register the function anyway, overwriting any existing registration,
/// use [`overwrite_registration_with_name`] instead.
///
/// To avoid conflicts, it's recommended to use a unique name for the function.
/// This can be achieved by "namespacing" the function with a unique identifier,
/// such as the name of your crate.
///
/// For example, to register a function, `add`, from a crate, `my_crate`,
/// you could use the name, `"my_crate::add"`.
///
/// Another approach could be to use the [type name] of the function,
/// however, it should be noted that anonymous functions and closures
/// are not guaranteed to have unique type names.
///
/// This method is a convenience around calling [`IntoFunction::into_function`] and [`DynamicFunction::with_name`]
/// on the function and inserting it into the registry using the [`register`] method.
///
/// # Examples
///
/// ```
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry};
/// # fn main() -> Result<(), FunctionRegistrationError> {
/// fn mul(a: i32, b: i32) -> i32 {
/// a * b
/// }
///
/// let div = |a: i32, b: i32| a / b;
///
/// let mut registry = FunctionRegistry::default();
/// registry
/// // Registering an anonymous function with a unique name
/// .register_with_name("my_crate::add", |a: i32, b: i32| {
/// a + b
/// })?
/// // Registering an existing function with its type name
/// .register_with_name(core::any::type_name_of_val(&mul), mul)?
/// // Registering an existing function with a custom name
/// .register_with_name("my_crate::mul", mul)?;
///
/// // Be careful not to register anonymous functions with their type name.
/// // This code works but registers the function with a non-unique name like `foo::bar::{{closure}}`
/// registry.register_with_name(core::any::type_name_of_val(&div), div)?;
/// # Ok(())
/// # }
/// ```
///
/// Names must be unique.
///
/// ```should_panic
/// # use bevy_reflect::func::FunctionRegistry;
/// fn one() {}
/// fn two() {}
///
/// let mut registry = FunctionRegistry::default();
/// registry.register_with_name("my_function", one).unwrap();
///
/// // Panic! A function has already been registered with the name "my_function"
/// registry.register_with_name("my_function", two).unwrap();
/// ```
///
/// [name]: DynamicFunction::name
/// [`register`]: Self::register
/// [`overwrite_registration_with_name`]: Self::overwrite_registration_with_name
/// [type name]: core::any::type_name
pub fn register_with_name<F, Marker>(
&mut self,
name: impl Into<Cow<'static, str>>,
function: F,
) -> Result<&mut Self, FunctionRegistrationError>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function().with_name(name);
self.register(function)
}
/// Registers the given function, overwriting any existing registration.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// and mapped according to its [name].
///
/// Because the function must have a name,
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
/// be registered using [`overwrite_registration_with_name`] or manually converted to a [`DynamicFunction`]
/// and named using [`DynamicFunction::with_name`].
/// Failure to do so will result in an error being returned.
///
/// To avoid overwriting existing registrations,
/// it's recommended to use the [`register`] method instead.
///
/// Returns the previous function with the same name, if any.
///
/// [name]: DynamicFunction::name
/// [`overwrite_registration_with_name`]: Self::overwrite_registration_with_name
/// [`register`]: Self::register
pub fn overwrite_registration<F, Marker>(
&mut self,
function: F,
) -> Result<Option<DynamicFunction<'static>>, FunctionRegistrationError>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function();
let name = function
.name()
.ok_or(FunctionRegistrationError::MissingName)?
.clone();
Ok(self.functions.insert(name, function))
}
/// Registers the given function, overwriting any existing registration.
///
/// This function accepts both functions that satisfy [`IntoFunction`]
/// and direct [`DynamicFunction`] instances.
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
/// with its [name] set to the given name.
///
/// Functions are mapped according to their name.
/// To avoid overwriting existing registrations,
/// it's recommended to use the [`register_with_name`] method instead.
///
/// This method is a convenience around calling [`IntoFunction::into_function`] and [`DynamicFunction::with_name`]
/// on the function and inserting it into the registry using the [`overwrite_registration`] method.
///
/// Returns the previous function with the same name, if any.
///
/// [name]: DynamicFunction::name
/// [`register_with_name`]: Self::register_with_name
/// [`overwrite_registration`]: Self::overwrite_registration
pub fn overwrite_registration_with_name<F, Marker>(
&mut self,
name: impl Into<Cow<'static, str>>,
function: F,
) -> Option<DynamicFunction<'static>>
where
F: IntoFunction<'static, Marker> + 'static,
{
let function = function.into_function().with_name(name);
match self.overwrite_registration(function) {
Ok(existing) => existing,
Err(FunctionRegistrationError::MissingName) => {
unreachable!("the function should have a name")
}
Err(FunctionRegistrationError::DuplicateName(_)) => {
unreachable!("should overwrite functions with the same name")
}
}
}
/// Calls the function with the given [name] and [args].
///
/// Returns `None` if no function with the given name is registered.
/// Otherwise, returns the result of the function call.
///
/// [name]: DynamicFunction::name
/// [args]: ArgList
pub fn call<'a>(&self, name: &str, args: ArgList<'a>) -> Option<FunctionResult<'a>> {
let func = self.get(name)?;
Some(func.call(args))
}
/// Get a reference to a registered function by [name].
///
/// [name]: DynamicFunction::name
pub fn get(&self, name: &str) -> Option<&DynamicFunction<'static>> {
self.functions.get(name)
}
/// Returns `true` if a function with the given [name] is registered.
///
/// [name]: DynamicFunction::name
pub fn contains(&self, name: &str) -> bool {
self.functions.contains_key(name)
}
/// Returns an iterator over all registered functions.
pub fn iter(&self) -> impl ExactSizeIterator<Item = &DynamicFunction<'static>> {
self.functions.values()
}
/// Returns the number of registered functions.
pub fn len(&self) -> usize {
self.functions.len()
}
/// Returns `true` if no functions are registered.
pub fn is_empty(&self) -> bool {
self.functions.is_empty()
}
}
impl Debug for FunctionRegistry {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.functions.values()).finish()
}
}
/// A synchronized wrapper around a [`FunctionRegistry`].
#[derive(Clone, Default, Debug)]
pub struct FunctionRegistryArc {
pub internal: Arc<RwLock<FunctionRegistry>>,
}
impl FunctionRegistryArc {
/// Takes a read lock on the underlying [`FunctionRegistry`].
pub fn read(&self) -> RwLockReadGuard<'_, FunctionRegistry> {
self.internal.read().unwrap_or_else(PoisonError::into_inner)
}
/// Takes a write lock on the underlying [`FunctionRegistry`].
pub fn write(&self) -> RwLockWriteGuard<'_, FunctionRegistry> {
self.internal
.write()
.unwrap_or_else(PoisonError::into_inner)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::{ArgList, IntoFunction};
use alloc::format;
#[test]
fn should_register_function() {
fn foo() -> i32 {
123
}
let mut registry = FunctionRegistry::default();
registry.register(foo).unwrap();
let function = registry.get(core::any::type_name_of_val(&foo)).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_anonymous_function() {
let mut registry = FunctionRegistry::default();
registry.register_with_name("foo", || 123_i32).unwrap();
let function = registry.get("foo").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_closure() {
let value = 123;
let foo = move || -> i32 { value };
let mut registry = FunctionRegistry::default();
registry.register_with_name("foo", foo).unwrap();
let function = registry.get("foo").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_dynamic_function() {
fn foo() -> i32 {
123
}
let function = foo.into_function().with_name("custom_name");
let mut registry = FunctionRegistry::default();
registry.register(function).unwrap();
let function = registry.get("custom_name").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_register_dynamic_closure() {
let value = 123;
let foo = move || -> i32 { value };
let function = foo.into_function().with_name("custom_name");
let mut registry = FunctionRegistry::default();
registry.register(function).unwrap();
let function = registry.get("custom_name").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_only_register_function_once() {
fn foo() -> i32 {
123
}
fn bar() -> i32 {
321
}
let name = core::any::type_name_of_val(&foo);
let mut registry = FunctionRegistry::default();
registry.register(foo).unwrap();
let result = registry.register(bar.into_function().with_name(name));
assert!(matches!(
result,
Err(FunctionRegistrationError::DuplicateName(_))
));
assert_eq!(registry.len(), 1);
let function = registry.get(name).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
fn should_allow_overwriting_registration() {
fn foo() -> i32 {
123
}
fn bar() -> i32 {
321
}
let name = core::any::type_name_of_val(&foo);
let mut registry = FunctionRegistry::default();
registry.register(foo).unwrap();
registry
.overwrite_registration(bar.into_function().with_name(name))
.unwrap();
assert_eq!(registry.len(), 1);
let function = registry.get(name).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&321));
}
#[test]
fn should_call_function_via_registry() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let mut registry = FunctionRegistry::default();
registry.register(add).unwrap();
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
let result = registry
.call(core::any::type_name_of_val(&add), args)
.unwrap();
let value = result.unwrap().unwrap_owned();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
fn should_error_on_missing_name() {
let foo = || -> i32 { 123 };
let function = foo.into_function();
let mut registry = FunctionRegistry::default();
let result = registry.register(function);
assert!(matches!(
result,
Err(FunctionRegistrationError::MissingName)
));
}
#[test]
fn should_debug_function_registry() {
fn foo() -> i32 {
123
}
let mut registry = FunctionRegistry::default();
registry.register_with_name("foo", foo).unwrap();
let debug = format!("{:?}", registry);
assert_eq!(debug, "{DynamicFunction(fn foo() -> i32)}");
}
}

View File

@@ -0,0 +1,166 @@
use crate::PartialReflect;
use alloc::boxed::Box;
/// The return type of a [`DynamicFunction`] or [`DynamicFunctionMut`].
///
/// [`DynamicFunction`]: crate::func::DynamicFunction
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug)]
pub enum Return<'a> {
/// The function returns an owned value.
///
/// This includes functions that return nothing (i.e. they return `()`).
Owned(Box<dyn PartialReflect>),
/// The function returns a reference to a value.
Ref(&'a dyn PartialReflect),
/// The function returns a mutable reference to a value.
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Return<'a> {
/// Creates an [`Owned`](Self::Owned) unit (`()`) type.
pub fn unit() -> Self {
Self::Owned(Box::new(()))
}
/// Returns `true` if the return value is an [`Owned`](Self::Owned) unit (`()`) type.
pub fn is_unit(&self) -> bool {
match self {
Return::Owned(val) => val.represents::<()>(),
_ => false,
}
}
/// Unwraps the return value as an owned value.
///
/// # Panics
///
/// Panics if the return value is not [`Self::Owned`].
pub fn unwrap_owned(self) -> Box<dyn PartialReflect> {
match self {
Return::Owned(value) => value,
_ => panic!("expected owned value"),
}
}
/// Unwraps the return value as a reference to a value.
///
/// # Panics
///
/// Panics if the return value is not [`Self::Ref`].
pub fn unwrap_ref(self) -> &'a dyn PartialReflect {
match self {
Return::Ref(value) => value,
_ => panic!("expected reference value"),
}
}
/// Unwraps the return value as a mutable reference to a value.
///
/// # Panics
///
/// Panics if the return value is not [`Self::Mut`].
pub fn unwrap_mut(self) -> &'a mut dyn PartialReflect {
match self {
Return::Mut(value) => value,
_ => panic!("expected mutable reference value"),
}
}
}
/// A trait for types that can be converted into a [`Return`] value.
///
/// This trait exists so that types can be automatically converted into a [`Return`]
/// by [`ReflectFn`] and [`ReflectFnMut`].
///
/// This trait is used instead of a blanket [`Into`] implementation due to coherence issues:
/// we can't implement `Into<Return>` for both `T` and `&T`/`&mut T`.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`ReflectFn`]: crate::func::ReflectFn
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
/// [derive macro]: derive@crate::Reflect
pub trait IntoReturn {
/// Converts [`Self`] into a [`Return`] value.
fn into_return<'a>(self) -> Return<'a>
where
Self: 'a;
}
impl IntoReturn for () {
fn into_return<'a>(self) -> Return<'a> {
Return::unit()
}
}
/// Implements the [`IntoReturn`] trait for the given type.
///
/// This will implement it for `ty`, `&ty`, and `&mut ty`.
///
/// See [`impl_function_traits`] for details on syntax.
///
/// [`impl_function_traits`]: crate::func::macros::impl_function_traits
macro_rules! impl_into_return {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
)?
$(
[
$(const $N: ident : $size: ident),*
]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Owned(Box::new(self))
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for &'static $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Ref(self)
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for &'static mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Mut(self)
}
}
};
}
pub(crate) use impl_into_return;

View File

@@ -0,0 +1,236 @@
//! Function signature types.
//!
//! Function signatures differ from [`FunctionInfo`] and [`SignatureInfo`] in that they
//! are only concerned about the types and order of the arguments and return type of a function.
//!
//! The names of arguments do not matter,
//! nor does any other information about the function such as its name or other attributes.
//!
//! This makes signatures useful for comparing or hashing functions strictly based on their
//! arguments and return type.
//!
//! [`FunctionInfo`]: crate::func::info::FunctionInfo
use crate::func::args::ArgInfo;
use crate::func::{ArgList, SignatureInfo};
use crate::Type;
use alloc::boxed::Box;
use bevy_platform::collections::Equivalent;
use core::borrow::Borrow;
use core::fmt::{Debug, Formatter};
use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
/// The signature of a function.
///
/// This can be used as a way to compare or hash functions based on their arguments and return type.
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Signature {
args: ArgumentSignature,
ret: Type,
}
impl Signature {
/// Create a new function signature with the given argument signature and return type.
pub fn new(args: ArgumentSignature, ret: Type) -> Self {
Self { args, ret }
}
/// Get the argument signature of the function.
pub fn args(&self) -> &ArgumentSignature {
&self.args
}
/// Get the return type of the function.
pub fn return_type(&self) -> &Type {
&self.ret
}
}
impl Debug for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?} -> {:?}", self.args, self.ret)
}
}
impl<T: Borrow<SignatureInfo>> From<T> for Signature {
fn from(info: T) -> Self {
let info = info.borrow();
Self::new(ArgumentSignature::from(info), *info.return_info().ty())
}
}
/// A wrapper around a borrowed [`ArgList`] that can be used as an
/// [equivalent] of an [`ArgumentSignature`].
///
/// [equivalent]: Equivalent
pub(super) struct ArgListSignature<'a, 'b>(&'a ArgList<'b>);
impl Equivalent<ArgumentSignature> for ArgListSignature<'_, '_> {
fn equivalent(&self, key: &ArgumentSignature) -> bool {
self.len() == key.len() && self.iter().eq(key.iter())
}
}
impl<'a, 'b> ArgListSignature<'a, 'b> {
pub fn iter(&self) -> impl ExactSizeIterator<Item = &Type> {
self.0.iter().map(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
})
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl Eq for ArgListSignature<'_, '_> {}
impl PartialEq for ArgListSignature<'_, '_> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
impl Hash for ArgListSignature<'_, '_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.iter().for_each(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
.hash(state);
});
}
}
impl<'a, 'b> From<&'a ArgList<'b>> for ArgListSignature<'a, 'b> {
fn from(args: &'a ArgList<'b>) -> Self {
Self(args)
}
}
/// The argument-portion of a function signature.
///
/// For example, given a function signature `(a: i32, b: f32) -> u32`,
/// the argument signature would be `(i32, f32)`.
///
/// This can be used as a way to compare or hash functions based on their arguments.
#[derive(Clone)]
pub struct ArgumentSignature(Box<[Type]>);
impl Debug for ArgumentSignature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut tuple = f.debug_tuple("");
for ty in self.0.iter() {
tuple.field(ty);
}
tuple.finish()
}
}
impl Deref for ArgumentSignature {
type Target = [Type];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ArgumentSignature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Eq for ArgumentSignature {}
impl PartialEq for ArgumentSignature {
fn eq(&self, other: &Self) -> bool {
self.0.len() == other.0.len() && self.0.iter().eq(other.0.iter())
}
}
impl Hash for ArgumentSignature {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.iter().for_each(|ty| ty.hash(state));
}
}
impl FromIterator<Type> for ArgumentSignature {
fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: Borrow<SignatureInfo>> From<T> for ArgumentSignature {
fn from(info: T) -> Self {
Self(
info.borrow()
.args()
.iter()
.map(ArgInfo::ty)
.copied()
.collect(),
)
}
}
impl From<&ArgList<'_>> for ArgumentSignature {
fn from(args: &ArgList) -> Self {
Self(
args.iter()
.map(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
})
.copied()
.collect(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::TypedFunction;
use alloc::{format, string::String, vec};
#[test]
fn should_generate_signature_from_function_info() {
fn add(a: i32, b: f32) -> u32 {
(a as f32 + b).round() as u32
}
let info = add.get_function_info();
let signature = Signature::from(info.base());
assert_eq!(signature.args().0.len(), 2);
assert_eq!(signature.args().0[0], Type::of::<i32>());
assert_eq!(signature.args().0[1], Type::of::<f32>());
assert_eq!(*signature.return_type(), Type::of::<u32>());
}
#[test]
fn should_debug_signature() {
let signature = Signature::new(
ArgumentSignature::from_iter(vec![Type::of::<&mut String>(), Type::of::<i32>()]),
Type::of::<()>(),
);
assert_eq!(
format!("{:?}", signature),
"(&mut alloc::string::String, i32) -> ()"
);
}
}

339
vendor/bevy_reflect/src/generics.rs vendored Normal file
View File

@@ -0,0 +1,339 @@
use crate::type_info::impl_type_methods;
use crate::{Reflect, Type, TypePath};
use alloc::{borrow::Cow, boxed::Box};
use bevy_platform::sync::Arc;
use core::ops::Deref;
use derive_more::derive::From;
/// The generic parameters of a type.
///
/// This is automatically generated via the [`Reflect` derive macro]
/// and stored on the [`TypeInfo`] returned by [`Typed::type_info`]
/// for types that have generics.
///
/// It supports both type parameters and const parameters
/// so long as they implement [`TypePath`].
///
/// If the type has no generics, this will be empty.
///
/// If the type is marked with `#[reflect(type_path = false)]`,
/// the generics will be empty even if the type has generics.
///
/// [`Reflect` derive macro]: bevy_reflect_derive::Reflect
/// [`TypeInfo`]: crate::type_info::TypeInfo
/// [`Typed::type_info`]: crate::Typed::type_info
#[derive(Clone, Default, Debug)]
pub struct Generics(Box<[GenericInfo]>);
impl Generics {
/// Creates an empty set of generics.
pub fn new() -> Self {
Self(Box::new([]))
}
/// Finds the generic parameter with the given name.
///
/// Returns `None` if no such parameter exists.
pub fn get_named(&self, name: &str) -> Option<&GenericInfo> {
// For small sets of generics (the most common case),
// a linear search is often faster using a `HashMap`.
self.0.iter().find(|info| info.name() == name)
}
/// Adds the given generic parameter to the set.
pub fn with(mut self, info: impl Into<GenericInfo>) -> Self {
self.0 = IntoIterator::into_iter(self.0)
.chain(core::iter::once(info.into()))
.collect();
self
}
}
impl<T: Into<GenericInfo>> FromIterator<T> for Generics {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().map(Into::into).collect())
}
}
impl Deref for Generics {
type Target = [GenericInfo];
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// An enum representing a generic parameter.
#[derive(Clone, Debug, From)]
pub enum GenericInfo {
/// A type parameter.
///
/// An example would be `T` in `struct Foo<T, U>`.
Type(TypeParamInfo),
/// A const parameter.
///
/// An example would be `N` in `struct Foo<const N: usize>`.
Const(ConstParamInfo),
}
impl GenericInfo {
/// The name of the generic parameter.
pub fn name(&self) -> &Cow<'static, str> {
match self {
Self::Type(info) => info.name(),
Self::Const(info) => info.name(),
}
}
/// Whether the generic parameter is a const parameter.
pub fn is_const(&self) -> bool {
match self {
Self::Type(_) => false,
Self::Const(_) => true,
}
}
impl_type_methods!(self => {
match self {
Self::Type(info) => info.ty(),
Self::Const(info) => info.ty(),
}
});
}
/// Type information for a generic type parameter.
///
/// An example of a type parameter would be `T` in `struct Foo<T>`.
#[derive(Clone, Debug)]
pub struct TypeParamInfo {
name: Cow<'static, str>,
ty: Type,
default: Option<Type>,
}
impl TypeParamInfo {
/// Creates a new type parameter with the given name.
pub fn new<T: TypePath + ?Sized>(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
ty: Type::of::<T>(),
default: None,
}
}
/// Sets the default type for the parameter.
pub fn with_default<T: TypePath + ?Sized>(mut self) -> Self {
self.default = Some(Type::of::<T>());
self
}
/// The name of the type parameter.
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
/// The default type for the parameter, if any.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{GenericInfo, Reflect, Typed};
/// #[derive(Reflect)]
/// struct Foo<T = f32>(T);
///
/// let generics = Foo::<String>::type_info().generics();
/// let GenericInfo::Type(info) = generics.get_named("T").unwrap() else {
/// panic!("expected a type parameter");
/// };
///
/// let default = info.default().unwrap();
///
/// assert!(default.is::<f32>());
/// ```
pub fn default(&self) -> Option<&Type> {
self.default.as_ref()
}
impl_type_methods!(ty);
}
/// Type information for a const generic parameter.
///
/// An example of a const parameter would be `N` in `struct Foo<const N: usize>`.
#[derive(Clone, Debug)]
pub struct ConstParamInfo {
name: Cow<'static, str>,
ty: Type,
// Rust currently only allows certain primitive types in const generic position,
// meaning that `Reflect` is guaranteed to be implemented for the default value.
default: Option<Arc<dyn Reflect>>,
}
impl ConstParamInfo {
/// Creates a new const parameter with the given name.
pub fn new<T: TypePath + ?Sized>(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
ty: Type::of::<T>(),
default: None,
}
}
/// Sets the default value for the parameter.
pub fn with_default<T: Reflect + 'static>(mut self, default: T) -> Self {
let arc = Arc::new(default);
#[cfg(not(target_has_atomic = "ptr"))]
#[expect(
unsafe_code,
reason = "unsized coercion is an unstable feature for non-std types"
)]
// SAFETY:
// - Coercion from `T` to `dyn Reflect` is valid as `T: Reflect + 'static`
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
let arc = unsafe { Arc::from_raw(Arc::into_raw(arc) as *const dyn Reflect) };
self.default = Some(arc);
self
}
/// The name of the const parameter.
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
/// The default value for the parameter, if any.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{GenericInfo, Reflect, Typed};
/// #[derive(Reflect)]
/// struct Foo<const N: usize = 10>([u8; N]);
///
/// let generics = Foo::<5>::type_info().generics();
/// let GenericInfo::Const(info) = generics.get_named("N").unwrap() else {
/// panic!("expected a const parameter");
/// };
///
/// let default = info.default().unwrap();
///
/// assert_eq!(default.downcast_ref::<usize>().unwrap(), &10);
/// ```
pub fn default(&self) -> Option<&dyn Reflect> {
self.default.as_deref()
}
impl_type_methods!(ty);
}
macro_rules! impl_generic_info_methods {
// Implements both getter and setter methods for the given field.
($field:ident) => {
$crate::generics::impl_generic_info_methods!(self => &self.$field);
/// Sets the generic parameters for this type.
pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
self.$field = generics;
self
}
};
// Implements only a getter method for the given expression.
($self:ident => $expr:expr) => {
/// Gets the generic parameters for this type.
pub fn generics(&$self) -> &crate::generics::Generics {
$expr
}
};
}
pub(crate) use impl_generic_info_methods;
#[cfg(test)]
mod tests {
use super::*;
use crate::{Reflect, Typed};
use alloc::string::String;
use core::fmt::Debug;
#[test]
fn should_maintain_order() {
#[derive(Reflect)]
struct Test<T, U: Debug, const N: usize>([(T, U); N]);
let generics = <Test<f32, String, 10> as Typed>::type_info()
.as_tuple_struct()
.unwrap()
.generics();
assert_eq!(generics.len(), 3);
let mut iter = generics.iter();
let t = iter.next().unwrap();
assert_eq!(t.name(), "T");
assert!(t.ty().is::<f32>());
assert!(!t.is_const());
let u = iter.next().unwrap();
assert_eq!(u.name(), "U");
assert!(u.ty().is::<String>());
assert!(!u.is_const());
let n = iter.next().unwrap();
assert_eq!(n.name(), "N");
assert!(n.ty().is::<usize>());
assert!(n.is_const());
assert!(iter.next().is_none());
}
#[test]
fn should_get_by_name() {
#[derive(Reflect)]
enum Test<T, U: Debug, const N: usize> {
Array([(T, U); N]),
}
let generics = <Test<f32, String, 10> as Typed>::type_info()
.as_enum()
.unwrap()
.generics();
let t = generics.get_named("T").unwrap();
assert_eq!(t.name(), "T");
assert!(t.ty().is::<f32>());
assert!(!t.is_const());
let u = generics.get_named("U").unwrap();
assert_eq!(u.name(), "U");
assert!(u.ty().is::<String>());
assert!(!u.is_const());
let n = generics.get_named("N").unwrap();
assert_eq!(n.name(), "N");
assert!(n.ty().is::<usize>());
assert!(n.is_const());
}
#[test]
fn should_store_defaults() {
#[derive(Reflect)]
struct Test<T, U: Debug = String, const N: usize = 10>([(T, U); N]);
let generics = <Test<f32> as Typed>::type_info()
.as_tuple_struct()
.unwrap()
.generics();
let GenericInfo::Type(u) = generics.get_named("U").unwrap() else {
panic!("expected a type parameter");
};
assert_eq!(u.default().unwrap(), &Type::of::<String>());
let GenericInfo::Const(n) = generics.get_named("N").unwrap() else {
panic!("expected a const parameter");
};
assert_eq!(n.default().unwrap().downcast_ref::<usize>().unwrap(), &10);
}
}

View File

@@ -0,0 +1,8 @@
use crate::impl_type_path;
impl_type_path!(::foldhash::fast::FoldHasher);
impl_type_path!(::foldhash::fast::FixedState);
impl_type_path!(::foldhash::fast::RandomState);
impl_type_path!(::foldhash::quality::FoldHasher);
impl_type_path!(::foldhash::quality::FixedState);
impl_type_path!(::foldhash::quality::RandomState);

575
vendor/bevy_reflect/src/impls/glam.rs vendored Normal file
View File

@@ -0,0 +1,575 @@
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use assert_type_match::assert_type_match;
use bevy_reflect_derive::{impl_reflect, impl_reflect_opaque};
use glam::*;
/// Reflects the given foreign type as an enum and asserts that the variants/fields match up.
macro_rules! reflect_enum {
($(#[$meta:meta])* enum $ident:ident { $($ty:tt)* } ) => {
impl_reflect!($(#[$meta])* enum $ident { $($ty)* });
#[assert_type_match($ident, test_only)]
#[expect(
clippy::upper_case_acronyms,
reason = "The variants used are not acronyms."
)]
enum $ident { $($ty)* }
};
}
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec2 {
x: i32,
y: i32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec3 {
x: i32,
y: i32,
z: i32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec4 {
x: i32,
y: i32,
z: i32,
w: i32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I8Vec2 {
x: i8,
y: i8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I8Vec3 {
x: i8,
y: i8,
z: i8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I8Vec4 {
x: i8,
y: i8,
z: i8,
w: i8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I16Vec2 {
x: i16,
y: i16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I16Vec3 {
x: i16,
y: i16,
z: i16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I16Vec4 {
x: i16,
y: i16,
z: i16,
w: i16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec2 {
x: i64,
y: i64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec3 {
x: i64,
y: i64,
z: i64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec4 {
x: i64,
y: i64,
z: i64,
w: i64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec2 {
x: u32,
y: u32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec3 {
x: u32,
y: u32,
z: u32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec4 {
x: u32,
y: u32,
z: u32,
w: u32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U8Vec2 {
x: u8,
y: u8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U8Vec3 {
x: u8,
y: u8,
z: u8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U8Vec4 {
x: u8,
y: u8,
z: u8,
w: u8,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U16Vec2 {
x: u16,
y: u16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U16Vec3 {
x: u16,
y: u16,
z: u16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U16Vec4 {
x: u16,
y: u16,
z: u16,
w: u16,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec2 {
x: u64,
y: u64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec3 {
x: u64,
y: u64,
z: u64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec4 {
x: u64,
y: u64,
z: u64,
w: u64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec2 {
x: f32,
y: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec3 {
x: f32,
y: f32,
z: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec3A {
x: f32,
y: f32,
z: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec4 {
x: f32,
y: f32,
z: f32,
w: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec2 {
x: bool,
y: bool,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec3 {
x: bool,
y: bool,
z: bool,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec4 {
x: bool,
y: bool,
z: bool,
w: bool,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec2 {
x: f64,
y: f64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec3 {
x: f64,
y: f64,
z: f64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec4 {
x: f64,
y: f64,
z: f64,
w: f64,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat2 {
x_axis: Vec2,
y_axis: Vec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat3 {
x_axis: Vec3,
y_axis: Vec3,
z_axis: Vec3,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat3A {
x_axis: Vec3A,
y_axis: Vec3A,
z_axis: Vec3A,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat4 {
x_axis: Vec4,
y_axis: Vec4,
z_axis: Vec4,
w_axis: Vec4,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat2 {
x_axis: DVec2,
y_axis: DVec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat3 {
x_axis: DVec3,
y_axis: DVec3,
z_axis: DVec3,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat4 {
x_axis: DVec4,
y_axis: DVec4,
z_axis: DVec4,
w_axis: DVec4,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Affine2 {
matrix2: Mat2,
translation: Vec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Affine3A {
matrix3: Mat3A,
translation: Vec3A,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DAffine2 {
matrix2: DMat2,
translation: DVec2,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DAffine3 {
matrix3: DMat3,
translation: DVec3,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Quat {
x: f32,
y: f32,
z: f32,
w: f32,
}
);
impl_reflect!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DQuat {
x: f64,
y: f64,
z: f64,
w: f64,
}
);
reflect_enum!(
#[reflect(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
enum EulerRot {
ZYX,
ZXY,
YXZ,
YZX,
XYZ,
XZY,
ZYZ,
ZXZ,
YXY,
YZY,
XYX,
XZX,
ZYXEx,
ZXYEx,
YXZEx,
YZXEx,
XYZEx,
XZYEx,
ZYZEx,
ZXZEx,
YXYEx,
YZYEx,
XYXEx,
XZXEx,
}
);
impl_reflect_opaque!(::glam::BVec3A(
Clone,
Debug,
Default,
Deserialize,
Serialize
));
impl_reflect_opaque!(::glam::BVec4A(
Clone,
Debug,
Default,
Deserialize,
Serialize
));
#[cfg(test)]
mod tests {
use alloc::{format, string::String};
use ron::{
ser::{to_string_pretty, PrettyConfig},
Deserializer,
};
use serde::de::DeserializeSeed;
use static_assertions::assert_impl_all;
use crate::{
prelude::*,
serde::{ReflectDeserializer, ReflectSerializer},
Enum, GetTypeRegistration, TypeRegistry,
};
use super::*;
assert_impl_all!(EulerRot: Enum);
#[test]
fn euler_rot_serialization() {
let v = EulerRot::YXZ;
let mut registry = TypeRegistry::default();
registry.register::<EulerRot>();
let ser = ReflectSerializer::new(&v, &registry);
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = to_string_pretty(&ser, config).unwrap();
let expected = r#"
{
"glam::EulerRot": YXZ,
}"#;
assert_eq!(expected, format!("\n{output}"));
}
#[test]
fn euler_rot_deserialization() {
let data = r#"
{
"glam::EulerRot": XZY,
}"#;
let mut registry = TypeRegistry::default();
registry.add_registration(EulerRot::get_type_registration());
let de = ReflectDeserializer::new(&registry);
let mut deserializer =
Deserializer::from_str(data).expect("Failed to acquire deserializer");
let dynamic_struct = de
.deserialize(&mut deserializer)
.expect("Failed to deserialize");
let mut result = EulerRot::default();
result.apply(dynamic_struct.as_partial_reflect());
assert_eq!(result, EulerRot::XZY);
}
}

View File

@@ -0,0 +1,15 @@
use crate::{impl_reflect_opaque, prelude::ReflectDefault, ReflectDeserialize, ReflectSerialize};
impl_reflect_opaque!(::petgraph::graph::NodeIndex(
Clone,
Default,
PartialEq,
Hash,
Serialize,
Deserialize
));
impl_reflect_opaque!(::petgraph::graph::DiGraph<
N: ::core::clone::Clone,
E: ::core::clone::Clone,
Ix: ::petgraph::graph::IndexType
>(Clone));

View File

@@ -0,0 +1,238 @@
use crate::{
utility::GenericTypeInfoCell, ApplyError, FromReflect, FromType, Generics, GetTypeRegistration,
List, ListInfo, ListIter, MaybeTyped, PartialReflect, Reflect, ReflectFromPtr, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeParamInfo, TypePath, TypeRegistration,
Typed,
};
use alloc::{borrow::Cow, boxed::Box, string::ToString, vec::Vec};
use bevy_reflect::ReflectCloneError;
use bevy_reflect_derive::impl_type_path;
use core::any::Any;
use smallvec::{Array as SmallArray, SmallVec};
impl<T: SmallArray + TypePath + Send + Sync> List for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
if index < SmallVec::len(self) {
Some(&self[index] as &dyn PartialReflect)
} else {
None
}
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
if index < SmallVec::len(self) {
Some(&mut self[index] as &mut dyn PartialReflect)
} else {
None
}
}
fn insert(&mut self, index: usize, value: Box<dyn PartialReflect>) {
let value = value.try_take::<T::Item>().unwrap_or_else(|value| {
<T as SmallArray>::Item::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"Attempted to insert invalid value of type {}.",
value.reflect_type_path()
)
})
});
SmallVec::insert(self, index, value);
}
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
Box::new(self.remove(index))
}
fn push(&mut self, value: Box<dyn PartialReflect>) {
let value = value.try_take::<T::Item>().unwrap_or_else(|value| {
<T as SmallArray>::Item::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"Attempted to push invalid value of type {}.",
value.reflect_type_path()
)
})
});
SmallVec::push(self, value);
}
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
self.pop()
.map(|value| Box::new(value) as Box<dyn PartialReflect>)
}
fn len(&self) -> usize {
<SmallVec<T>>::len(self)
}
fn iter(&self) -> ListIter {
ListIter::new(self)
}
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
self.drain(..)
.map(|value| Box::new(value) as Box<dyn PartialReflect>)
.collect()
}
}
impl<T: SmallArray + TypePath + Send + Sync> PartialReflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info())
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Ok(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
Some(self)
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
Some(self)
}
fn apply(&mut self, value: &dyn PartialReflect) {
crate::list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
crate::list_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::List(self)
}
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new(
self.iter()
.map(|value| {
value
.reflect_clone()?
.take()
.map_err(|_| ReflectCloneError::FailedDowncast {
expected: Cow::Borrowed(<T::Item as TypePath>::type_path()),
received: Cow::Owned(value.reflect_type_path().to_string()),
})
})
.collect::<Result<Self, ReflectCloneError>>()?,
))
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
crate::list_partial_eq(self, value)
}
}
impl<T: SmallArray + TypePath + Send + Sync> Reflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
}
fn as_reflect(&self) -> &dyn Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
}
impl<T: SmallArray + TypePath + Send + Sync + 'static> Typed for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn type_info() -> &'static TypeInfo {
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| {
TypeInfo::List(
ListInfo::new::<Self, T::Item>()
.with_generics(Generics::from_iter([TypeParamInfo::new::<T>("T")])),
)
})
}
}
impl_type_path!(::smallvec::SmallVec<T: SmallArray>);
impl<T: SmallArray + TypePath + Send + Sync> FromReflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
let ref_list = reflect.reflect_ref().as_list().ok()?;
let mut new_list = Self::with_capacity(ref_list.len());
for field in ref_list.iter() {
new_list.push(<T as SmallArray>::Item::from_reflect(field)?);
}
Some(new_list)
}
}
impl<T: SmallArray + TypePath + Send + Sync> GetTypeRegistration for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<SmallVec<T>>();
registration.insert::<ReflectFromPtr>(FromType::<SmallVec<T>>::from_type());
registration
}
}
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(SmallVec<T>; <T: SmallArray + TypePath + Send + Sync> where T::Item: FromReflect + MaybeTyped + TypePath);

View File

@@ -0,0 +1,34 @@
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::impl_reflect_opaque;
impl_reflect_opaque!(::smol_str::SmolStr(
Clone,
Debug,
Hash,
PartialEq,
Default,
Serialize,
Deserialize,
));
#[cfg(test)]
mod tests {
use crate::{FromReflect, PartialReflect};
use smol_str::SmolStr;
#[test]
fn should_partial_eq_smolstr() {
let a: &dyn PartialReflect = &SmolStr::new("A");
let a2: &dyn PartialReflect = &SmolStr::new("A");
let b: &dyn PartialReflect = &SmolStr::new("B");
assert_eq!(Some(true), a.reflect_partial_eq(a2));
assert_eq!(Some(false), a.reflect_partial_eq(b));
}
#[test]
fn smolstr_should_from_reflect() {
let smolstr = SmolStr::new("hello_world.rs");
let output = <SmolStr as FromReflect>::from_reflect(&smolstr);
assert_eq!(Some(smolstr), output);
}
}

2888
vendor/bevy_reflect/src/impls/std.rs vendored Normal file

File diff suppressed because it is too large Load Diff

12
vendor/bevy_reflect/src/impls/uuid.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::impl_reflect_opaque;
impl_reflect_opaque!(::uuid::Uuid(
Serialize,
Deserialize,
Default,
Clone,
Debug,
PartialEq,
Hash
));

View File

@@ -0,0 +1,10 @@
use crate::{impl_reflect_opaque, ReflectDeserialize, ReflectSerialize};
impl_reflect_opaque!(::wgpu_types::TextureFormat(
Clone,
Debug,
Hash,
PartialEq,
Deserialize,
Serialize,
));

334
vendor/bevy_reflect/src/kind.rs vendored Normal file
View File

@@ -0,0 +1,334 @@
use alloc::boxed::Box;
use thiserror::Error;
#[cfg(feature = "functions")]
use crate::func::Function;
use crate::{Array, Enum, List, Map, PartialReflect, Set, Struct, Tuple, TupleStruct};
/// An enumeration of the "kinds" of a reflected type.
///
/// Each kind corresponds to a specific reflection trait,
/// such as [`Struct`] or [`List`],
/// which itself corresponds to the kind or structure of a type.
///
/// A [`ReflectKind`] is obtained via [`PartialReflect::reflect_kind`],
/// or via [`ReflectRef::kind`],[`ReflectMut::kind`] or [`ReflectOwned::kind`].
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ReflectKind {
/// A [struct-like] type.
///
/// [struct-like]: Struct
Struct,
/// A [tuple-struct-like] type.
///
/// [tuple-struct-like]: TupleStruct
TupleStruct,
/// A [tuple-like] type.
///
/// [tuple-like]: Tuple
Tuple,
/// A [list-like] type.
///
/// [list-like]: List
List,
/// An [array-like] type.
///
/// [array-like]: Array
Array,
/// A [map-like] type.
///
/// [map-like]: Map
Map,
/// A [set-like] type.
///
/// [set-like]: Set
Set,
/// An [enum-like] type.
///
/// [enum-like]: Enum
Enum,
/// A [function-like] type.
///
/// [function-like]: Function
#[cfg(feature = "functions")]
Function,
/// An opaque type.
///
/// This most often represents a type where it is either impossible, difficult,
/// or unuseful to reflect the type further.
///
/// This includes types like `String` and `Instant`.
///
/// Despite not technically being opaque types,
/// primitives like `u32` `i32` are considered opaque for the purposes of reflection.
///
/// Additionally, any type that [derives `Reflect`] with the `#[reflect(opaque)]` attribute
/// will be considered an opaque type.
///
/// [derives `Reflect`]: bevy_reflect_derive::Reflect
Opaque,
}
impl core::fmt::Display for ReflectKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ReflectKind::Struct => f.pad("struct"),
ReflectKind::TupleStruct => f.pad("tuple struct"),
ReflectKind::Tuple => f.pad("tuple"),
ReflectKind::List => f.pad("list"),
ReflectKind::Array => f.pad("array"),
ReflectKind::Map => f.pad("map"),
ReflectKind::Set => f.pad("set"),
ReflectKind::Enum => f.pad("enum"),
#[cfg(feature = "functions")]
ReflectKind::Function => f.pad("function"),
ReflectKind::Opaque => f.pad("opaque"),
}
}
}
macro_rules! impl_reflect_kind_conversions {
($name:ident$(<$lifetime:lifetime>)?) => {
impl $name$(<$lifetime>)? {
/// Returns the "kind" of this reflected type without any information.
pub fn kind(&self) -> ReflectKind {
match self {
Self::Struct(_) => ReflectKind::Struct,
Self::TupleStruct(_) => ReflectKind::TupleStruct,
Self::Tuple(_) => ReflectKind::Tuple,
Self::List(_) => ReflectKind::List,
Self::Array(_) => ReflectKind::Array,
Self::Map(_) => ReflectKind::Map,
Self::Set(_) => ReflectKind::Set,
Self::Enum(_) => ReflectKind::Enum,
#[cfg(feature = "functions")]
Self::Function(_) => ReflectKind::Function,
Self::Opaque(_) => ReflectKind::Opaque,
}
}
}
impl From<$name$(<$lifetime>)?> for ReflectKind {
fn from(value: $name) -> Self {
match value {
$name::Struct(_) => Self::Struct,
$name::TupleStruct(_) => Self::TupleStruct,
$name::Tuple(_) => Self::Tuple,
$name::List(_) => Self::List,
$name::Array(_) => Self::Array,
$name::Map(_) => Self::Map,
$name::Set(_) => Self::Set,
$name::Enum(_) => Self::Enum,
#[cfg(feature = "functions")]
$name::Function(_) => Self::Function,
$name::Opaque(_) => Self::Opaque,
}
}
}
};
}
/// Caused when a type was expected to be of a certain [kind], but was not.
///
/// [kind]: ReflectKind
#[derive(Debug, Error)]
#[error("kind mismatch: expected {expected:?}, received {received:?}")]
pub struct ReflectKindMismatchError {
pub expected: ReflectKind,
pub received: ReflectKind,
}
macro_rules! impl_cast_method {
($name:ident : Opaque => $retval:ty) => {
#[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
#[doc = "\n\nReturns an error if `self` is not the [`Self::Opaque`] variant."]
pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
match self {
Self::Opaque(value) => Ok(value),
_ => Err(ReflectKindMismatchError {
expected: ReflectKind::Opaque,
received: self.kind(),
}),
}
}
};
($name:ident : $kind:ident => $retval:ty) => {
#[doc = concat!("Attempts a cast to a [`", stringify!($kind), "`] trait object.")]
#[doc = concat!("\n\nReturns an error if `self` is not the [`Self::", stringify!($kind), "`] variant.")]
pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
match self {
Self::$kind(value) => Ok(value),
_ => Err(ReflectKindMismatchError {
expected: ReflectKind::$kind,
received: self.kind(),
}),
}
}
};
}
/// An immutable enumeration of ["kinds"] of a reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectRef`] is obtained via [`PartialReflect::reflect_ref`].
///
/// ["kinds"]: ReflectKind
pub enum ReflectRef<'a> {
Struct(&'a dyn Struct),
TupleStruct(&'a dyn TupleStruct),
Tuple(&'a dyn Tuple),
List(&'a dyn List),
Array(&'a dyn Array),
Map(&'a dyn Map),
Set(&'a dyn Set),
Enum(&'a dyn Enum),
#[cfg(feature = "functions")]
Function(&'a dyn Function),
Opaque(&'a dyn PartialReflect),
}
impl_reflect_kind_conversions!(ReflectRef<'_>);
impl<'a> ReflectRef<'a> {
impl_cast_method!(as_struct: Struct => &'a dyn Struct);
impl_cast_method!(as_tuple_struct: TupleStruct => &'a dyn TupleStruct);
impl_cast_method!(as_tuple: Tuple => &'a dyn Tuple);
impl_cast_method!(as_list: List => &'a dyn List);
impl_cast_method!(as_array: Array => &'a dyn Array);
impl_cast_method!(as_map: Map => &'a dyn Map);
impl_cast_method!(as_set: Set => &'a dyn Set);
impl_cast_method!(as_enum: Enum => &'a dyn Enum);
impl_cast_method!(as_opaque: Opaque => &'a dyn PartialReflect);
}
/// A mutable enumeration of ["kinds"] of a reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectMut`] is obtained via [`PartialReflect::reflect_mut`].
///
/// ["kinds"]: ReflectKind
pub enum ReflectMut<'a> {
Struct(&'a mut dyn Struct),
TupleStruct(&'a mut dyn TupleStruct),
Tuple(&'a mut dyn Tuple),
List(&'a mut dyn List),
Array(&'a mut dyn Array),
Map(&'a mut dyn Map),
Set(&'a mut dyn Set),
Enum(&'a mut dyn Enum),
#[cfg(feature = "functions")]
Function(&'a mut dyn Function),
Opaque(&'a mut dyn PartialReflect),
}
impl_reflect_kind_conversions!(ReflectMut<'_>);
impl<'a> ReflectMut<'a> {
impl_cast_method!(as_struct: Struct => &'a mut dyn Struct);
impl_cast_method!(as_tuple_struct: TupleStruct => &'a mut dyn TupleStruct);
impl_cast_method!(as_tuple: Tuple => &'a mut dyn Tuple);
impl_cast_method!(as_list: List => &'a mut dyn List);
impl_cast_method!(as_array: Array => &'a mut dyn Array);
impl_cast_method!(as_map: Map => &'a mut dyn Map);
impl_cast_method!(as_set: Set => &'a mut dyn Set);
impl_cast_method!(as_enum: Enum => &'a mut dyn Enum);
impl_cast_method!(as_opaque: Opaque => &'a mut dyn PartialReflect);
}
/// An owned enumeration of ["kinds"] of a reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectOwned`] is obtained via [`PartialReflect::reflect_owned`].
///
/// ["kinds"]: ReflectKind
pub enum ReflectOwned {
Struct(Box<dyn Struct>),
TupleStruct(Box<dyn TupleStruct>),
Tuple(Box<dyn Tuple>),
List(Box<dyn List>),
Array(Box<dyn Array>),
Map(Box<dyn Map>),
Set(Box<dyn Set>),
Enum(Box<dyn Enum>),
#[cfg(feature = "functions")]
Function(Box<dyn Function>),
Opaque(Box<dyn PartialReflect>),
}
impl_reflect_kind_conversions!(ReflectOwned);
impl ReflectOwned {
impl_cast_method!(into_struct: Struct => Box<dyn Struct>);
impl_cast_method!(into_tuple_struct: TupleStruct => Box<dyn TupleStruct>);
impl_cast_method!(into_tuple: Tuple => Box<dyn Tuple>);
impl_cast_method!(into_list: List => Box<dyn List>);
impl_cast_method!(into_array: Array => Box<dyn Array>);
impl_cast_method!(into_map: Map => Box<dyn Map>);
impl_cast_method!(into_set: Set => Box<dyn Set>);
impl_cast_method!(into_enum: Enum => Box<dyn Enum>);
impl_cast_method!(into_value: Opaque => Box<dyn PartialReflect>);
}
#[cfg(test)]
mod tests {
use alloc::vec;
use std::collections::HashSet;
use super::*;
#[test]
fn should_cast_ref() {
let value = vec![1, 2, 3];
let result = value.reflect_ref().as_list();
assert!(result.is_ok());
let result = value.reflect_ref().as_array();
assert!(matches!(
result,
Err(ReflectKindMismatchError {
expected: ReflectKind::Array,
received: ReflectKind::List
})
));
}
#[test]
fn should_cast_mut() {
let mut value: HashSet<i32> = HashSet::default();
let result = value.reflect_mut().as_set();
assert!(result.is_ok());
let result = value.reflect_mut().as_map();
assert!(matches!(
result,
Err(ReflectKindMismatchError {
expected: ReflectKind::Map,
received: ReflectKind::Set
})
));
}
#[test]
fn should_cast_owned() {
let value = Box::new(Some(123));
let result = value.reflect_owned().into_enum();
assert!(result.is_ok());
let value = Box::new(Some(123));
let result = value.reflect_owned().into_struct();
assert!(matches!(
result,
Err(ReflectKindMismatchError {
expected: ReflectKind::Struct,
received: ReflectKind::Enum
})
));
}
}

3510
vendor/bevy_reflect/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

568
vendor/bevy_reflect/src/list.rs vendored Normal file
View File

@@ -0,0 +1,568 @@
use alloc::{boxed::Box, vec::Vec};
use core::{
any::Any,
fmt::{Debug, Formatter},
hash::{Hash, Hasher},
};
use bevy_reflect_derive::impl_type_path;
use crate::generics::impl_generic_info_methods;
use crate::{
type_info::impl_type_methods, utility::reflect_hasher, ApplyError, FromReflect, Generics,
MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
TypeInfo, TypePath,
};
/// A trait used to power [list-like] operations via [reflection].
///
/// This corresponds to types, like [`Vec`], which contain an ordered sequence
/// of elements that implement [`Reflect`].
///
/// Unlike the [`Array`](crate::Array) trait, implementors of this trait are not expected to
/// maintain a constant length.
/// Methods like [insertion](List::insert) and [removal](List::remove) explicitly allow for their
/// internal size to change.
///
/// [`push`](List::push) and [`pop`](List::pop) have default implementations,
/// however it will generally be more performant to implement them manually
/// as the default implementation uses a very naive approach to find the correct position.
///
/// This trait expects its elements to be ordered linearly from front to back.
/// The _front_ element starts at index 0 with the _back_ element ending at the largest index.
/// This contract above should be upheld by any manual implementors.
///
/// Due to the [type-erasing] nature of the reflection API as a whole,
/// this trait does not make any guarantees that the implementor's elements
/// are homogeneous (i.e. all the same type).
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, List};
///
/// let foo: &mut dyn List = &mut vec![123_u32, 456_u32, 789_u32];
/// assert_eq!(foo.len(), 3);
///
/// let last_field: Box<dyn PartialReflect> = foo.pop().unwrap();
/// assert_eq!(last_field.try_downcast_ref::<u32>(), Some(&789));
/// ```
///
/// [list-like]: https://doc.rust-lang.org/book/ch08-01-vectors.html
/// [reflection]: crate
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
pub trait List: PartialReflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Inserts an element at position `index` within the list,
/// shifting all elements after it towards the back of the list.
///
/// # Panics
/// Panics if `index > len`.
fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>);
/// Removes and returns the element at position `index` within the list,
/// shifting all elements before it towards the front of the list.
///
/// # Panics
/// Panics if `index` is out of bounds.
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect>;
/// Appends an element to the _back_ of the list.
fn push(&mut self, value: Box<dyn PartialReflect>) {
self.insert(self.len(), value);
}
/// Removes the _back_ element from the list and returns it, or [`None`] if it is empty.
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
if self.is_empty() {
None
} else {
Some(self.remove(self.len() - 1))
}
}
/// Returns the number of elements in the list.
fn len(&self) -> usize;
/// Returns `true` if the collection contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the list.
fn iter(&self) -> ListIter;
/// Drain the elements of this list to get a vector of owned values.
///
/// After calling this function, `self` will be empty. The order of items in the returned
/// [`Vec`] will match the order of items in `self`.
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
/// Clones the list, producing a [`DynamicList`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_list` instead")]
fn clone_dynamic(&self) -> DynamicList {
self.to_dynamic_list()
}
/// Creates a new [`DynamicList`] from this list.
fn to_dynamic_list(&self) -> DynamicList {
DynamicList {
represented_type: self.get_represented_type_info(),
values: self.iter().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_list_info(&self) -> Option<&'static ListInfo> {
self.get_represented_type_info()?.as_list().ok()
}
}
/// A container for compile-time list info.
#[derive(Clone, Debug)]
pub struct ListInfo {
ty: Type,
generics: Generics,
item_info: fn() -> Option<&'static TypeInfo>,
item_ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl ListInfo {
/// Create a new [`ListInfo`].
pub fn new<TList: List + TypePath, TItem: FromReflect + MaybeTyped + TypePath>() -> Self {
Self {
ty: Type::of::<TList>(),
generics: Generics::new(),
item_info: TItem::maybe_type_info,
item_ty: Type::of::<TItem>(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this list.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
impl_type_methods!(ty);
/// The [`TypeInfo`] of the list item.
///
/// Returns `None` if the list item does not contain static type information,
/// such as for dynamic types.
pub fn item_info(&self) -> Option<&'static TypeInfo> {
(self.item_info)()
}
/// The [type] of the list item.
///
/// [type]: Type
pub fn item_ty(&self) -> Type {
self.item_ty
}
/// The docstring of this list, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// A list of reflected values.
#[derive(Default)]
pub struct DynamicList {
represented_type: Option<&'static TypeInfo>,
values: Vec<Box<dyn PartialReflect>>,
}
impl DynamicList {
/// Sets the [type] to be represented by this `DynamicList`.
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::List`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::List(_)),
"expected TypeInfo::List but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Appends a typed value to the list.
pub fn push<T: PartialReflect>(&mut self, value: T) {
self.values.push(Box::new(value));
}
/// Appends a [`Reflect`] trait object to the list.
pub fn push_box(&mut self, value: Box<dyn PartialReflect>) {
self.values.push(value);
}
}
impl List for DynamicList {
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
self.values.get(index).map(|value| &**value)
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>) {
self.values.insert(index, element);
}
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
self.values.remove(index)
}
fn push(&mut self, value: Box<dyn PartialReflect>) {
DynamicList::push_box(self, value);
}
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
self.values.pop()
}
fn len(&self) -> usize {
self.values.len()
}
fn iter(&self) -> ListIter {
ListIter::new(self)
}
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
self.values.drain(..).collect()
}
}
impl PartialReflect for DynamicList {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
list_try_apply(self, value)
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::List(self)
}
#[inline]
fn reflect_hash(&self) -> Option<u64> {
list_hash(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
list_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicList(")?;
list_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicList);
impl Debug for DynamicList {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicList {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect(),
}
}
}
impl<T: PartialReflect> FromIterator<T> for DynamicList {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|field| Box::new(field).into_partial_reflect())
.collect()
}
}
impl IntoIterator for DynamicList {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicList {
type Item = &'a dyn PartialReflect;
type IntoIter = ListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// An iterator over an [`List`].
pub struct ListIter<'a> {
list: &'a dyn List,
index: usize,
}
impl ListIter<'_> {
/// Creates a new [`ListIter`].
#[inline]
pub const fn new(list: &dyn List) -> ListIter {
ListIter { list, index: 0 }
}
}
impl<'a> Iterator for ListIter<'a> {
type Item = &'a dyn PartialReflect;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let value = self.list.get(self.index);
self.index += value.is_some() as usize;
value
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.list.len();
(size, Some(size))
}
}
impl ExactSizeIterator for ListIter<'_> {}
/// Returns the `u64` hash of the given [list](List).
#[inline]
pub fn list_hash<L: List>(list: &L) -> Option<u64> {
let mut hasher = reflect_hasher();
Any::type_id(list).hash(&mut hasher);
list.len().hash(&mut hasher);
for value in list.iter() {
hasher.write_u64(value.reflect_hash()?);
}
Some(hasher.finish())
}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// If the length of `b` is greater than that of `a`, the excess elements of `b`
/// are cloned and appended to `a`.
///
/// # Panics
///
/// This function panics if `b` is not a list.
#[inline]
pub fn list_apply<L: List>(a: &mut L, b: &dyn PartialReflect) {
if let Err(err) = list_try_apply(a, b) {
panic!("{err}");
}
}
/// Tries to apply the elements of `b` to the corresponding elements of `a` and
/// returns a Result.
///
/// If the length of `b` is greater than that of `a`, the excess elements of `b`
/// are cloned and appended to `a`.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a list or if
/// applying elements to each other fails.
#[inline]
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let list_value = b.reflect_ref().as_list()?;
for (i, value) in list_value.iter().enumerate() {
if i < a.len() {
if let Some(v) = a.get_mut(i) {
v.try_apply(value)?;
}
} else {
List::push(a, value.to_dynamic());
}
}
Ok(())
}
/// Compares a [`List`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a list;
/// - `b` is the same length as `a`;
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn list_partial_eq<L: List + ?Sized>(a: &L, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::List(list) = b.reflect_ref() else {
return Some(false);
};
if a.len() != list.len() {
return Some(false);
}
for (a_value, b_value) in a.iter().zip(list.iter()) {
let eq_result = a_value.reflect_partial_eq(b_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}
Some(true)
}
/// The default debug formatter for [`List`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
///
/// let my_list: &dyn Reflect = &vec![1, 2, 3];
/// println!("{:#?}", my_list);
///
/// // Output:
///
/// // [
/// // 1,
/// // 2,
/// // 3,
/// // ]
/// ```
#[inline]
pub fn list_debug(dyn_list: &dyn List, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_list();
for item in dyn_list.iter() {
debug.entry(&item as &dyn Debug);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use super::DynamicList;
use crate::Reflect;
use alloc::{boxed::Box, vec};
use core::assert_eq;
#[test]
fn test_into_iter() {
let mut list = DynamicList::default();
list.push(0usize);
list.push(1usize);
list.push(2usize);
let items = list.into_iter();
for (index, item) in items.into_iter().enumerate() {
let value = item
.try_take::<usize>()
.expect("couldn't downcast to usize");
assert_eq!(index, value);
}
}
#[test]
fn next_index_increment() {
const SIZE: usize = if cfg!(debug_assertions) {
4
} else {
// If compiled in release mode, verify we dont overflow
usize::MAX
};
let b = Box::new(vec![(); SIZE]).into_reflect();
let list = b.reflect_ref().as_list().unwrap();
let mut iter = list.iter();
iter.index = SIZE - 1;
assert!(iter.next().is_some());
// When None we should no longer increase index
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
assert!(iter.next().is_none());
assert!(iter.index == SIZE);
}
}

751
vendor/bevy_reflect/src/map.rs vendored Normal file
View File

@@ -0,0 +1,751 @@
use core::fmt::{Debug, Formatter};
use bevy_platform::collections::HashTable;
use bevy_reflect_derive::impl_type_path;
use crate::{
generics::impl_generic_info_methods, type_info::impl_type_methods, ApplyError, Generics,
MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
TypeInfo, TypePath,
};
use alloc::{boxed::Box, format, vec::Vec};
/// A trait used to power [map-like] operations via [reflection].
///
/// Maps contain zero or more entries of a key and its associated value,
/// and correspond to types like [`HashMap`] and [`BTreeMap`].
/// The order of these entries is not guaranteed by this trait.
///
/// # Hashing and equality
///
/// All keys are expected to return a valid hash value from [`PartialReflect::reflect_hash`] and be
/// comparable using [`PartialReflect::reflect_partial_eq`].
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding
/// `#[reflect(Hash, PartialEq)]` to the entire struct or enum.
/// The ordering is expected to be total, that is as if the reflected type implements the [`Eq`] trait.
/// This is true even for manual implementors who do not hash or compare values,
/// as it is still relied on by [`DynamicMap`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, Map};
/// use std::collections::HashMap;
///
///
/// let foo: &mut dyn Map = &mut HashMap::<u32, bool>::new();
/// foo.insert_boxed(Box::new(123_u32), Box::new(true));
/// assert_eq!(foo.len(), 1);
///
/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.try_downcast_ref::<bool>(), Some(&true));
/// ```
///
/// [`HashMap`]: std::collections::HashMap
/// [`BTreeMap`]: alloc::collections::BTreeMap
/// [map-like]: https://doc.rust-lang.org/book/ch08-03-hash-maps.html
/// [reflection]: crate
pub trait Map: PartialReflect {
/// Returns a reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect>;
/// Returns the key-value pair at `index` by reference, or `None` if out of bounds.
fn get_at(&self, index: usize) -> Option<(&dyn PartialReflect, &dyn PartialReflect)>;
/// Returns the key-value pair at `index` by reference where the value is a mutable reference, or `None` if out of bounds.
fn get_at_mut(
&mut self,
index: usize,
) -> Option<(&dyn PartialReflect, &mut dyn PartialReflect)>;
/// Returns the number of elements in the map.
fn len(&self) -> usize;
/// Returns `true` if the list contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the key-value pairs of the map.
fn iter(&self) -> MapIter;
/// Drain the key-value pairs of this map to get a vector of owned values.
///
/// After calling this function, `self` will be empty.
fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>;
/// Clones the map, producing a [`DynamicMap`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_map` instead")]
fn clone_dynamic(&self) -> DynamicMap {
self.to_dynamic_map()
}
/// Creates a new [`DynamicMap`] from this map.
fn to_dynamic_map(&self) -> DynamicMap {
let mut map = DynamicMap::default();
map.set_represented_type(self.get_represented_type_info());
for (key, value) in self.iter() {
map.insert_boxed(key.to_dynamic(), value.to_dynamic());
}
map
}
/// Inserts a key-value pair into the map.
///
/// If the map did not have this key present, `None` is returned.
/// If the map did have this key present, the value is updated, and the old value is returned.
fn insert_boxed(
&mut self,
key: Box<dyn PartialReflect>,
value: Box<dyn PartialReflect>,
) -> Option<Box<dyn PartialReflect>>;
/// Removes an entry from the map.
///
/// If the map did not have this key present, `None` is returned.
/// If the map did have this key present, the removed value is returned.
fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>>;
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_map_info(&self) -> Option<&'static MapInfo> {
self.get_represented_type_info()?.as_map().ok()
}
}
/// A container for compile-time map info.
#[derive(Clone, Debug)]
pub struct MapInfo {
ty: Type,
generics: Generics,
key_info: fn() -> Option<&'static TypeInfo>,
key_ty: Type,
value_info: fn() -> Option<&'static TypeInfo>,
value_ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl MapInfo {
/// Create a new [`MapInfo`].
pub fn new<
TMap: Map + TypePath,
TKey: Reflect + MaybeTyped + TypePath,
TValue: Reflect + MaybeTyped + TypePath,
>() -> Self {
Self {
ty: Type::of::<TMap>(),
generics: Generics::new(),
key_info: TKey::maybe_type_info,
key_ty: Type::of::<TKey>(),
value_info: TValue::maybe_type_info,
value_ty: Type::of::<TValue>(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this map.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
impl_type_methods!(ty);
/// The [`TypeInfo`] of the key type.
///
/// Returns `None` if the key type does not contain static type information,
/// such as for dynamic types.
pub fn key_info(&self) -> Option<&'static TypeInfo> {
(self.key_info)()
}
/// The [type] of the key type.
///
/// [type]: Type
pub fn key_ty(&self) -> Type {
self.key_ty
}
/// The [`TypeInfo`] of the value type.
///
/// Returns `None` if the value type does not contain static type information,
/// such as for dynamic types.
pub fn value_info(&self) -> Option<&'static TypeInfo> {
(self.value_info)()
}
/// The [type] of the value type.
///
/// [type]: Type
pub fn value_ty(&self) -> Type {
self.value_ty
}
/// The docstring of this map, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
#[macro_export]
macro_rules! hash_error {
( $key:expr ) => {{
let type_path = (*$key).reflect_type_path();
if !$key.is_dynamic() {
format!(
"the given key of type `{}` does not support hashing",
type_path
)
} else {
match (*$key).get_represented_type_info() {
// Handle dynamic types that do not represent a type (i.e a plain `DynamicStruct`):
None => format!("the dynamic type `{}` does not support hashing", type_path),
// Handle dynamic types that do represent a type (i.e. a `DynamicStruct` proxying `Foo`):
Some(s) => format!(
"the dynamic type `{}` (representing `{}`) does not support hashing",
type_path,
s.type_path()
),
}
}
}}
}
/// An ordered mapping between reflected values.
#[derive(Default)]
pub struct DynamicMap {
represented_type: Option<&'static TypeInfo>,
values: Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>,
indices: HashTable<usize>,
}
impl DynamicMap {
/// Sets the [type] to be represented by this `DynamicMap`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Map`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Map(_)),
"expected TypeInfo::Map but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Inserts a typed key-value pair into the map.
pub fn insert<K: PartialReflect, V: PartialReflect>(&mut self, key: K, value: V) {
self.insert_boxed(Box::new(key), Box::new(value));
}
fn internal_hash(value: &dyn PartialReflect) -> u64 {
value.reflect_hash().expect(&hash_error!(value))
}
fn internal_eq<'a>(
value: &'a dyn PartialReflect,
values: &'a [(Box<dyn PartialReflect>, Box<dyn PartialReflect>)],
) -> impl FnMut(&usize) -> bool + 'a {
|&index| {
value
.reflect_partial_eq(&*values[index].0)
.expect("underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
}
}
}
impl Map for DynamicMap {
fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
let hash = Self::internal_hash(key);
let eq = Self::internal_eq(key, &self.values);
self.indices
.find(hash, eq)
.map(|&index| &*self.values[index].1)
}
fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect> {
let hash = Self::internal_hash(key);
let eq = Self::internal_eq(key, &self.values);
self.indices
.find(hash, eq)
.map(|&index| &mut *self.values[index].1)
}
fn get_at(&self, index: usize) -> Option<(&dyn PartialReflect, &dyn PartialReflect)> {
self.values
.get(index)
.map(|(key, value)| (&**key, &**value))
}
fn get_at_mut(
&mut self,
index: usize,
) -> Option<(&dyn PartialReflect, &mut dyn PartialReflect)> {
self.values
.get_mut(index)
.map(|(key, value)| (&**key, &mut **value))
}
fn len(&self) -> usize {
self.values.len()
}
fn iter(&self) -> MapIter {
MapIter::new(self)
}
fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> {
self.values.drain(..).collect()
}
fn insert_boxed(
&mut self,
key: Box<dyn PartialReflect>,
value: Box<dyn PartialReflect>,
) -> Option<Box<dyn PartialReflect>> {
assert_eq!(
key.reflect_partial_eq(&*key),
Some(true),
"keys inserted in `Map`-like types are expected to reflect `PartialEq`"
);
let hash = Self::internal_hash(&*key);
let eq = Self::internal_eq(&*key, &self.values);
match self.indices.find(hash, eq) {
Some(&index) => {
let (key_ref, value_ref) = &mut self.values[index];
*key_ref = key;
let old_value = core::mem::replace(value_ref, value);
Some(old_value)
}
None => {
let index = self.values.len();
self.values.push((key, value));
self.indices.insert_unique(hash, index, |&index| {
Self::internal_hash(&*self.values[index].0)
});
None
}
}
}
fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>> {
let hash = Self::internal_hash(key);
let eq = Self::internal_eq(key, &self.values);
match self.indices.find_entry(hash, eq) {
Ok(entry) => {
let (index, _) = entry.remove();
let (_, old_value) = self.values.swap_remove(index);
// The `swap_remove` might have moved the last element of `values`
// to `index`, so we might need to fix up its index in `indices`.
// If the removed element was also the last element there's nothing to
// fixup and this will return `None`, otherwise it returns the key
// whose index needs to be fixed up.
if let Some((moved_key, _)) = self.values.get(index) {
let hash = Self::internal_hash(&**moved_key);
let moved_index = self
.indices
.find_mut(hash, |&moved_index| moved_index == self.values.len())
.expect("key inserted in a `DynamicMap` is no longer present, this means its reflected `Hash` might be incorrect");
*moved_index = index;
}
Some(old_value)
}
Err(_) => None,
}
}
}
impl PartialReflect for DynamicMap {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
map_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
map_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Map
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Map(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Map(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Map(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
map_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicMap(")?;
map_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicMap);
impl Debug for DynamicMap {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
/// An iterator over the key-value pairs of a [`Map`].
pub struct MapIter<'a> {
map: &'a dyn Map,
index: usize,
}
impl MapIter<'_> {
/// Creates a new [`MapIter`].
#[inline]
pub const fn new(map: &dyn Map) -> MapIter {
MapIter { map, index: 0 }
}
}
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
fn next(&mut self) -> Option<Self::Item> {
let value = self.map.get_at(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.map.len();
(size, Some(size))
}
}
impl FromIterator<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>)>>(
items: I,
) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert_boxed(key, value);
}
map
}
}
impl<K: Reflect, V: Reflect> FromIterator<(K, V)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (K, V)>>(items: I) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert(key, value);
}
map
}
}
impl IntoIterator for DynamicMap {
type Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>);
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicMap {
type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
type IntoIter = MapIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> ExactSizeIterator for MapIter<'a> {}
/// Compares a [`Map`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a map;
/// - `b` is the same length as `a`;
/// - For each key-value pair in `a`, `b` contains a value for the given key,
/// and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn map_partial_eq<M: Map + ?Sized>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Map(map) = b.reflect_ref() else {
return Some(false);
};
if a.len() != map.len() {
return Some(false);
}
for (key, value) in a.iter() {
if let Some(map_value) = map.get(key) {
let eq_result = value.reflect_partial_eq(map_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`Map`] types.
///
/// # Example
/// ```
/// # use std::collections::HashMap;
/// use bevy_reflect::Reflect;
///
/// let mut my_map = HashMap::new();
/// my_map.insert(123, String::from("Hello"));
/// println!("{:#?}", &my_map as &dyn Reflect);
///
/// // Output:
///
/// // {
/// // 123: "Hello",
/// // }
/// ```
#[inline]
pub fn map_debug(dyn_map: &dyn Map, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_map();
for (key, value) in dyn_map.iter() {
debug.entry(&key as &dyn Debug, &value as &dyn Debug);
}
debug.finish()
}
/// Applies the elements of reflected map `b` to the corresponding elements of map `a`.
///
/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Panics
///
/// This function panics if `b` is not a reflected map.
#[inline]
pub fn map_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) {
if let Err(err) = map_try_apply(a, b) {
panic!("{err}");
}
}
/// Tries to apply the elements of reflected map `b` to the corresponding elements of map `a`
/// and returns a Result.
///
/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected map or if
/// applying elements to each other fails.
#[inline]
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let map_value = b.reflect_ref().as_map()?;
for (key, b_value) in map_value.iter() {
if let Some(a_value) = a.get_mut(key) {
a_value.try_apply(b_value)?;
} else {
a.insert_boxed(key.to_dynamic(), b_value.to_dynamic());
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::{DynamicMap, Map};
use alloc::{
borrow::ToOwned,
string::{String, ToString},
};
#[test]
fn test_into_iter() {
let expected = ["foo", "bar", "baz"];
let mut map = DynamicMap::default();
map.insert(0usize, expected[0].to_string());
map.insert(1usize, expected[1].to_string());
map.insert(2usize, expected[2].to_string());
for (index, item) in map.into_iter().enumerate() {
let key = item
.0
.try_take::<usize>()
.expect("couldn't downcast to usize");
let value = item
.1
.try_take::<String>()
.expect("couldn't downcast to String");
assert_eq!(index, key);
assert_eq!(expected[index], value);
}
}
#[test]
fn test_map_get_at() {
let values = ["first", "second", "third"];
let mut map = DynamicMap::default();
map.insert(0usize, values[0].to_string());
map.insert(1usize, values[1].to_string());
map.insert(1usize, values[2].to_string());
let (key_r, value_r) = map.get_at(1).expect("Item wasn't found");
let value = value_r
.try_downcast_ref::<String>()
.expect("Couldn't downcast to String");
let key = key_r
.try_downcast_ref::<usize>()
.expect("Couldn't downcast to usize");
assert_eq!(key, &1usize);
assert_eq!(value, &values[2].to_owned());
assert!(map.get_at(2).is_none());
map.remove(&1usize);
assert!(map.get_at(1).is_none());
}
#[test]
fn test_map_get_at_mut() {
let values = ["first", "second", "third"];
let mut map = DynamicMap::default();
map.insert(0usize, values[0].to_string());
map.insert(1usize, values[1].to_string());
map.insert(1usize, values[2].to_string());
let (key_r, value_r) = map.get_at_mut(1).expect("Item wasn't found");
let value = value_r
.try_downcast_mut::<String>()
.expect("Couldn't downcast to String");
let key = key_r
.try_downcast_ref::<usize>()
.expect("Couldn't downcast to usize");
assert_eq!(key, &1usize);
assert_eq!(value, &mut values[2].to_owned());
value.clone_from(&values[0].to_owned());
assert_eq!(
map.get(&1usize)
.expect("Item wasn't found")
.try_downcast_ref::<String>()
.expect("Couldn't downcast to String"),
&values[0].to_owned()
);
assert!(map.get_at(2).is_none());
}
#[test]
fn next_index_increment() {
let values = ["first", "last"];
let mut map = DynamicMap::default();
map.insert(0usize, values[0]);
map.insert(1usize, values[1]);
let mut iter = map.iter();
let size = iter.len();
for _ in 0..2 {
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
}
// When None we should no longer increase index
for _ in 0..2 {
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}
#[test]
fn remove() {
let mut map = DynamicMap::default();
map.insert(0, 0);
map.insert(1, 1);
assert_eq!(map.remove(&0).unwrap().try_downcast_ref(), Some(&0));
assert!(map.get(&0).is_none());
assert_eq!(map.get(&1).unwrap().try_downcast_ref(), Some(&1));
assert_eq!(map.remove(&1).unwrap().try_downcast_ref(), Some(&1));
assert!(map.get(&1).is_none());
assert!(map.remove(&1).is_none());
assert!(map.get(&1).is_none());
}
}

184
vendor/bevy_reflect/src/path/access.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
//! Representation for individual element accesses within a path.
use alloc::borrow::Cow;
use core::fmt;
use super::error::AccessErrorKind;
use crate::{AccessError, PartialReflect, ReflectKind, ReflectMut, ReflectRef, VariantType};
type InnerResult<T> = Result<T, AccessErrorKind>;
/// A singular element access within a path.
/// Multiple accesses can be combined into a [`ParsedPath`](super::ParsedPath).
///
/// Can be applied to a [`dyn Reflect`](crate::Reflect) to get a reference to the targeted element.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Access<'a> {
/// A name-based field access on a struct.
Field(Cow<'a, str>),
/// A index-based field access on a struct.
FieldIndex(usize),
/// An index-based access on a tuple.
TupleIndex(usize),
/// An index-based access on a list.
ListIndex(usize),
}
impl fmt::Display for Access<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Access::Field(field) => write!(f, ".{field}"),
Access::FieldIndex(index) => write!(f, "#{index}"),
Access::TupleIndex(index) => write!(f, ".{index}"),
Access::ListIndex(index) => write!(f, "[{index}]"),
}
}
}
impl<'a> Access<'a> {
/// Converts this into an "owned" value.
///
/// If the [`Access`] is of variant [`Field`](Access::Field),
/// the field's [`Cow<str>`] will be converted to its owned
/// counterpart, which doesn't require a reference.
pub fn into_owned(self) -> Access<'static> {
match self {
Self::Field(value) => Access::Field(Cow::Owned(value.into_owned())),
Self::FieldIndex(value) => Access::FieldIndex(value),
Self::TupleIndex(value) => Access::TupleIndex(value),
Self::ListIndex(value) => Access::ListIndex(value),
}
}
pub(super) fn element<'r>(
&self,
base: &'r dyn PartialReflect,
offset: Option<usize>,
) -> Result<&'r dyn PartialReflect, AccessError<'a>> {
self.element_inner(base)
.and_then(|opt| opt.ok_or(AccessErrorKind::MissingField(base.reflect_kind())))
.map_err(|err| err.with_access(self.clone(), offset))
}
fn element_inner<'r>(
&self,
base: &'r dyn PartialReflect,
) -> InnerResult<Option<&'r dyn PartialReflect>> {
use ReflectRef::*;
let invalid_variant =
|expected, actual| AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual };
match (self, base.reflect_ref()) {
(Self::Field(field), Struct(struct_ref)) => Ok(struct_ref.field(field.as_ref())),
(Self::Field(field), Enum(enum_ref)) => match enum_ref.variant_type() {
VariantType::Struct => Ok(enum_ref.field(field.as_ref())),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(&Self::FieldIndex(index), Struct(struct_ref)) => Ok(struct_ref.field_at(index)),
(&Self::FieldIndex(index), Enum(enum_ref)) => match enum_ref.variant_type() {
VariantType::Struct => Ok(enum_ref.field_at(index)),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(Self::Field(_) | Self::FieldIndex(_), actual) => {
Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Struct,
actual: actual.into(),
})
}
(&Self::TupleIndex(index), TupleStruct(tuple)) => Ok(tuple.field(index)),
(&Self::TupleIndex(index), Tuple(tuple)) => Ok(tuple.field(index)),
(&Self::TupleIndex(index), Enum(enum_ref)) => match enum_ref.variant_type() {
VariantType::Tuple => Ok(enum_ref.field_at(index)),
actual => Err(invalid_variant(VariantType::Tuple, actual)),
},
(Self::TupleIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Tuple,
actual: actual.into(),
}),
(&Self::ListIndex(index), List(list)) => Ok(list.get(index)),
(&Self::ListIndex(index), Array(list)) => Ok(list.get(index)),
(Self::ListIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::List,
actual: actual.into(),
}),
}
}
pub(super) fn element_mut<'r>(
&self,
base: &'r mut dyn PartialReflect,
offset: Option<usize>,
) -> Result<&'r mut dyn PartialReflect, AccessError<'a>> {
let kind = base.reflect_kind();
self.element_inner_mut(base)
.and_then(|maybe| maybe.ok_or(AccessErrorKind::MissingField(kind)))
.map_err(|err| err.with_access(self.clone(), offset))
}
fn element_inner_mut<'r>(
&self,
base: &'r mut dyn PartialReflect,
) -> InnerResult<Option<&'r mut dyn PartialReflect>> {
use ReflectMut::*;
let invalid_variant =
|expected, actual| AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual };
match (self, base.reflect_mut()) {
(Self::Field(field), Struct(struct_mut)) => Ok(struct_mut.field_mut(field.as_ref())),
(Self::Field(field), Enum(enum_mut)) => match enum_mut.variant_type() {
VariantType::Struct => Ok(enum_mut.field_mut(field.as_ref())),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(&Self::FieldIndex(index), Struct(struct_mut)) => Ok(struct_mut.field_at_mut(index)),
(&Self::FieldIndex(index), Enum(enum_mut)) => match enum_mut.variant_type() {
VariantType::Struct => Ok(enum_mut.field_at_mut(index)),
actual => Err(invalid_variant(VariantType::Struct, actual)),
},
(Self::Field(_) | Self::FieldIndex(_), actual) => {
Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Struct,
actual: actual.into(),
})
}
(&Self::TupleIndex(index), TupleStruct(tuple)) => Ok(tuple.field_mut(index)),
(&Self::TupleIndex(index), Tuple(tuple)) => Ok(tuple.field_mut(index)),
(&Self::TupleIndex(index), Enum(enum_mut)) => match enum_mut.variant_type() {
VariantType::Tuple => Ok(enum_mut.field_at_mut(index)),
actual => Err(invalid_variant(VariantType::Tuple, actual)),
},
(Self::TupleIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::Tuple,
actual: actual.into(),
}),
(&Self::ListIndex(index), List(list)) => Ok(list.get_mut(index)),
(&Self::ListIndex(index), Array(list)) => Ok(list.get_mut(index)),
(Self::ListIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
expected: ReflectKind::List,
actual: actual.into(),
}),
}
}
/// Returns a reference to this [`Access`]'s inner value as a [`&dyn Display`](fmt::Display).
pub fn display_value(&self) -> &dyn fmt::Display {
match self {
Self::Field(value) => value,
Self::FieldIndex(value) | Self::TupleIndex(value) | Self::ListIndex(value) => value,
}
}
pub(super) fn kind(&self) -> &'static str {
match self {
Self::Field(_) => "field",
Self::FieldIndex(_) => "field index",
Self::TupleIndex(_) | Self::ListIndex(_) => "index",
}
}
}

129
vendor/bevy_reflect/src/path/error.rs vendored Normal file
View File

@@ -0,0 +1,129 @@
use core::fmt;
use super::Access;
use crate::{ReflectKind, VariantType};
/// The kind of [`AccessError`], along with some kind-specific information.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AccessErrorKind {
/// An error that occurs when a certain type doesn't
/// contain the value referenced by the [`Access`].
MissingField(ReflectKind),
/// An error that occurs when using an [`Access`] on the wrong type.
/// (i.e. a [`ListIndex`](Access::ListIndex) on a struct, or a [`TupleIndex`](Access::TupleIndex) on a list)
IncompatibleTypes {
/// The [`ReflectKind`] that was expected based on the [`Access`].
expected: ReflectKind,
/// The actual [`ReflectKind`] that was found.
actual: ReflectKind,
},
/// An error that occurs when using an [`Access`] on the wrong enum variant.
/// (i.e. a [`ListIndex`](Access::ListIndex) on a struct variant, or a [`TupleIndex`](Access::TupleIndex) on a unit variant)
IncompatibleEnumVariantTypes {
/// The [`VariantType`] that was expected based on the [`Access`].
expected: VariantType,
/// The actual [`VariantType`] that was found.
actual: VariantType,
},
}
impl AccessErrorKind {
pub(super) fn with_access(self, access: Access, offset: Option<usize>) -> AccessError {
AccessError {
kind: self,
access,
offset,
}
}
}
/// An error originating from an [`Access`] of an element within a type.
///
/// Use the `Display` impl of this type to get information on the error.
///
/// Some sample messages:
///
/// ```text
/// Error accessing element with `.alpha` access (offset 14): The struct accessed doesn't have an "alpha" field
/// Error accessing element with '[0]' access: Expected index access to access a list, found a struct instead.
/// Error accessing element with '.4' access: Expected variant index access to access a Tuple variant, found a Unit variant instead.
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccessError<'a> {
pub(super) kind: AccessErrorKind,
pub(super) access: Access<'a>,
pub(super) offset: Option<usize>,
}
impl<'a> AccessError<'a> {
/// Returns the kind of [`AccessError`].
pub const fn kind(&self) -> &AccessErrorKind {
&self.kind
}
/// The returns the [`Access`] that this [`AccessError`] occurred in.
pub const fn access(&self) -> &Access {
&self.access
}
/// If the [`Access`] was created with a parser or an offset was manually provided,
/// returns the offset of the [`Access`] in its path string.
pub const fn offset(&self) -> Option<&usize> {
self.offset.as_ref()
}
}
impl fmt::Display for AccessError<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let AccessError {
kind,
access,
offset,
} = self;
write!(f, "Error accessing element with `{access}` access")?;
if let Some(offset) = offset {
write!(f, "(offset {offset})")?;
}
write!(f, ": ")?;
match kind {
AccessErrorKind::MissingField(type_accessed) => {
match access {
Access::Field(field) => write!(
f,
"The {type_accessed} accessed doesn't have {} `{}` field",
if let Some("a" | "e" | "i" | "o" | "u") = field.get(0..1) {
"an"
} else {
"a"
},
access.display_value()
),
Access::FieldIndex(_) => write!(
f,
"The {type_accessed} accessed doesn't have field index `{}`",
access.display_value(),
),
Access::TupleIndex(_) | Access::ListIndex(_) => write!(
f,
"The {type_accessed} accessed doesn't have index `{}`",
access.display_value()
)
}
}
AccessErrorKind::IncompatibleTypes { expected, actual } => write!(
f,
"Expected {} access to access a {expected}, found a {actual} instead.",
access.kind()
),
AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual } => write!(
f,
"Expected variant {} access to access a {expected:?} variant, found a {actual:?} variant instead.",
access.kind()
),
}
}
}
impl core::error::Error for AccessError<'_> {}

828
vendor/bevy_reflect/src/path/mod.rs vendored Normal file
View File

@@ -0,0 +1,828 @@
pub mod access;
pub use access::*;
mod error;
pub use error::*;
mod parse;
pub use parse::ParseError;
use parse::PathParser;
use crate::{PartialReflect, Reflect};
use alloc::vec::Vec;
use core::fmt;
use derive_more::derive::From;
use thiserror::Error;
type PathResult<'a, T> = Result<T, ReflectPathError<'a>>;
/// An error returned from a failed path string query.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum ReflectPathError<'a> {
/// An error caused by trying to access a path that's not able to be accessed,
/// see [`AccessError`] for details.
#[error(transparent)]
InvalidAccess(AccessError<'a>),
/// An error that occurs when a type cannot downcast to a given type.
#[error("Can't downcast result of access to the given type")]
InvalidDowncast,
/// An error caused by an invalid path string that couldn't be parsed.
#[error("Encountered an error at offset {offset} while parsing `{path}`: {error}")]
ParseError {
/// Position in `path`.
offset: usize,
/// The path that the error occurred in.
path: &'a str,
/// The underlying error.
error: ParseError<'a>,
},
}
impl<'a> From<AccessError<'a>> for ReflectPathError<'a> {
fn from(value: AccessError<'a>) -> Self {
ReflectPathError::InvalidAccess(value)
}
}
/// Something that can be interpreted as a reflection path in [`GetPath`].
pub trait ReflectPath<'a>: Sized {
/// Gets a reference to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::reflect_path`] for more details,
/// see [`element`](Self::element) if you want a typed return value.
fn reflect_element(self, root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect>;
/// Gets a mutable reference to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::reflect_path_mut`] for more details.
fn reflect_element_mut(
self,
root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect>;
/// Gets a `&T` to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::path`] for more details.
fn element<T: Reflect>(self, root: &dyn PartialReflect) -> PathResult<'a, &T> {
self.reflect_element(root).and_then(|p| {
p.try_downcast_ref::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
/// Gets a `&mut T` to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::path_mut`] for more details.
fn element_mut<T: Reflect>(self, root: &mut dyn PartialReflect) -> PathResult<'a, &mut T> {
self.reflect_element_mut(root).and_then(|p| {
p.try_downcast_mut::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
}
impl<'a> ReflectPath<'a> for &'a str {
fn reflect_element(self, mut root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect> {
for (access, offset) in PathParser::new(self) {
let a = access?;
root = a.element(root, Some(offset))?;
}
Ok(root)
}
fn reflect_element_mut(
self,
mut root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect> {
for (access, offset) in PathParser::new(self) {
root = access?.element_mut(root, Some(offset))?;
}
Ok(root)
}
}
/// A trait which allows nested [`Reflect`] values to be retrieved with path strings.
///
/// Using these functions repeatedly with the same string requires parsing the string every time.
/// To avoid this cost, it's recommended to construct a [`ParsedPath`] instead.
///
/// # Syntax
///
/// ## Structs
///
/// Field paths for [`Struct`] elements use the standard Rust field access syntax of
/// dot and field name: `.field_name`.
///
/// Additionally, struct fields may be accessed by their index within the struct's definition.
/// This is accomplished by using the hash symbol (`#`) in place of the standard dot: `#0`.
///
/// Accessing a struct's field by index can speed up fetches at runtime due to the removed
/// need for string matching.
/// And while this can be more performant, it's best to keep in mind the tradeoffs when
/// utilizing such optimizations.
/// For example, this can result in fairly fragile code as the string paths will need to be
/// kept in sync with the struct definitions since the order of fields could be easily changed.
/// Because of this, storing these kinds of paths in persistent storage (i.e. game assets)
/// is strongly discouraged.
///
/// Note that a leading dot (`.`) or hash (`#`) token is implied for the first item in a path,
/// and may therefore be omitted.
///
/// Additionally, an empty path may be used to get the struct itself.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect, PartialEq, Debug)]
/// struct MyStruct {
/// value: u32
/// }
///
/// let my_struct = MyStruct { value: 123 };
/// // Access via field name
/// assert_eq!(my_struct.path::<u32>(".value").unwrap(), &123);
/// // Access via field index
/// assert_eq!(my_struct.path::<u32>("#0").unwrap(), &123);
/// // Access self
/// assert_eq!(*my_struct.path::<MyStruct>("").unwrap(), my_struct);
/// ```
///
/// ## Tuples and Tuple Structs
///
/// [`Tuple`] and [`TupleStruct`] elements also follow a conventional Rust syntax.
/// Fields are accessed with a dot and the field index: `.0`.
///
/// Note that a leading dot (`.`) token is implied for the first item in a path,
/// and may therefore be omitted.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect)]
/// struct MyTupleStruct(u32);
///
/// let my_tuple_struct = MyTupleStruct(123);
/// assert_eq!(my_tuple_struct.path::<u32>(".0").unwrap(), &123);
/// ```
///
/// ## Lists and Arrays
///
/// [`List`] and [`Array`] elements are accessed with brackets: `[0]`.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath};
/// let my_list: Vec<u32> = vec![1, 2, 3];
/// assert_eq!(my_list.path::<u32>("[2]").unwrap(), &3);
/// ```
///
/// ## Enums
///
/// Pathing for [`Enum`] elements works a bit differently than in normal Rust.
/// Usually, you would need to pattern match an enum, branching off on the desired variants.
/// Paths used by this trait do not have any pattern matching capabilities;
/// instead, they assume the variant is already known ahead of time.
///
/// The syntax used, therefore, depends on the variant being accessed:
/// - Struct variants use the struct syntax (outlined above)
/// - Tuple variants use the tuple syntax (outlined above)
/// - Unit variants have no fields to access
///
/// If the variant cannot be known ahead of time, the path will need to be split up
/// and proper enum pattern matching will need to be handled manually.
///
/// ### Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect)]
/// enum MyEnum {
/// Unit,
/// Tuple(bool),
/// Struct {
/// value: u32
/// }
/// }
///
/// let tuple_variant = MyEnum::Tuple(true);
/// assert_eq!(tuple_variant.path::<bool>(".0").unwrap(), &true);
///
/// let struct_variant = MyEnum::Struct { value: 123 };
/// // Access via field name
/// assert_eq!(struct_variant.path::<u32>(".value").unwrap(), &123);
/// // Access via field index
/// assert_eq!(struct_variant.path::<u32>("#0").unwrap(), &123);
///
/// // Error: Expected struct variant
/// assert!(matches!(tuple_variant.path::<u32>(".value"), Err(_)));
/// ```
///
/// # Chaining
///
/// Using the aforementioned syntax, path items may be chained one after another
/// to create a full path to a nested element.
///
/// ## Example
/// ```
/// # use bevy_reflect::{GetPath, Reflect};
/// #[derive(Reflect)]
/// struct MyStruct {
/// value: Vec<Option<u32>>
/// }
///
/// let my_struct = MyStruct {
/// value: vec![None, None, Some(123)],
/// };
/// assert_eq!(
/// my_struct.path::<u32>(".value[2].0").unwrap(),
/// &123,
/// );
/// ```
///
/// [`Struct`]: crate::Struct
/// [`Tuple`]: crate::Tuple
/// [`TupleStruct`]: crate::TupleStruct
/// [`List`]: crate::List
/// [`Array`]: crate::Array
/// [`Enum`]: crate::Enum
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `GetPath` so cannot be accessed by reflection path",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetPath: PartialReflect {
/// Returns a reference to the value specified by `path`.
///
/// To retrieve a statically typed reference, use
/// [`path`][GetPath::path].
fn reflect_path<'p>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &dyn PartialReflect> {
path.reflect_element(self.as_partial_reflect())
}
/// Returns a mutable reference to the value specified by `path`.
///
/// To retrieve a statically typed mutable reference, use
/// [`path_mut`][GetPath::path_mut].
fn reflect_path_mut<'p>(
&mut self,
path: impl ReflectPath<'p>,
) -> PathResult<'p, &mut dyn PartialReflect> {
path.reflect_element_mut(self.as_partial_reflect_mut())
}
/// Returns a statically typed reference to the value specified by `path`.
///
/// This will automatically handle downcasting to type `T`.
/// The downcast will fail if this value is not of type `T`
/// (which may be the case when using dynamic types like [`DynamicStruct`]).
///
/// [`DynamicStruct`]: crate::DynamicStruct
fn path<'p, T: Reflect>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &T> {
path.element(self.as_partial_reflect())
}
/// Returns a statically typed mutable reference to the value specified by `path`.
///
/// This will automatically handle downcasting to type `T`.
/// The downcast will fail if this value is not of type `T`
/// (which may be the case when using dynamic types like [`DynamicStruct`]).
///
/// [`DynamicStruct`]: crate::DynamicStruct
fn path_mut<'p, T: Reflect>(&mut self, path: impl ReflectPath<'p>) -> PathResult<'p, &mut T> {
path.element_mut(self.as_partial_reflect_mut())
}
}
// Implement `GetPath` for `dyn Reflect`
impl<T: Reflect + ?Sized> GetPath for T {}
/// An [`Access`] combined with an `offset` for more helpful error reporting.
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct OffsetAccess {
/// The [`Access`] itself.
pub access: Access<'static>,
/// A character offset in the string the path was parsed from.
pub offset: Option<usize>,
}
impl From<Access<'static>> for OffsetAccess {
fn from(access: Access<'static>) -> Self {
OffsetAccess {
access,
offset: None,
}
}
}
/// A pre-parsed path to an element within a type.
///
/// This struct can be constructed manually from its [`Access`]es or with
/// the [parse](ParsedPath::parse) method.
///
/// This struct may be used like [`GetPath`] but removes the cost of parsing the path
/// string at each element access.
///
/// It's recommended to use this in place of [`GetPath`] when the path string is
/// unlikely to be changed and will be accessed repeatedly.
///
/// ## Examples
///
/// Parsing a [`&'static str`](str):
/// ```
/// # use bevy_reflect::ParsedPath;
/// let my_static_string: &'static str = "bar#0.1[2].0";
/// // Breakdown:
/// // "bar" - Access struct field named "bar"
/// // "#0" - Access struct field at index 0
/// // ".1" - Access tuple struct field at index 1
/// // "[2]" - Access list element at index 2
/// // ".0" - Access tuple variant field at index 0
/// let my_path = ParsedPath::parse_static(my_static_string);
/// ```
/// Parsing a non-static [`&str`](str):
/// ```
/// # use bevy_reflect::ParsedPath;
/// let my_string = String::from("bar#0.1[2].0");
/// // Breakdown:
/// // "bar" - Access struct field named "bar"
/// // "#0" - Access struct field at index 0
/// // ".1" - Access tuple struct field at index 1
/// // "[2]" - Access list element at index 2
/// // ".0" - Access tuple variant field at index 0
/// let my_path = ParsedPath::parse(&my_string);
/// ```
/// Manually constructing a [`ParsedPath`]:
/// ```
/// # use std::borrow::Cow;
/// # use bevy_reflect::access::Access;
/// # use bevy_reflect::ParsedPath;
/// let path_elements = [
/// Access::Field(Cow::Borrowed("bar")),
/// Access::FieldIndex(0),
/// Access::TupleIndex(1),
/// Access::ListIndex(2),
/// Access::TupleIndex(1),
/// ];
/// let my_path = ParsedPath::from(path_elements);
/// ```
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, From)]
pub struct ParsedPath(
/// This is a vector of pre-parsed [`OffsetAccess`]es.
pub Vec<OffsetAccess>,
);
impl ParsedPath {
/// Parses a [`ParsedPath`] from a string.
///
/// Returns an error if the string does not represent a valid path to an element.
///
/// The exact format for path strings can be found in the documentation for [`GetPath`].
/// In short, though, a path consists of one or more chained accessor strings.
/// These are:
/// - Named field access (`.field`)
/// - Unnamed field access (`.1`)
/// - Field index access (`#0`)
/// - Sequence access (`[2]`)
///
/// # Example
/// ```
/// # use bevy_reflect::{ParsedPath, Reflect, ReflectPath};
/// #[derive(Reflect)]
/// struct Foo {
/// bar: Bar,
/// }
///
/// #[derive(Reflect)]
/// struct Bar {
/// baz: Baz,
/// }
///
/// #[derive(Reflect)]
/// struct Baz(f32, Vec<Option<u32>>);
///
/// let foo = Foo {
/// bar: Bar {
/// baz: Baz(3.14, vec![None, None, Some(123)])
/// },
/// };
///
/// let parsed_path = ParsedPath::parse("bar#0.1[2].0").unwrap();
/// // Breakdown:
/// // "bar" - Access struct field named "bar"
/// // "#0" - Access struct field at index 0
/// // ".1" - Access tuple struct field at index 1
/// // "[2]" - Access list element at index 2
/// // ".0" - Access tuple variant field at index 0
///
/// assert_eq!(parsed_path.element::<u32>(&foo).unwrap(), &123);
/// ```
pub fn parse(string: &str) -> PathResult<Self> {
let mut parts = Vec::new();
for (access, offset) in PathParser::new(string) {
parts.push(OffsetAccess {
access: access?.into_owned(),
offset: Some(offset),
});
}
Ok(Self(parts))
}
/// Similar to [`Self::parse`] but only works on `&'static str`
/// and does not allocate per named field.
pub fn parse_static(string: &'static str) -> PathResult<'static, Self> {
let mut parts = Vec::new();
for (access, offset) in PathParser::new(string) {
parts.push(OffsetAccess {
access: access?,
offset: Some(offset),
});
}
Ok(Self(parts))
}
}
impl<'a> ReflectPath<'a> for &'a ParsedPath {
fn reflect_element(self, mut root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect> {
for OffsetAccess { access, offset } in &self.0 {
root = access.element(root, *offset)?;
}
Ok(root)
}
fn reflect_element_mut(
self,
mut root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect> {
for OffsetAccess { access, offset } in &self.0 {
root = access.element_mut(root, *offset)?;
}
Ok(root)
}
}
impl<const N: usize> From<[OffsetAccess; N]> for ParsedPath {
fn from(value: [OffsetAccess; N]) -> Self {
ParsedPath(value.to_vec())
}
}
impl From<Vec<Access<'static>>> for ParsedPath {
fn from(value: Vec<Access<'static>>) -> Self {
ParsedPath(
value
.into_iter()
.map(|access| OffsetAccess {
access,
offset: None,
})
.collect(),
)
}
}
impl<const N: usize> From<[Access<'static>; N]> for ParsedPath {
fn from(value: [Access<'static>; N]) -> Self {
value.to_vec().into()
}
}
impl<'a> TryFrom<&'a str> for ParsedPath {
type Error = ReflectPathError<'a>;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
ParsedPath::parse(value)
}
}
impl fmt::Display for ParsedPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for OffsetAccess { access, .. } in &self.0 {
write!(f, "{access}")?;
}
Ok(())
}
}
impl core::ops::Index<usize> for ParsedPath {
type Output = OffsetAccess;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl core::ops::IndexMut<usize> for ParsedPath {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
#[cfg(test)]
#[expect(
clippy::approx_constant,
reason = "We don't need the exact value of Pi here."
)]
mod tests {
use super::*;
use crate::*;
use alloc::vec;
#[derive(Reflect, PartialEq, Debug)]
struct A {
w: usize,
x: B,
y: Vec<C>,
z: D,
unit_variant: F,
tuple_variant: F,
struct_variant: F,
array: [i32; 3],
tuple: (bool, f32),
}
#[derive(Reflect, PartialEq, Debug)]
struct B {
foo: usize,
łø: C,
}
#[derive(Reflect, PartialEq, Debug)]
struct C {
mосква: f32,
}
#[derive(Reflect, PartialEq, Debug)]
struct D(E);
#[derive(Reflect, PartialEq, Debug)]
struct E(f32, usize);
#[derive(Reflect, PartialEq, Debug)]
enum F {
Unit,
Tuple(u32, u32),
Şķràźÿ { : char },
}
fn a_sample() -> A {
A {
w: 1,
x: B {
foo: 10,
łø: C { mосква: 3.14 },
},
y: vec![C { mосква: 1.0 }, C { mосква: 2.0 }],
z: D(E(10.0, 42)),
unit_variant: F::Unit,
tuple_variant: F::Tuple(123, 321),
struct_variant: F::Şķràźÿ { : 'm' },
array: [86, 75, 309],
tuple: (true, 1.23),
}
}
fn offset(access: Access<'static>, offset: usize) -> OffsetAccess {
OffsetAccess {
access,
offset: Some(offset),
}
}
fn access_field(field: &'static str) -> Access<'static> {
Access::Field(field.into())
}
type StaticError = ReflectPathError<'static>;
fn invalid_access(
offset: usize,
actual: ReflectKind,
expected: ReflectKind,
access: &'static str,
) -> StaticError {
ReflectPathError::InvalidAccess(AccessError {
kind: AccessErrorKind::IncompatibleTypes { actual, expected },
access: ParsedPath::parse_static(access).unwrap()[1].access.clone(),
offset: Some(offset),
})
}
#[test]
fn try_from() {
assert_eq!(
ParsedPath::try_from("w").unwrap().0,
&[offset(access_field("w"), 1)]
);
let r = ParsedPath::try_from("w[");
let matches = matches!(r, Err(ReflectPathError::ParseError { .. }));
assert!(
matches,
"ParsedPath::try_from did not return a ParseError for \"w[\""
);
}
#[test]
fn parsed_path_parse() {
assert_eq!(
ParsedPath::parse("w").unwrap().0,
&[offset(access_field("w"), 1)]
);
assert_eq!(
ParsedPath::parse("x.foo").unwrap().0,
&[offset(access_field("x"), 1), offset(access_field("foo"), 2)]
);
assert_eq!(
ParsedPath::parse("x.łørđ.mосква").unwrap().0,
&[
offset(access_field("x"), 1),
offset(access_field("łørđ"), 2),
offset(access_field("mосква"), 10)
]
);
assert_eq!(
ParsedPath::parse("y[1].mосква").unwrap().0,
&[
offset(access_field("y"), 1),
offset(Access::ListIndex(1), 2),
offset(access_field("mосква"), 5)
]
);
assert_eq!(
ParsedPath::parse("z.0.1").unwrap().0,
&[
offset(access_field("z"), 1),
offset(Access::TupleIndex(0), 2),
offset(Access::TupleIndex(1), 4),
]
);
assert_eq!(
ParsedPath::parse("x#0").unwrap().0,
&[
offset(access_field("x"), 1),
offset(Access::FieldIndex(0), 2)
]
);
assert_eq!(
ParsedPath::parse("x#0#1").unwrap().0,
&[
offset(access_field("x"), 1),
offset(Access::FieldIndex(0), 2),
offset(Access::FieldIndex(1), 4)
]
);
}
#[test]
fn parsed_path_get_field() {
let a = a_sample();
let b = ParsedPath::parse("w").unwrap();
let c = ParsedPath::parse("x.foo").unwrap();
let d = ParsedPath::parse("x.łørđ.mосква").unwrap();
let e = ParsedPath::parse("y[1].mосква").unwrap();
let f = ParsedPath::parse("z.0.1").unwrap();
let g = ParsedPath::parse("x#0").unwrap();
let h = ParsedPath::parse("x#1#0").unwrap();
let i = ParsedPath::parse("unit_variant").unwrap();
let j = ParsedPath::parse("tuple_variant.1").unwrap();
let k = ParsedPath::parse("struct_variant.東京").unwrap();
let l = ParsedPath::parse("struct_variant#0").unwrap();
let m = ParsedPath::parse("array[2]").unwrap();
let n = ParsedPath::parse("tuple.1").unwrap();
for _ in 0..30 {
assert_eq!(*b.element::<usize>(&a).unwrap(), 1);
assert_eq!(*c.element::<usize>(&a).unwrap(), 10);
assert_eq!(*d.element::<f32>(&a).unwrap(), 3.14);
assert_eq!(*e.element::<f32>(&a).unwrap(), 2.0);
assert_eq!(*f.element::<usize>(&a).unwrap(), 42);
assert_eq!(*g.element::<usize>(&a).unwrap(), 10);
assert_eq!(*h.element::<f32>(&a).unwrap(), 3.14);
assert_eq!(*i.element::<F>(&a).unwrap(), F::Unit);
assert_eq!(*j.element::<u32>(&a).unwrap(), 321);
assert_eq!(*k.element::<char>(&a).unwrap(), 'm');
assert_eq!(*l.element::<char>(&a).unwrap(), 'm');
assert_eq!(*m.element::<i32>(&a).unwrap(), 309);
assert_eq!(*n.element::<f32>(&a).unwrap(), 1.23);
}
}
#[test]
fn reflect_array_behaves_like_list() {
#[derive(Reflect)]
struct A {
list: Vec<u8>,
array: [u8; 10],
}
let a = A {
list: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
};
assert_eq!(*a.path::<u8>("list[5]").unwrap(), 5);
assert_eq!(*a.path::<u8>("array[5]").unwrap(), 5);
assert_eq!(*a.path::<u8>("list[0]").unwrap(), 0);
assert_eq!(*a.path::<u8>("array[0]").unwrap(), 0);
}
#[test]
fn reflect_array_behaves_like_list_mut() {
#[derive(Reflect)]
struct A {
list: Vec<u8>,
array: [u8; 10],
}
let mut a = A {
list: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
};
assert_eq!(*a.path_mut::<u8>("list[5]").unwrap(), 5);
assert_eq!(*a.path_mut::<u8>("array[5]").unwrap(), 5);
*a.path_mut::<u8>("list[5]").unwrap() = 10;
*a.path_mut::<u8>("array[5]").unwrap() = 10;
assert_eq!(*a.path_mut::<u8>("list[5]").unwrap(), 10);
assert_eq!(*a.path_mut::<u8>("array[5]").unwrap(), 10);
}
#[test]
fn reflect_path() {
let mut a = a_sample();
assert_eq!(*a.path::<A>("").unwrap(), a);
assert_eq!(*a.path::<usize>("w").unwrap(), 1);
assert_eq!(*a.path::<usize>("x.foo").unwrap(), 10);
assert_eq!(*a.path::<f32>("x.łørđ.mосква").unwrap(), 3.14);
assert_eq!(*a.path::<f32>("y[1].mосква").unwrap(), 2.0);
assert_eq!(*a.path::<usize>("z.0.1").unwrap(), 42);
assert_eq!(*a.path::<usize>("x#0").unwrap(), 10);
assert_eq!(*a.path::<f32>("x#1#0").unwrap(), 3.14);
assert_eq!(*a.path::<F>("unit_variant").unwrap(), F::Unit);
assert_eq!(*a.path::<u32>("tuple_variant.1").unwrap(), 321);
assert_eq!(*a.path::<char>("struct_variant.東京").unwrap(), 'm');
assert_eq!(*a.path::<char>("struct_variant#0").unwrap(), 'm');
assert_eq!(*a.path::<i32>("array[2]").unwrap(), 309);
assert_eq!(*a.path::<f32>("tuple.1").unwrap(), 1.23);
*a.path_mut::<f32>("tuple.1").unwrap() = 3.21;
assert_eq!(*a.path::<f32>("tuple.1").unwrap(), 3.21);
*a.path_mut::<f32>("y[1].mосква").unwrap() = 3.0;
assert_eq!(a.y[1].mосква, 3.0);
*a.path_mut::<u32>("tuple_variant.0").unwrap() = 1337;
assert_eq!(a.tuple_variant, F::Tuple(1337, 321));
assert_eq!(
a.reflect_path("x.notreal").err().unwrap(),
ReflectPathError::InvalidAccess(AccessError {
kind: AccessErrorKind::MissingField(ReflectKind::Struct),
access: access_field("notreal"),
offset: Some(2),
})
);
assert_eq!(
a.reflect_path("unit_variant.0").err().unwrap(),
ReflectPathError::InvalidAccess(AccessError {
kind: AccessErrorKind::IncompatibleEnumVariantTypes {
actual: VariantType::Unit,
expected: VariantType::Tuple,
},
access: ParsedPath::parse_static("unit_variant.0").unwrap()[1]
.access
.clone(),
offset: Some(13),
})
);
assert_eq!(
a.reflect_path("x[0]").err().unwrap(),
invalid_access(2, ReflectKind::Struct, ReflectKind::List, "x[0]")
);
assert_eq!(
a.reflect_path("y.x").err().unwrap(),
invalid_access(2, ReflectKind::List, ReflectKind::Struct, "y.x")
);
}
#[test]
fn accept_leading_tokens() {
assert_eq!(
ParsedPath::parse(".w").unwrap().0,
&[offset(access_field("w"), 1)]
);
assert_eq!(
ParsedPath::parse("#0.foo").unwrap().0,
&[
offset(Access::FieldIndex(0), 1),
offset(access_field("foo"), 3)
]
);
assert_eq!(
ParsedPath::parse(".5").unwrap().0,
&[offset(Access::TupleIndex(5), 1)]
);
assert_eq!(
ParsedPath::parse("[0].łørđ").unwrap().0,
&[
offset(Access::ListIndex(0), 1),
offset(access_field("łørđ"), 4)
]
);
}
}

200
vendor/bevy_reflect/src/path/parse.rs vendored Normal file
View File

@@ -0,0 +1,200 @@
use core::{
fmt::{self, Write},
num::ParseIntError,
str::from_utf8_unchecked,
};
use thiserror::Error;
use super::{Access, ReflectPathError};
/// An error that occurs when parsing reflect path strings.
#[derive(Debug, PartialEq, Eq, Error)]
#[error(transparent)]
pub struct ParseError<'a>(Error<'a>);
/// A parse error for a path string.
#[derive(Debug, PartialEq, Eq, Error)]
enum Error<'a> {
#[error("expected an identifier, but reached end of path string")]
NoIdent,
#[error("expected an identifier, got '{0}' instead")]
ExpectedIdent(Token<'a>),
#[error("failed to parse index as integer")]
InvalidIndex(#[from] ParseIntError),
#[error("a '[' wasn't closed, reached end of path string before finding a ']'")]
Unclosed,
#[error("a '[' wasn't closed properly, got '{0}' instead")]
BadClose(Token<'a>),
#[error("a ']' was found before an opening '['")]
CloseBeforeOpen,
}
pub(super) struct PathParser<'a> {
path: &'a str,
remaining: &'a [u8],
}
impl<'a> PathParser<'a> {
pub(super) fn new(path: &'a str) -> Self {
let remaining = path.as_bytes();
PathParser { path, remaining }
}
fn next_token(&mut self) -> Option<Token<'a>> {
let to_parse = self.remaining;
// Return with `None` if empty.
let (first_byte, remaining) = to_parse.split_first()?;
if let Some(token) = Token::symbol_from_byte(*first_byte) {
self.remaining = remaining; // NOTE: all symbols are ASCII
return Some(token);
}
// We are parsing either `0123` or `field`.
// If we do not find a subsequent token, we are at the end of the parse string.
let ident_len = to_parse.iter().position(|t| Token::SYMBOLS.contains(t));
let (ident, remaining) = to_parse.split_at(ident_len.unwrap_or(to_parse.len()));
// SAFETY: This relies on `self.remaining` always remaining valid UTF8:
// - self.remaining is a slice derived from self.path (valid &str)
// - The slice's end is either the same as the valid &str or
// the last byte before an ASCII utf-8 character (ie: it is a char
// boundary).
// - The slice always starts after a symbol ie: an ASCII character's boundary.
#[expect(
unsafe_code,
reason = "We have fulfilled the Safety requirements for `from_utf8_unchecked`."
)]
let ident = unsafe { from_utf8_unchecked(ident) };
self.remaining = remaining;
Some(Token::Ident(Ident(ident)))
}
fn next_ident(&mut self) -> Result<Ident<'a>, Error<'a>> {
match self.next_token() {
Some(Token::Ident(ident)) => Ok(ident),
Some(other) => Err(Error::ExpectedIdent(other)),
None => Err(Error::NoIdent),
}
}
fn access_following(&mut self, token: Token<'a>) -> Result<Access<'a>, Error<'a>> {
match token {
Token::Dot => Ok(self.next_ident()?.field()),
Token::Pound => self.next_ident()?.field_index(),
Token::Ident(ident) => Ok(ident.field()),
Token::CloseBracket => Err(Error::CloseBeforeOpen),
Token::OpenBracket => {
let index_ident = self.next_ident()?.list_index()?;
match self.next_token() {
Some(Token::CloseBracket) => Ok(index_ident),
Some(other) => Err(Error::BadClose(other)),
None => Err(Error::Unclosed),
}
}
}
}
fn offset(&self) -> usize {
self.path.len() - self.remaining.len()
}
}
impl<'a> Iterator for PathParser<'a> {
type Item = (Result<Access<'a>, ReflectPathError<'a>>, usize);
fn next(&mut self) -> Option<Self::Item> {
let token = self.next_token()?;
let offset = self.offset();
Some((
self.access_following(token)
.map_err(|error| ReflectPathError::ParseError {
offset,
path: self.path,
error: ParseError(error),
}),
offset,
))
}
}
#[derive(Debug, PartialEq, Eq)]
struct Ident<'a>(&'a str);
impl<'a> Ident<'a> {
fn field(self) -> Access<'a> {
let field = |_| Access::Field(self.0.into());
self.0.parse().map(Access::TupleIndex).unwrap_or_else(field)
}
fn field_index(self) -> Result<Access<'a>, Error<'a>> {
Ok(Access::FieldIndex(self.0.parse()?))
}
fn list_index(self) -> Result<Access<'a>, Error<'a>> {
Ok(Access::ListIndex(self.0.parse()?))
}
}
// NOTE: We use repr(u8) so that the `match byte` in `Token::symbol_from_byte`
// becomes a "check `byte` is one of SYMBOLS and forward its value" this makes
// the optimizer happy, and shaves off a few cycles.
#[derive(Debug, PartialEq, Eq)]
#[repr(u8)]
enum Token<'a> {
Dot = b'.',
Pound = b'#',
OpenBracket = b'[',
CloseBracket = b']',
Ident(Ident<'a>),
}
impl fmt::Display for Token<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Token::Dot => f.write_char('.'),
Token::Pound => f.write_char('#'),
Token::OpenBracket => f.write_char('['),
Token::CloseBracket => f.write_char(']'),
Token::Ident(ident) => f.write_str(ident.0),
}
}
}
impl<'a> Token<'a> {
const SYMBOLS: &'static [u8] = b".#[]";
fn symbol_from_byte(byte: u8) -> Option<Self> {
match byte {
b'.' => Some(Self::Dot),
b'#' => Some(Self::Pound),
b'[' => Some(Self::OpenBracket),
b']' => Some(Self::CloseBracket),
_ => None,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::path::ParsedPath;
#[test]
fn parse_invalid() {
assert_eq!(
ParsedPath::parse_static("x.."),
Err(ReflectPathError::ParseError {
error: ParseError(Error::ExpectedIdent(Token::Dot)),
offset: 2,
path: "x..",
}),
);
assert!(matches!(
ParsedPath::parse_static("y[badindex]"),
Err(ReflectPathError::ParseError {
error: ParseError(Error::InvalidIndex(_)),
offset: 2,
path: "y[badindex]",
}),
));
}
}

644
vendor/bevy_reflect/src/reflect.rs vendored Normal file
View File

@@ -0,0 +1,644 @@
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;
/// A enumeration of all error outcomes that might happen when running [`try_apply`](PartialReflect::try_apply).
#[derive(Error, Debug)]
pub enum ApplyError {
#[error("attempted to apply `{from_kind}` to `{to_kind}`")]
/// Attempted to apply the wrong [kind](ReflectKind) to a type, e.g. a struct to an enum.
MismatchedKinds {
from_kind: ReflectKind,
to_kind: ReflectKind,
},
#[error("enum variant `{variant_name}` doesn't have a field named `{field_name}`")]
/// Enum variant that we tried to apply to was missing a field.
MissingEnumField {
variant_name: Box<str>,
field_name: Box<str>,
},
#[error("`{from_type}` is not `{to_type}`")]
/// Tried to apply incompatible types.
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")]
/// Attempted to apply to types with mismatched sizes, e.g. a [u8; 4] to [u8; 3].
DifferentSize { from_size: usize, to_size: usize },
#[error("variant with name `{variant_name}` does not exist on enum `{enum_name}`")]
/// The enum we tried to apply to didn't contain a variant with the give 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,
}
}
}
/// The foundational trait of [`bevy_reflect`], used for accessing and modifying data dynamically.
///
/// This is a supertrait of [`Reflect`],
/// meaning any type which implements `Reflect` implements `PartialReflect` by definition.
///
/// It's recommended to use [the derive macro for `Reflect`] rather than manually implementing this trait.
/// Doing so will automatically implement this trait as well as many other useful traits for reflection,
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
///
/// See the [crate-level documentation] to see how this trait and its subtraits can be used.
///
/// [`bevy_reflect`]: crate
/// [the derive macro for `Reflect`]: bevy_reflect_derive::Reflect
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Enum`]: crate::Enum
/// [crate-level documentation]: crate
#[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
// NB: we don't use `Self: Any` since for downcasting, `Reflect` should be used.
Self: 'static,
{
/// Returns the [`TypeInfo`] of the type _represented_ by this value.
///
/// For most types, this will simply return their own `TypeInfo`.
/// However, for dynamic types, such as [`DynamicStruct`] or [`DynamicList`],
/// this will return the type they represent
/// (or `None` if they don't represent any particular type).
///
/// This method is great if you have an instance of a type or a `dyn Reflect`,
/// and want to access its [`TypeInfo`]. However, if this method is to be called
/// frequently, consider using [`TypeRegistry::get_type_info`] as it can be more
/// performant for such use cases.
///
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>;
/// Casts this type to a boxed, reflected value.
///
/// This is useful for coercing trait objects.
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect>;
/// Casts this type to a reflected value.
///
/// This is useful for coercing trait objects.
fn as_partial_reflect(&self) -> &dyn PartialReflect;
/// Casts this type to a mutable, reflected value.
///
/// This is useful for coercing trait objects.
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect;
/// Attempts to cast this type to a boxed, [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>;
/// Attempts to cast this type to a [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_as_reflect(&self) -> Option<&dyn Reflect>;
/// Attempts to cast this type to a mutable, [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect>;
/// Applies a reflected value to this value.
///
/// If a type implements an [introspection subtrait], then the semantics of this
/// method are as follows:
/// - If `T` is a [`Struct`], then the value of each named field of `value` is
/// applied to the corresponding named field of `self`. Fields which are
/// not present in both structs are ignored.
/// - If `T` is a [`TupleStruct`] or [`Tuple`], then the value of each
/// numbered field is applied to the corresponding numbered field of
/// `self.` Fields which are not present in both values are ignored.
/// - If `T` is an [`Enum`], then the variant of `self` is `updated` to match
/// the variant of `value`. The corresponding fields of that variant are
/// applied from `value` onto `self`. Fields which are not present in both
/// values are ignored.
/// - If `T` is a [`List`] or [`Array`], then each element of `value` is applied
/// to the corresponding element of `self`. Up to `self.len()` items are applied,
/// and excess elements in `value` are appended to `self`.
/// - If `T` is a [`Map`], then for each key in `value`, the associated
/// value is applied to the value associated with the same key in `self`.
/// Keys which are not present in `self` are inserted.
/// - If `T` is none of these, then `value` is downcast to `T`, cloned, and
/// assigned to `self`.
///
/// Note that `Reflect` must be implemented manually for [`List`]s and
/// [`Map`]s in order to achieve the correct semantics, as derived
/// implementations will have the semantics for [`Struct`], [`TupleStruct`], [`Enum`]
/// or none of the above depending on the kind of type. For lists and maps, use the
/// [`list_apply`] and [`map_apply`] helper functions when implementing this method.
///
/// [introspection subtrait]: crate#the-introspection-subtraits
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Tuple`]: crate::Tuple
/// [`Enum`]: crate::Enum
/// [`List`]: crate::List
/// [`Array`]: crate::Array
/// [`Map`]: crate::Map
/// [`list_apply`]: crate::list_apply
/// [`map_apply`]: crate::map_apply
///
/// # Panics
///
/// Derived implementations of this method will panic:
/// - If the type of `value` is not of the same kind as `T` (e.g. if `T` is
/// a `List`, while `value` is a `Struct`).
/// - If `T` is any complex type and the corresponding fields or elements of
/// `self` and `value` are not of the same type.
/// - If `T` is an opaque type and `self` cannot be downcast to `T`
fn apply(&mut self, value: &dyn PartialReflect) {
PartialReflect::try_apply(self, value).unwrap();
}
/// Tries to [`apply`](PartialReflect::apply) a reflected value to this value.
///
/// Functions the same as the [`apply`](PartialReflect::apply) function but returns an error instead of
/// panicking.
///
/// # Handling Errors
///
/// This function may leave `self` in a partially mutated state if a error was encountered on the way.
/// consider maintaining a cloned instance of this data you can switch to if a error is encountered.
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError>;
/// Returns a zero-sized enumeration of "kinds" of type.
///
/// See [`ReflectKind`].
fn reflect_kind(&self) -> ReflectKind {
self.reflect_ref().kind()
}
/// Returns an immutable enumeration of "kinds" of type.
///
/// See [`ReflectRef`].
fn reflect_ref(&self) -> ReflectRef;
/// Returns a mutable enumeration of "kinds" of type.
///
/// See [`ReflectMut`].
fn reflect_mut(&mut self) -> ReflectMut;
/// Returns an owned enumeration of "kinds" of type.
///
/// See [`ReflectOwned`].
fn reflect_owned(self: Box<Self>) -> ReflectOwned;
/// Clones `Self` into its dynamic representation.
///
/// For value types or types marked with `#[reflect_value]`,
/// this will simply return a clone of `Self`.
///
/// Otherwise the associated dynamic type will be returned.
///
/// For example, a [`List`] type will invoke [`List::clone_dynamic`], returning [`DynamicList`].
/// A [`Struct`] type will invoke [`Struct::clone_dynamic`], returning [`DynamicStruct`].
/// And so on.
///
/// If the dynamic behavior is not desired, a concrete clone can be obtained using [`PartialReflect::reflect_clone`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::{PartialReflect};
/// let value = (1, true, 3.14);
/// let cloned = value.clone_value();
/// assert!(cloned.is_dynamic())
/// ```
///
/// [`List`]: crate::List
/// [`List::clone_dynamic`]: crate::List::clone_dynamic
/// [`DynamicList`]: crate::DynamicList
/// [`Struct`]: crate::Struct
/// [`Struct::clone_dynamic`]: crate::Struct::clone_dynamic
/// [`DynamicStruct`]: crate::DynamicStruct
#[deprecated(
since = "0.16.0",
note = "to clone reflected values, prefer using `reflect_clone`. To convert reflected values to dynamic ones, use `to_dynamic`."
)]
fn clone_value(&self) -> Box<dyn PartialReflect> {
self.to_dynamic()
}
/// Converts this reflected value into its dynamic representation based on its [kind].
///
/// For example, a [`List`] type will internally invoke [`List::to_dynamic_list`], returning [`DynamicList`].
/// A [`Struct`] type will invoke [`Struct::to_dynamic_struct`], returning [`DynamicStruct`].
/// And so on.
///
/// If the [kind] is [opaque], then the value will attempt to be cloned directly via [`reflect_clone`],
/// since opaque types do not have any standard dynamic representation.
///
/// To attempt to clone the value directly such that it returns a concrete instance of this type,
/// use [`reflect_clone`].
///
/// # Panics
///
/// This method will panic if the [kind] is [opaque] and the call to [`reflect_clone`] fails.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{PartialReflect};
/// let value = (1, true, 3.14);
/// let dynamic_value = value.to_dynamic();
/// assert!(dynamic_value.is_dynamic())
/// ```
///
/// [kind]: PartialReflect::reflect_kind
/// [`List`]: crate::List
/// [`List::to_dynamic_list`]: crate::List::to_dynamic_list
/// [`DynamicList`]: crate::DynamicList
/// [`Struct`]: crate::Struct
/// [`Struct::to_dynamic_struct`]: crate::Struct::to_dynamic_struct
/// [`DynamicStruct`]: crate::DynamicStruct
/// [opaque]: crate::ReflectKind::Opaque
/// [`reflect_clone`]: PartialReflect::reflect_clone
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(),
}
}
/// Attempts to clone `Self` using reflection.
///
/// Unlike [`to_dynamic`], which generally returns a dynamic representation of `Self`,
/// this method attempts create a clone of `Self` directly, if possible.
///
/// If the clone cannot be performed, an appropriate [`ReflectCloneError`] is returned.
///
/// # Example
///
/// ```
/// # use bevy_reflect::PartialReflect;
/// let value = (1, true, 3.14);
/// let cloned = value.reflect_clone().unwrap();
/// assert!(cloned.is::<(i32, bool, f64)>())
/// ```
///
/// [`to_dynamic`]: PartialReflect::to_dynamic
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Err(ReflectCloneError::NotImplemented {
type_path: Cow::Owned(self.reflect_type_path().to_string()),
})
}
/// Returns a hash of the value (which includes the type).
///
/// If the underlying type does not support hashing, returns `None`.
fn reflect_hash(&self) -> Option<u64> {
None
}
/// Returns a "partial equality" comparison result.
///
/// If the underlying type does not support equality testing, returns `None`.
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
None
}
/// Debug formatter for the value.
///
/// Any value that is not an implementor of other `Reflect` subtraits
/// (e.g. [`List`], [`Map`]), will default to the format: `"Reflect(type_path)"`,
/// where `type_path` is the [type path] of the underlying type.
///
/// [`List`]: crate::List
/// [`Map`]: crate::Map
/// [type path]: TypePath::type_path
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()),
}
}
/// Indicates whether or not this type is a _dynamic_ type.
///
/// Dynamic types include the ones built-in to this [crate],
/// such as [`DynamicStruct`], [`DynamicList`], and [`DynamicTuple`].
/// However, they may be custom types used as proxies for other types
/// or to facilitate scripting capabilities.
///
/// By default, this method will return `false`.
///
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
/// [`DynamicTuple`]: crate::DynamicTuple
fn is_dynamic(&self) -> bool {
false
}
}
/// A core trait of [`bevy_reflect`], used for downcasting to concrete types.
///
/// This is a subtrait of [`PartialReflect`],
/// meaning any type which implements `Reflect` implements `PartialReflect` by definition.
///
/// It's recommended to use [the derive macro] rather than manually implementing this trait.
/// Doing so will automatically implement this trait, [`PartialReflect`], and many other useful traits for reflection,
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
///
/// If you need to use this trait as a generic bound along with other reflection traits,
/// for your convenience, consider using [`Reflectable`] instead.
///
/// See the [crate-level documentation] to see how this trait can be used.
///
/// [`bevy_reflect`]: crate
/// [the derive macro]: bevy_reflect_derive::Reflect
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Enum`]: crate::Enum
/// [`Reflectable`]: crate::Reflectable
/// [crate-level documentation]: crate
#[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 {
/// Returns the value as a [`Box<dyn Any>`][core::any::Any].
///
/// For remote wrapper types, this will return the remote type instead.
fn into_any(self: Box<Self>) -> Box<dyn Any>;
/// Returns the value as a [`&dyn Any`][core::any::Any].
///
/// For remote wrapper types, this will return the remote type instead.
fn as_any(&self) -> &dyn Any;
/// Returns the value as a [`&mut dyn Any`][core::any::Any].
///
/// For remote wrapper types, this will return the remote type instead.
fn as_any_mut(&mut self) -> &mut dyn Any;
/// Casts this type to a boxed, fully-reflected value.
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect>;
/// Casts this type to a fully-reflected value.
fn as_reflect(&self) -> &dyn Reflect;
/// Casts this type to a mutable, fully-reflected value.
fn as_reflect_mut(&mut self) -> &mut dyn Reflect;
/// Performs a type-checked assignment of a reflected value to this value.
///
/// If `value` does not contain a value of type `T`, returns an `Err`
/// containing the trait object.
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
}
impl dyn PartialReflect {
/// Returns `true` if the underlying value represents a value of type `T`, or `false`
/// otherwise.
///
/// Read `is` for more information on underlying values and represented types.
#[inline]
pub fn represents<T: Reflect + TypePath>(&self) -> bool {
self.get_represented_type_info()
.is_some_and(|t| t.type_path() == T::type_path())
}
/// Downcasts the value to type `T`, consuming the trait object.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
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)
}
/// Downcasts the value to type `T`, unboxing and consuming the trait object.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn try_take<T: Any>(self: Box<dyn PartialReflect>) -> Result<T, Box<dyn PartialReflect>> {
self.try_downcast().map(|value| *value)
}
/// Downcasts the value to type `T` by reference.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns [`None`].
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn try_downcast_ref<T: Any>(&self) -> Option<&T> {
self.try_as_reflect()?.downcast_ref()
}
/// Downcasts the value to type `T` by mutable reference.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns [`None`].
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
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)
}
}
// The following implementation never actually shadows the concrete TypePath implementation.
// See the comment on `dyn Reflect`'s `TypePath` implementation.
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 {
/// Downcasts the value to type `T`, consuming the trait object.
///
/// If the underlying value is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
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)
}
}
/// Downcasts the value to type `T`, unboxing and consuming the trait object.
///
/// If the underlying value is not of type `T`, returns `Err(self)`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
pub fn take<T: Any>(self: Box<dyn Reflect>) -> Result<T, Box<dyn Reflect>> {
self.downcast::<T>().map(|value| *value)
}
/// Returns `true` if the underlying value is of type `T`, or `false`
/// otherwise.
///
/// The underlying value is the concrete type that is stored in this `dyn` object;
/// it can be downcasted to. In the case that this underlying value "represents"
/// a different type, like the Dynamic\*\*\* types do, you can call `represents`
/// to determine what type they represent. Represented types cannot be downcasted
/// to, but you can use [`FromReflect`] to create a value of the represented type from them.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
///
/// [`FromReflect`]: crate::FromReflect
#[inline]
pub fn is<T: Any>(&self) -> bool {
self.as_any().type_id() == TypeId::of::<T>()
}
/// Downcasts the value to type `T` by reference.
///
/// If the underlying value is not of type `T`, returns `None`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref::<T>()
}
/// Downcasts the value to type `T` by mutable reference.
///
/// If the underlying value is not of type `T`, returns `None`.
///
/// For remote types, `T` should be the type itself rather than the wrapper type.
#[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>()))
}
}
// The following implementation never actually shadows the concrete `TypePath` implementation.
// See this playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=589064053f27bc100d90da89c6a860aa).
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: Box<Self>) -> 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: Box<Self>) -> 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: Box<dyn $crate::Reflect>,
) -> Result<(), Box<dyn $crate::Reflect>> {
*self = <dyn $crate::Reflect>::take(value)?;
Ok(())
}
}
};
}
pub(crate) use impl_full_reflect;

33
vendor/bevy_reflect/src/reflectable.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use crate::{GetTypeRegistration, Reflect, TypePath, Typed};
/// A catch-all trait that is bound by the core reflection traits,
/// useful to simplify reflection-based generic type bounds.
///
/// You do _not_ need to implement this trait manually.
/// It is automatically implemented for all types that implement its supertraits.
/// And these supertraits are all automatically derived with the [`Reflect` derive macro].
///
/// This should namely be used to bound generic arguments to the necessary traits for reflection.
/// Doing this has the added benefit of reducing migration costs, as a change to the required traits
/// is automatically handled by this trait.
///
/// For now, the supertraits of this trait includes:
/// * [`Reflect`]
/// * [`GetTypeRegistration`]
/// * [`Typed`]
/// * [`TypePath`]
///
/// ## Example
///
/// ```
/// # use bevy_reflect::{Reflect, Reflectable};
/// #[derive(Reflect)]
/// struct MyStruct<T: Reflectable> {
/// value: T
/// }
/// ```
///
/// [`Reflect` derive macro]: bevy_reflect_derive::Reflect
pub trait Reflectable: Reflect + GetTypeRegistration + Typed + TypePath {}
impl<T: Reflect + GetTypeRegistration + Typed + TypePath> Reflectable for T {}

64
vendor/bevy_reflect/src/remote.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
use crate::Reflect;
/// Marks a type as a [reflectable] wrapper for a remote type.
///
/// This allows types from external libraries (remote types) to be included in reflection.
///
/// # Safety
///
/// It is highly recommended to avoid implementing this trait manually and instead use the
/// [`#[reflect_remote]`](crate::reflect_remote) attribute macro.
/// This is because the trait tends to rely on [`transmute`], which is [very unsafe].
///
/// The macro will ensure that the following safety requirements are met:
/// - `Self` is a single-field tuple struct (i.e. a newtype) containing the remote type.
/// - `Self` is `#[repr(transparent)]` over the remote type.
///
/// Additionally, the macro will automatically generate [`Reflect`] and [`FromReflect`] implementations,
/// along with compile-time assertions to validate that the safety requirements have been met.
///
/// # Example
///
/// ```
/// use bevy_reflect_derive::{reflect_remote, Reflect};
///
/// mod some_lib {
/// pub struct TheirType {
/// pub value: u32
/// }
/// }
///
/// #[reflect_remote(some_lib::TheirType)]
/// struct MyType {
/// pub value: u32
/// }
///
/// #[derive(Reflect)]
/// struct MyStruct {
/// #[reflect(remote = MyType)]
/// data: some_lib::TheirType,
/// }
/// ```
///
/// [reflectable]: Reflect
/// [`transmute`]: core::mem::transmute
/// [very unsafe]: https://doc.rust-lang.org/1.71.0/nomicon/transmutes.html
/// [`FromReflect`]: crate::FromReflect
pub trait ReflectRemote: Reflect {
/// The remote type this type represents via reflection.
type Remote;
/// Converts a reference of this wrapper to a reference of its remote type.
fn as_remote(&self) -> &Self::Remote;
/// Converts a mutable reference of this wrapper to a mutable reference of its remote type.
fn as_remote_mut(&mut self) -> &mut Self::Remote;
/// Converts this wrapper into its remote type.
fn into_remote(self) -> Self::Remote;
/// Converts a reference of the remote type to a reference of this wrapper.
fn as_wrapper(remote: &Self::Remote) -> &Self;
/// Converts a mutable reference of the remote type to a mutable reference of this wrapper.
fn as_wrapper_mut(remote: &mut Self::Remote) -> &mut Self;
/// Converts the remote type into this wrapper.
fn into_wrapper(remote: Self::Remote) -> Self;
}

View File

@@ -0,0 +1,50 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
ArrayInfo, DynamicArray, TypeRegistry,
};
use alloc::{string::ToString, vec::Vec};
use core::{fmt, fmt::Formatter};
use serde::de::{Error, SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Array`] values.
///
/// [`Array`]: crate::Array
pub(super) struct ArrayVisitor<'a, P> {
pub array_info: &'static ArrayInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for ArrayVisitor<'_, P> {
type Value = DynamicArray;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected array value")
}
fn visit_seq<V>(mut self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default());
let registration = try_get_registration(self.array_info.item_ty(), self.registry)?;
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor.as_deref_mut(),
))? {
vec.push(value);
}
if vec.len() != self.array_info.capacity() {
return Err(Error::invalid_length(
vec.len(),
&self.array_info.capacity().to_string().as_str(),
));
}
Ok(DynamicArray::new(vec.into_boxed_slice()))
}
}

View File

@@ -0,0 +1,84 @@
use crate::serde::de::error_utils::make_custom_error;
use crate::{FromType, PartialReflect, TypeRegistry};
use alloc::boxed::Box;
use serde::Deserializer;
/// Trait used to provide finer control when deserializing a reflected type with one of
/// the reflection deserializers.
///
/// This trait is the reflection equivalent of `serde`'s [`Deserialize`] trait.
/// The main difference is that this trait provides access to the [`TypeRegistry`],
/// which means that we can use the registry and all its stored type information
/// to deserialize our type.
///
/// This can be useful when writing a custom reflection deserializer where we may
/// want to handle parts of the deserialization process, but temporarily pass control
/// to the standard reflection deserializer for other parts.
///
/// For the serialization equivalent of this trait, see [`SerializeWithRegistry`].
///
/// # Rationale
///
/// Without this trait and its associated [type data], such a deserializer would have to
/// write out all of the deserialization logic itself, possibly including
/// unnecessary code duplication and trivial implementations.
///
/// This is because a normal [`Deserialize`] implementation has no knowledge of the
/// [`TypeRegistry`] and therefore cannot create a reflection-based deserializer for
/// nested items.
///
/// # Implementors
///
/// In order for this to work with the reflection deserializers like [`TypedReflectDeserializer`]
/// and [`ReflectDeserializer`], implementors should be sure to register the
/// [`ReflectDeserializeWithRegistry`] type data.
/// This can be done [via the registry] or by adding `#[reflect(DeserializeWithRegistry)]` to
/// the type definition.
///
/// [`Deserialize`]: ::serde::Deserialize
/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry
/// [type data]: ReflectDeserializeWithRegistry
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [via the registry]: TypeRegistry::register_type_data
pub trait DeserializeWithRegistry<'de>: Sized {
fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
}
/// Type data used to deserialize a [`PartialReflect`] type with a custom [`DeserializeWithRegistry`] implementation.
#[derive(Clone)]
pub struct ReflectDeserializeWithRegistry {
deserialize: fn(
deserializer: &mut dyn erased_serde::Deserializer,
registry: &TypeRegistry,
) -> Result<Box<dyn PartialReflect>, erased_serde::Error>,
}
impl ReflectDeserializeWithRegistry {
/// Deserialize a [`PartialReflect`] type with this type data's custom [`DeserializeWithRegistry`] implementation.
pub fn deserialize<'de, D>(
&self,
deserializer: D,
registry: &TypeRegistry,
) -> Result<Box<dyn PartialReflect>, D::Error>
where
D: Deserializer<'de>,
{
let mut erased = <dyn erased_serde::Deserializer>::erase(deserializer);
(self.deserialize)(&mut erased, registry).map_err(make_custom_error)
}
}
impl<T: PartialReflect + for<'de> DeserializeWithRegistry<'de>> FromType<T>
for ReflectDeserializeWithRegistry
{
fn from_type() -> Self {
Self {
deserialize: |deserializer, registry| {
Ok(Box::new(T::deserialize(deserializer, registry)?))
},
}
}
}

View File

@@ -0,0 +1,531 @@
#[cfg(feature = "debug_stack")]
use crate::serde::de::error_utils::TYPE_INFO_STACK;
use crate::serde::{ReflectDeserializeWithRegistry, SerializationData};
use crate::{
serde::{
de::{
arrays::ArrayVisitor, enums::EnumVisitor, error_utils::make_custom_error,
lists::ListVisitor, maps::MapVisitor, options::OptionVisitor, sets::SetVisitor,
structs::StructVisitor, tuple_structs::TupleStructVisitor, tuples::TupleVisitor,
},
TypeRegistrationDeserializer,
},
PartialReflect, ReflectDeserialize, TypeInfo, TypePath, TypeRegistration, TypeRegistry,
};
use alloc::boxed::Box;
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, Error, IgnoredAny, MapAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A general purpose deserializer for reflected types.
///
/// This is the deserializer counterpart to [`ReflectSerializer`].
///
/// See [`TypedReflectDeserializer`] for a deserializer that expects a known type.
///
/// # Input
///
/// This deserializer expects a map with a single entry,
/// where the key is the _full_ [type path] of the reflected type
/// and the value is the serialized data.
///
/// # Output
///
/// This deserializer will return a [`Box<dyn Reflect>`] containing the deserialized data.
///
/// For opaque types (i.e. [`ReflectKind::Opaque`]) or types that register [`ReflectDeserialize`] type data,
/// this `Box` will contain the expected type.
/// For example, deserializing an `i32` will return a `Box<i32>` (as a `Box<dyn Reflect>`).
///
/// Otherwise, this `Box` will contain the dynamic equivalent.
/// For example, a deserialized struct might return a [`Box<DynamicStruct>`]
/// and a deserialized `Vec` might return a [`Box<DynamicList>`].
///
/// This means that if the actual type is needed, these dynamic representations will need to
/// be converted to the concrete type using [`FromReflect`] or [`ReflectFromReflect`].
///
/// If you want to override deserialization for a specific [`TypeRegistration`],
/// you can pass in a reference to a [`ReflectDeserializerProcessor`] which will
/// take priority over all other deserialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use serde::de::DeserializeSeed;
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{DynamicStruct, TypeRegistry, serde::ReflectDeserializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// #[type_path = "my_crate"]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = r#"{
/// "my_crate::MyStruct": (
/// value: 123
/// )
/// }"#;
///
/// let mut deserializer = ron::Deserializer::from_str(input).unwrap();
/// let reflect_deserializer = ReflectDeserializer::new(&registry);
///
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not an opaque type and does not register `ReflectDeserialize`,
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
///
/// // We can convert back to `MyStruct` using `FromReflect`.
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(output.as_partial_reflect()).unwrap();
/// assert_eq!(value, MyStruct { value: 123 });
///
/// // We can also do this dynamically with `ReflectFromReflect`.
/// let type_id = output.get_represented_type_info().unwrap().type_id();
/// let reflect_from_reflect = registry.get_type_data::<ReflectFromReflect>(type_id).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(output.as_partial_reflect()).unwrap();
/// assert!(value.is::<MyStruct>());
/// assert_eq!(value.take::<MyStruct>().unwrap(), MyStruct { value: 123 });
/// ```
///
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [type path]: crate::TypePath::type_path
/// [`Box<dyn Reflect>`]: crate::Reflect
/// [`ReflectKind::Opaque`]: crate::ReflectKind::Opaque
/// [`ReflectDeserialize`]: crate::ReflectDeserialize
/// [`Box<DynamicStruct>`]: crate::DynamicStruct
/// [`Box<DynamicList>`]: crate::DynamicList
/// [`FromReflect`]: crate::FromReflect
/// [`ReflectFromReflect`]: crate::ReflectFromReflect
/// [`with_processor`]: Self::with_processor
pub struct ReflectDeserializer<'a, P: ReflectDeserializerProcessor = ()> {
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'a> ReflectDeserializer<'a, ()> {
/// Creates a deserializer with no processor.
///
/// If you want to add custom logic for deserializing certain types, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(registry: &'a TypeRegistry) -> Self {
Self {
registry,
processor: None,
}
}
}
impl<'a, P: ReflectDeserializerProcessor> ReflectDeserializer<'a, P> {
/// Creates a deserializer with a processor.
///
/// If you do not need any custom logic for handling certain types, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(registry: &'a TypeRegistry, processor: &'a mut P) -> Self {
Self {
registry,
processor: Some(processor),
}
}
}
impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de> for ReflectDeserializer<'_, P> {
type Value = Box<dyn PartialReflect>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
struct UntypedReflectDeserializerVisitor<'a, P> {
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de>
for UntypedReflectDeserializerVisitor<'_, P>
{
type Value = Box<dyn PartialReflect>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter
.write_str("map containing `type` and `value` entries for the reflected value")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let registration = map
.next_key_seed(TypeRegistrationDeserializer::new(self.registry))?
.ok_or_else(|| Error::invalid_length(0, &"a single entry"))?;
let value = map.next_value_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor,
))?;
if map.next_key::<IgnoredAny>()?.is_some() {
return Err(Error::invalid_length(2, &"a single entry"));
}
Ok(value)
}
}
deserializer.deserialize_map(UntypedReflectDeserializerVisitor {
registry: self.registry,
processor: self.processor,
})
}
}
/// A deserializer for reflected types whose [`TypeRegistration`] is known.
///
/// This is the deserializer counterpart to [`TypedReflectSerializer`].
///
/// See [`ReflectDeserializer`] for a deserializer that expects an unknown type.
///
/// # Input
///
/// Since the type is already known, the input is just the serialized data.
///
/// # Output
///
/// This deserializer will return a [`Box<dyn Reflect>`] containing the deserialized data.
///
/// For opaque types (i.e. [`ReflectKind::Opaque`]) or types that register [`ReflectDeserialize`] type data,
/// this `Box` will contain the expected type.
/// For example, deserializing an `i32` will return a `Box<i32>` (as a `Box<dyn Reflect>`).
///
/// Otherwise, this `Box` will contain the dynamic equivalent.
/// For example, a deserialized struct might return a [`Box<DynamicStruct>`]
/// and a deserialized `Vec` might return a [`Box<DynamicList>`].
///
/// This means that if the actual type is needed, these dynamic representations will need to
/// be converted to the concrete type using [`FromReflect`] or [`ReflectFromReflect`].
///
/// If you want to override deserialization for a specific [`TypeRegistration`],
/// you can pass in a reference to a [`ReflectDeserializerProcessor`] which will
/// take priority over all other deserialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use serde::de::DeserializeSeed;
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{DynamicStruct, TypeRegistry, serde::TypedReflectDeserializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = r#"(
/// value: 123
/// )"#;
///
/// let registration = registry.get(TypeId::of::<MyStruct>()).unwrap();
///
/// let mut deserializer = ron::Deserializer::from_str(input).unwrap();
/// let reflect_deserializer = TypedReflectDeserializer::new(registration, &registry);
///
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not an opaque type and does not register `ReflectDeserialize`,
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
///
/// // We can convert back to `MyStruct` using `FromReflect`.
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(output.as_partial_reflect()).unwrap();
/// assert_eq!(value, MyStruct { value: 123 });
///
/// // We can also do this dynamically with `ReflectFromReflect`.
/// let type_id = output.get_represented_type_info().unwrap().type_id();
/// let reflect_from_reflect = registry.get_type_data::<ReflectFromReflect>(type_id).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(output.as_partial_reflect()).unwrap();
/// assert!(value.is::<MyStruct>());
/// assert_eq!(value.take::<MyStruct>().unwrap(), MyStruct { value: 123 });
/// ```
///
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`Box<dyn Reflect>`]: crate::Reflect
/// [`ReflectKind::Opaque`]: crate::ReflectKind::Opaque
/// [`ReflectDeserialize`]: crate::ReflectDeserialize
/// [`Box<DynamicStruct>`]: crate::DynamicStruct
/// [`Box<DynamicList>`]: crate::DynamicList
/// [`FromReflect`]: crate::FromReflect
/// [`ReflectFromReflect`]: crate::ReflectFromReflect
/// [`with_processor`]: Self::with_processor
pub struct TypedReflectDeserializer<'a, P: ReflectDeserializerProcessor = ()> {
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'a> TypedReflectDeserializer<'a, ()> {
/// Creates a typed deserializer with no processor.
///
/// If you want to add custom logic for deserializing certain types, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(registration: &'a TypeRegistration, registry: &'a TypeRegistry) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
registration,
registry,
processor: None,
}
}
/// Creates a new [`TypedReflectDeserializer`] for the given type `T`
/// without a processor.
///
/// # Panics
///
/// Panics if `T` is not registered in the given [`TypeRegistry`].
pub fn of<T: TypePath>(registry: &'a TypeRegistry) -> Self {
let registration = registry
.get(core::any::TypeId::of::<T>())
.unwrap_or_else(|| panic!("no registration found for type `{}`", T::type_path()));
Self {
registration,
registry,
processor: None,
}
}
}
impl<'a, P: ReflectDeserializerProcessor> TypedReflectDeserializer<'a, P> {
/// Creates a typed deserializer with a processor.
///
/// If you do not need any custom logic for handling certain types, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: &'a mut P,
) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
registration,
registry,
processor: Some(processor),
}
}
/// An internal constructor for creating a deserializer without resetting the type info stack.
pub(super) fn new_internal(
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
) -> Self {
Self {
registration,
registry,
processor,
}
}
}
impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de>
for TypedReflectDeserializer<'_, P>
{
type Value = Box<dyn PartialReflect>;
fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let deserialize_internal = || -> Result<Self::Value, D::Error> {
// First, check if our processor wants to deserialize this type
// This takes priority over any other deserialization operations
let deserializer = if let Some(processor) = self.processor.as_deref_mut() {
match processor.try_deserialize(self.registration, self.registry, deserializer) {
Ok(Ok(value)) => {
return Ok(value);
}
Err(err) => {
return Err(make_custom_error(err));
}
Ok(Err(deserializer)) => deserializer,
}
} else {
deserializer
};
let type_path = self.registration.type_info().type_path();
// Handle both Value case and types that have a custom `ReflectDeserialize`
if let Some(deserialize_reflect) = self.registration.data::<ReflectDeserialize>() {
let value = deserialize_reflect.deserialize(deserializer)?;
return Ok(value.into_partial_reflect());
}
if let Some(deserialize_reflect) =
self.registration.data::<ReflectDeserializeWithRegistry>()
{
let value = deserialize_reflect.deserialize(deserializer, self.registry)?;
return Ok(value);
}
match self.registration.type_info() {
TypeInfo::Struct(struct_info) => {
let mut dynamic_struct = deserializer.deserialize_struct(
struct_info.type_path_table().ident().unwrap(),
struct_info.field_names(),
StructVisitor {
struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?;
dynamic_struct.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_struct))
}
TypeInfo::TupleStruct(tuple_struct_info) => {
let mut dynamic_tuple_struct = if tuple_struct_info.field_len() == 1
&& self.registration.data::<SerializationData>().is_none()
{
deserializer.deserialize_newtype_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
TupleStructVisitor {
tuple_struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
} else {
deserializer.deserialize_tuple_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
tuple_struct_info.field_len(),
TupleStructVisitor {
tuple_struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
};
dynamic_tuple_struct.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_tuple_struct))
}
TypeInfo::List(list_info) => {
let mut dynamic_list = deserializer.deserialize_seq(ListVisitor {
list_info,
registry: self.registry,
processor: self.processor,
})?;
dynamic_list.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_list))
}
TypeInfo::Array(array_info) => {
let mut dynamic_array = deserializer.deserialize_tuple(
array_info.capacity(),
ArrayVisitor {
array_info,
registry: self.registry,
processor: self.processor,
},
)?;
dynamic_array.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_array))
}
TypeInfo::Map(map_info) => {
let mut dynamic_map = deserializer.deserialize_map(MapVisitor {
map_info,
registry: self.registry,
processor: self.processor,
})?;
dynamic_map.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_map))
}
TypeInfo::Set(set_info) => {
let mut dynamic_set = deserializer.deserialize_seq(SetVisitor {
set_info,
registry: self.registry,
processor: self.processor,
})?;
dynamic_set.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_set))
}
TypeInfo::Tuple(tuple_info) => {
let mut dynamic_tuple = deserializer.deserialize_tuple(
tuple_info.field_len(),
TupleVisitor {
tuple_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?;
dynamic_tuple.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_tuple))
}
TypeInfo::Enum(enum_info) => {
let mut dynamic_enum = if enum_info.type_path_table().module_path()
== Some("core::option")
&& enum_info.type_path_table().ident() == Some("Option")
{
deserializer.deserialize_option(OptionVisitor {
enum_info,
registry: self.registry,
processor: self.processor,
})?
} else {
deserializer.deserialize_enum(
enum_info.type_path_table().ident().unwrap(),
enum_info.variant_names(),
EnumVisitor {
enum_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
};
dynamic_enum.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_enum))
}
TypeInfo::Opaque(_) => {
// This case should already be handled
Err(make_custom_error(format_args!(
"type `{type_path}` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`",
)))
}
}
};
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(|stack| stack.push(self.registration.type_info()));
let output = deserialize_internal();
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
output
}
}

View File

@@ -0,0 +1,215 @@
use crate::{
serde::{
de::{
error_utils::make_custom_error,
helpers::ExpectedValues,
registration_utils::try_get_registration,
struct_utils::{visit_struct, visit_struct_seq},
tuple_utils::{visit_tuple, TupleLikeInfo},
},
TypedReflectDeserializer,
},
DynamicEnum, DynamicStruct, DynamicTuple, DynamicVariant, EnumInfo, StructVariantInfo,
TupleVariantInfo, TypeRegistration, TypeRegistry, VariantInfo,
};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Enum`] values.
///
/// [`Enum`]: crate::Enum
pub(super) struct EnumVisitor<'a, P> {
pub enum_info: &'static EnumInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for EnumVisitor<'_, P> {
type Value = DynamicEnum;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected enum value")
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let mut dynamic_enum = DynamicEnum::default();
let (variant_info, variant) = data.variant_seed(VariantDeserializer {
enum_info: self.enum_info,
})?;
let value: DynamicVariant = match variant_info {
VariantInfo::Unit(..) => variant.unit_variant()?.into(),
VariantInfo::Struct(struct_info) => variant
.struct_variant(
struct_info.field_names(),
StructVariantVisitor {
struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
.into(),
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
let registration = try_get_registration(
*TupleLikeInfo::field_at(tuple_info, 0)?.ty(),
self.registry,
)?;
let value =
variant.newtype_variant_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor,
))?;
let mut dynamic_tuple = DynamicTuple::default();
dynamic_tuple.insert_boxed(value);
dynamic_tuple.into()
}
VariantInfo::Tuple(tuple_info) => variant
.tuple_variant(
tuple_info.field_len(),
TupleVariantVisitor {
tuple_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?
.into(),
};
let variant_name = variant_info.name();
let variant_index = self
.enum_info
.index_of(variant_name)
.expect("variant should exist");
dynamic_enum.set_variant_with_index(variant_index, variant_name, value);
Ok(dynamic_enum)
}
}
struct VariantDeserializer {
enum_info: &'static EnumInfo,
}
impl<'de> DeserializeSeed<'de> for VariantDeserializer {
type Value = &'static VariantInfo;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
struct VariantVisitor(&'static EnumInfo);
impl<'de> Visitor<'de> for VariantVisitor {
type Value = &'static VariantInfo;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("expected either a variant index or variant name")
}
fn visit_u32<E>(self, variant_index: u32) -> Result<Self::Value, E>
where
E: Error,
{
self.0.variant_at(variant_index as usize).ok_or_else(|| {
make_custom_error(format_args!(
"no variant found at index `{}` on enum `{}`",
variant_index,
self.0.type_path()
))
})
}
fn visit_str<E>(self, variant_name: &str) -> Result<Self::Value, E>
where
E: Error,
{
self.0.variant(variant_name).ok_or_else(|| {
let names = self.0.iter().map(VariantInfo::name);
make_custom_error(format_args!(
"unknown variant `{}`, expected one of {:?}",
variant_name,
ExpectedValues::from_iter(names)
))
})
}
}
deserializer.deserialize_identifier(VariantVisitor(self.enum_info))
}
}
struct StructVariantVisitor<'a, P> {
struct_info: &'static StructVariantInfo,
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVariantVisitor<'_, P> {
type Value = DynamicStruct;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected struct variant value")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
visit_struct_seq(
&mut seq,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
visit_struct(
&mut map,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
}
struct TupleVariantVisitor<'a, P> {
tuple_info: &'static TupleVariantInfo,
registration: &'a TypeRegistration,
registry: &'a TypeRegistry,
processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleVariantVisitor<'_, P> {
type Value = DynamicTuple;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected tuple variant value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
visit_tuple(
&mut seq,
self.tuple_info,
self.registration,
self.registry,
self.processor,
)
}
}

View File

@@ -0,0 +1,29 @@
use core::fmt::Display;
use serde::de::Error;
#[cfg(feature = "debug_stack")]
use std::thread_local;
#[cfg(feature = "debug_stack")]
thread_local! {
/// The thread-local [`TypeInfoStack`] used for debugging.
///
/// [`TypeInfoStack`]: crate::type_info_stack::TypeInfoStack
pub(super) static TYPE_INFO_STACK: core::cell::RefCell<crate::type_info_stack::TypeInfoStack> = const { core::cell::RefCell::new(
crate::type_info_stack::TypeInfoStack::new()
) };
}
/// A helper function for generating a custom deserialization error message.
///
/// This function should be preferred over [`Error::custom`] as it will include
/// other useful information, such as the [type info stack].
///
/// [type info stack]: crate::type_info_stack::TypeInfoStack
pub(super) fn make_custom_error<E: Error>(msg: impl Display) -> E {
#[cfg(feature = "debug_stack")]
return TYPE_INFO_STACK
.with_borrow(|stack| E::custom(format_args!("{} (stack: {:?})", msg, stack)));
#[cfg(not(feature = "debug_stack"))]
return E::custom(msg);
}

View File

@@ -0,0 +1,78 @@
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{
fmt,
fmt::{Debug, Display, Formatter},
};
use serde::{
de::{Error, Visitor},
Deserialize,
};
/// A debug struct used for error messages that displays a list of expected values.
///
/// # Example
///
/// ```ignore (Can't import private struct from doctest)
/// let expected = vec!["foo", "bar", "baz"];
/// assert_eq!("`foo`, `bar`, `baz`", format!("{}", ExpectedValues(expected)));
/// ```
pub(super) struct ExpectedValues<T: Display>(pub Vec<T>);
impl<T: Display> FromIterator<T> for ExpectedValues<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: Display> Debug for ExpectedValues<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let len = self.0.len();
for (index, item) in self.0.iter().enumerate() {
write!(f, "`{item}`")?;
if index < len - 1 {
write!(f, ", ")?;
}
}
Ok(())
}
}
/// Represents a simple reflected identifier.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) struct Ident(pub String);
impl<'de> Deserialize<'de> for Ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct IdentVisitor;
impl<'de> Visitor<'de> for IdentVisitor {
type Value = Ident;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Ident(value.to_string()))
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Ident(value))
}
}
deserializer.deserialize_identifier(IdentVisitor)
}
}

View File

@@ -0,0 +1,41 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
DynamicList, ListInfo, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`List`] values.
///
/// [`List`]: crate::List
pub(super) struct ListVisitor<'a, P> {
pub list_info: &'static ListInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for ListVisitor<'_, P> {
type Value = DynamicList;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected list value")
}
fn visit_seq<V>(mut self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut list = DynamicList::default();
let registration = try_get_registration(self.list_info.item_ty(), self.registry)?;
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor.as_deref_mut(),
))? {
list.push_box(value);
}
Ok(list)
}
}

View File

@@ -0,0 +1,48 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
DynamicMap, Map, MapInfo, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{MapAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Map`] values.
///
/// [`Map`]: crate::Map
pub(super) struct MapVisitor<'a, P> {
pub map_info: &'static MapInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for MapVisitor<'_, P> {
type Value = DynamicMap;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected map value")
}
fn visit_map<V>(mut self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut dynamic_map = DynamicMap::default();
let key_registration = try_get_registration(self.map_info.key_ty(), self.registry)?;
let value_registration = try_get_registration(self.map_info.value_ty(), self.registry)?;
while let Some(key) = map.next_key_seed(TypedReflectDeserializer::new_internal(
key_registration,
self.registry,
self.processor.as_deref_mut(),
))? {
let value = map.next_value_seed(TypedReflectDeserializer::new_internal(
value_registration,
self.registry,
self.processor.as_deref_mut(),
))?;
dynamic_map.insert_boxed(key, value);
}
Ok(dynamic_map)
}
}

855
vendor/bevy_reflect/src/serde/de/mod.rs vendored Normal file
View File

@@ -0,0 +1,855 @@
pub use deserialize_with_registry::*;
pub use deserializer::*;
pub use processor::*;
pub use registrations::*;
mod arrays;
mod deserialize_with_registry;
mod deserializer;
mod enums;
mod error_utils;
mod helpers;
mod lists;
mod maps;
mod options;
mod processor;
mod registration_utils;
mod registrations;
mod sets;
mod struct_utils;
mod structs;
mod tuple_structs;
mod tuple_utils;
mod tuples;
#[cfg(test)]
mod tests {
use alloc::{
boxed::Box,
string::{String, ToString},
vec,
vec::Vec,
};
use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive};
use serde::{de::DeserializeSeed, Deserialize};
use serde::{de::IgnoredAny, Deserializer};
use bevy_platform::collections::{HashMap, HashSet};
use crate::{
serde::{
ReflectDeserializer, ReflectDeserializerProcessor, ReflectSerializer,
TypedReflectDeserializer,
},
DynamicEnum, FromReflect, PartialReflect, Reflect, ReflectDeserialize, TypeRegistration,
TypeRegistry,
};
#[derive(Reflect, Debug, PartialEq)]
struct MyStruct {
primitive_value: i8,
option_value: Option<String>,
option_value_complex: Option<SomeStruct>,
tuple_value: (f32, usize),
list_value: Vec<i32>,
array_value: [i32; 5],
map_value: HashMap<u8, usize>,
set_value: HashSet<u8>,
struct_value: SomeStruct,
tuple_struct_value: SomeTupleStruct,
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum,
newtype_enum: SomeEnum,
tuple_enum: SomeEnum,
struct_enum: SomeEnum,
ignored_struct: SomeIgnoredStruct,
ignored_tuple_struct: SomeIgnoredTupleStruct,
ignored_struct_variant: SomeIgnoredEnum,
ignored_tuple_variant: SomeIgnoredEnum,
custom_deserialize: CustomDeserialize,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeStruct {
foo: i64,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeTupleStruct(String);
#[derive(Reflect, Debug, PartialEq)]
struct SomeUnitStruct;
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredStruct {
#[reflect(ignore)]
ignored: i32,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredTupleStruct(#[reflect(ignore)] i32);
#[derive(Reflect, Debug, PartialEq, Deserialize)]
struct SomeDeserializableStruct {
foo: i64,
}
/// Implements a custom deserialize using `#[reflect(Deserialize)]`.
///
/// For testing purposes, this is just the auto-generated one from deriving.
#[derive(Reflect, Debug, PartialEq, Deserialize)]
#[reflect(Deserialize)]
struct CustomDeserialize {
value: usize,
#[serde(alias = "renamed")]
inner_struct: SomeDeserializableStruct,
}
#[derive(Reflect, Debug, PartialEq)]
enum SomeEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { foo: String },
}
#[derive(Reflect, Debug, PartialEq)]
enum SomeIgnoredEnum {
Tuple(#[reflect(ignore)] f32, #[reflect(ignore)] f32),
Struct {
#[reflect(ignore)]
foo: String,
},
}
fn get_registry() -> TypeRegistry {
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
registry.register::<SomeStruct>();
registry.register::<SomeTupleStruct>();
registry.register::<SomeUnitStruct>();
registry.register::<SomeIgnoredStruct>();
registry.register::<SomeIgnoredTupleStruct>();
registry.register::<CustomDeserialize>();
registry.register::<SomeDeserializableStruct>();
registry.register::<SomeEnum>();
registry.register::<SomeIgnoredEnum>();
registry.register::<i8>();
registry.register::<String>();
registry.register::<i64>();
registry.register::<f32>();
registry.register::<usize>();
registry.register::<i32>();
registry.register::<u8>();
registry.register::<(f32, usize)>();
registry.register::<[i32; 5]>();
registry.register::<Vec<i32>>();
registry.register::<HashMap<u8, usize>>();
registry.register::<HashSet<u8>>();
registry.register::<Option<SomeStruct>>();
registry.register::<Option<String>>();
registry.register_type_data::<Option<String>, ReflectDeserialize>();
registry
}
fn get_my_struct() -> MyStruct {
let mut map = <HashMap<_, _>>::default();
map.insert(64, 32);
let mut set = <HashSet<_>>::default();
set.insert(64);
MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
set_value: set,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 0 },
ignored_tuple_struct: SomeIgnoredTupleStruct(0),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::default(),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(0.0, 0.0),
custom_deserialize: CustomDeserialize {
value: 100,
inner_struct: SomeDeserializableStruct { foo: 101 },
},
}
}
#[test]
fn should_deserialize() {
let expected = get_my_struct();
let registry = get_registry();
let input = r#"{
"bevy_reflect::serde::de::tests::MyStruct": (
primitive_value: 123,
option_value: Some("Hello world!"),
option_value_complex: Some((
foo: 123,
)),
tuple_value: (3.1415927, 1337),
list_value: [
-2,
-1,
0,
1,
2,
],
array_value: (-2, -1, 0, 1, 2),
map_value: {
64: 32,
},
set_value: [
64,
],
struct_value: (
foo: 999999999,
),
tuple_struct_value: ("Tuple Struct"),
unit_struct: (),
unit_enum: Unit,
newtype_enum: NewType(123),
tuple_enum: Tuple(1.23, 3.21),
struct_enum: Struct(
foo: "Struct variant value",
),
ignored_struct: (),
ignored_tuple_struct: (),
ignored_struct_variant: Struct(),
ignored_tuple_variant: Tuple(),
custom_deserialize: (
value: 100,
renamed: (
foo: 101,
),
),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_deserialize_value() {
let input = r#"{
"f32": 1.23,
}"#;
let registry = get_registry();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = dynamic_output
.try_take::<f32>()
.expect("underlying type should be f32");
assert_eq!(1.23, output);
}
#[test]
fn should_deserialized_typed() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
}
let expected = Foo { bar: 123 };
let input = r#"(
bar: 123
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let reflect_deserializer = TypedReflectDeserializer::new(registration, &registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_deserialize_option() {
#[derive(Reflect, Debug, PartialEq)]
struct OptionTest {
none: Option<()>,
simple: Option<String>,
complex: Option<SomeStruct>,
}
let expected = OptionTest {
none: None,
simple: Some(String::from("Hello world!")),
complex: Some(SomeStruct { foo: 123 }),
};
let mut registry = get_registry();
registry.register::<OptionTest>();
registry.register::<Option<()>>();
// === Normal === //
let input = r#"{
"bevy_reflect::serde::de::tests::OptionTest": (
none: None,
simple: Some("Hello world!"),
complex: Some((
foo: 123,
)),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <OptionTest as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output, "failed to deserialize Options");
// === Implicit Some === //
let input = r#"
#![enable(implicit_some)]
{
"bevy_reflect::serde::de::tests::OptionTest": (
none: None,
simple: "Hello world!",
complex: (
foo: 123,
),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <OptionTest as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(
expected, output,
"failed to deserialize Options with implicit Some"
);
}
#[test]
fn enum_should_deserialize() {
#[derive(Reflect)]
enum MyEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { value: String },
}
let mut registry = get_registry();
registry.register::<MyEnum>();
// === Unit Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": Unit,
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Unit);
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
// === NewType Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": NewType(123),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::NewType(123));
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
// === Tuple Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": Tuple(1.23, 3.21),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Tuple(1.23, 3.21));
assert!(expected
.reflect_partial_eq(output.as_partial_reflect())
.unwrap());
// === Struct Variant === //
let input = r#"{
"bevy_reflect::serde::de::tests::MyEnum": Struct(
value: "I <3 Enums",
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Struct {
value: String::from("I <3 Enums"),
});
assert!(expected
.reflect_partial_eq(output.as_partial_reflect())
.unwrap());
}
// Regression test for https://github.com/bevyengine/bevy/issues/12462
#[test]
fn should_reserialize() {
let registry = get_registry();
let input1 = get_my_struct();
let serializer1 = ReflectSerializer::new(&input1, &registry);
let serialized1 = ron::ser::to_string(&serializer1).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized1).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let input2 = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let serializer2 = ReflectSerializer::new(input2.as_partial_reflect(), &registry);
let serialized2 = ron::ser::to_string(&serializer2).unwrap();
assert_eq!(serialized1, serialized2);
}
#[test]
fn should_deserialize_non_self_describing_binary() {
let expected = get_my_struct();
let registry = get_registry();
let input = vec![
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 114, 101, 102,
108, 101, 99, 116, 58, 58, 115, 101, 114, 100, 101, 58, 58, 100, 101, 58, 58, 116, 101,
115, 116, 115, 58, 58, 77, 121, 83, 116, 114, 117, 99, 116, 123, 1, 12, 0, 0, 0, 0, 0,
0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 1, 123, 0, 0, 0, 0, 0,
0, 0, 219, 15, 73, 64, 57, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255,
255, 255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 254, 255, 255, 255, 255,
255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 32, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 255, 201, 154, 59, 0, 0, 0, 0, 12, 0, 0,
0, 0, 0, 0, 0, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 0, 0, 0, 0, 1,
0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 164, 112, 157, 63, 164, 112, 77, 64, 3,
0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105,
97, 110, 116, 32, 118, 97, 108, 117, 101, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0,
0, 0, 101, 0, 0, 0, 0, 0, 0, 0,
];
let deserializer = ReflectDeserializer::new(&registry);
let config = bincode::config::standard().with_fixed_int_encoding();
let (dynamic_output, _read_bytes) =
bincode::serde::seed_decode_from_slice(deserializer, &input, config).unwrap();
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_deserialize_self_describing_binary() {
let expected = get_my_struct();
let registry = get_registry();
let input = vec![
129, 217, 40, 98, 101, 118, 121, 95, 114, 101, 102, 108, 101, 99, 116, 58, 58, 115,
101, 114, 100, 101, 58, 58, 100, 101, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77, 121,
83, 116, 114, 117, 99, 116, 220, 0, 20, 123, 172, 72, 101, 108, 108, 111, 32, 119, 111,
114, 108, 100, 33, 145, 123, 146, 202, 64, 73, 15, 219, 205, 5, 57, 149, 254, 255, 0,
1, 2, 149, 254, 255, 0, 1, 2, 129, 64, 32, 145, 64, 145, 206, 59, 154, 201, 255, 172,
84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 144, 164, 85, 110, 105, 116,
129, 167, 78, 101, 119, 84, 121, 112, 101, 123, 129, 165, 84, 117, 112, 108, 101, 146,
202, 63, 157, 112, 164, 202, 64, 77, 112, 164, 129, 166, 83, 116, 114, 117, 99, 116,
145, 180, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105, 97, 110, 116, 32, 118, 97,
108, 117, 101, 144, 144, 129, 166, 83, 116, 114, 117, 99, 116, 144, 129, 165, 84, 117,
112, 108, 101, 144, 146, 100, 145, 101,
];
let mut reader = std::io::BufReader::new(input.as_slice());
let deserializer = ReflectDeserializer::new(&registry);
let dynamic_output = deserializer
.deserialize(&mut rmp_serde::Deserializer::new(&mut reader))
.unwrap();
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_return_error_if_missing_type_data() {
let mut registry = TypeRegistry::new();
registry.register::<RangeInclusive<f32>>();
let input = r#"{"core::ops::RangeInclusive<f32>":(start:0.0,end:1.0)}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let error = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(error, ron::Error::Message("type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive<f32>`)".to_string()));
#[cfg(not(feature = "debug_stack"))]
assert_eq!(error, ron::Error::Message("type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()));
}
#[test]
fn should_use_processor_for_custom_deserialization() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct FooProcessor;
impl ReflectDeserializerProcessor for FooProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i64>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(456_i64)))
} else {
Ok(Err(deserializer))
}
}
}
let expected = Foo { bar: 123, qux: 456 };
let input = r#"(
bar: 123,
qux: 123,
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let mut processor = FooProcessor;
let reflect_deserializer =
TypedReflectDeserializer::with_processor(registration, &registry, &mut processor);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_use_processor_for_multiple_registrations() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct FooProcessor;
impl ReflectDeserializerProcessor for FooProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i32>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(123_i32)))
} else if registration.type_id() == TypeId::of::<i64>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(456_i64)))
} else {
Ok(Err(deserializer))
}
}
}
let expected = Foo { bar: 123, qux: 456 };
let input = r#"(
bar: 0,
qux: 0,
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let mut processor = FooProcessor;
let reflect_deserializer =
TypedReflectDeserializer::with_processor(registration, &registry, &mut processor);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).unwrap();
assert_eq!(expected, output);
}
#[test]
fn should_propagate_processor_deserialize_error() {
struct ErroringProcessor;
impl ReflectDeserializerProcessor for ErroringProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i32>() {
Err(serde::de::Error::custom("my custom deserialize error"))
} else {
Ok(Err(deserializer))
}
}
}
let registry = get_registry();
let input = r#"{"i32":123}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let mut processor = ErroringProcessor;
let reflect_deserializer = ReflectDeserializer::with_processor(&registry, &mut processor);
let error = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message("my custom deserialize error (stack: `i32`)".to_string())
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message("my custom deserialize error".to_string())
);
}
#[test]
fn should_access_local_scope_in_processor() {
struct ValueCountingProcessor<'a> {
values_found: &'a mut usize,
}
impl ReflectDeserializerProcessor for ValueCountingProcessor<'_> {
fn try_deserialize<'de, D>(
&mut self,
_: &TypeRegistration,
_: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
let _ = deserializer.deserialize_ignored_any(IgnoredAny)?;
*self.values_found += 1;
Ok(Ok(Box::new(123_i32)))
}
}
let registry = get_registry();
let input = r#"{"i32":0}"#;
let mut values_found = 0_usize;
let mut deserializer_processor = ValueCountingProcessor {
values_found: &mut values_found,
};
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer =
ReflectDeserializer::with_processor(&registry, &mut deserializer_processor);
reflect_deserializer.deserialize(&mut deserializer).unwrap();
assert_eq!(1, values_found);
}
#[test]
fn should_fail_from_reflect_if_processor_returns_wrong_typed_value() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct WrongTypeProcessor;
impl ReflectDeserializerProcessor for WrongTypeProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
if registration.type_id() == TypeId::of::<i32>() {
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(42_i64)))
} else {
Ok(Err(deserializer))
}
}
}
let input = r#"(
bar: 123,
qux: 123,
)"#;
let mut registry = get_registry();
registry.register::<Foo>();
let registration = registry.get(TypeId::of::<Foo>()).unwrap();
let mut processor = WrongTypeProcessor;
let reflect_deserializer =
TypedReflectDeserializer::with_processor(registration, &registry, &mut processor);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap();
assert!(<Foo as FromReflect>::from_reflect(dynamic_output.as_partial_reflect()).is_none());
}
#[cfg(feature = "functions")]
mod functions {
use super::*;
use crate::func::DynamicFunction;
#[test]
fn should_not_deserialize_function() {
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct MyStruct {
func: DynamicFunction<'static>,
}
let mut registry = TypeRegistry::new();
registry.register::<MyStruct>();
let input = r#"{
"bevy_reflect::serde::de::tests::functions::MyStruct": (
func: (),
),
}"#;
let reflect_deserializer = ReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let error = reflect_deserializer
.deserialize(&mut ron_deserializer)
.unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message(
"no registration found for type `bevy_reflect::DynamicFunction` (stack: `bevy_reflect::serde::de::tests::functions::MyStruct`)"
.to_string()
)
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message(
"no registration found for type `bevy_reflect::DynamicFunction`".to_string()
)
);
}
}
#[cfg(feature = "debug_stack")]
mod debug_stack {
use super::*;
#[test]
fn should_report_context_in_errors() {
#[derive(Reflect)]
struct Foo {
bar: Bar,
}
#[derive(Reflect)]
struct Bar {
some_other_field: Option<u32>,
baz: Baz,
}
#[derive(Reflect)]
struct Baz {
value: Vec<RangeInclusive<f32>>,
}
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
registry.register::<Bar>();
registry.register::<Baz>();
registry.register::<RangeInclusive<f32>>();
let input = r#"{"bevy_reflect::serde::de::tests::debug_stack::Foo":(bar:(some_other_field:Some(123),baz:(value:[(start:0.0,end:1.0)])))}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let error = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap_err();
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `bevy_reflect::serde::de::tests::debug_stack::Foo` -> `bevy_reflect::serde::de::tests::debug_stack::Bar` -> `bevy_reflect::serde::de::tests::debug_stack::Baz` -> `alloc::vec::Vec<core::ops::RangeInclusive<f32>>` -> `core::ops::RangeInclusive<f32>`)".to_string()
)
);
}
}
}

View File

@@ -0,0 +1,63 @@
use crate::{
serde::{
de::{error_utils::make_custom_error, registration_utils::try_get_registration},
TypedReflectDeserializer,
},
DynamicEnum, DynamicTuple, EnumInfo, TypeRegistry, VariantInfo,
};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, Error, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Option`] values.
pub(super) struct OptionVisitor<'a, P> {
pub enum_info: &'static EnumInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for OptionVisitor<'_, P> {
type Value = DynamicEnum;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected option value of type ")?;
formatter.write_str(self.enum_info.type_path())
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
let mut option = DynamicEnum::default();
option.set_variant("None", ());
Ok(option)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let variant_info = self.enum_info.variant("Some").unwrap();
match variant_info {
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
let field = tuple_info.field_at(0).unwrap();
let registration = try_get_registration(*field.ty(), self.registry)?;
let de = TypedReflectDeserializer::new_internal(
registration,
self.registry,
self.processor,
);
let mut value = DynamicTuple::default();
value.insert_boxed(de.deserialize(deserializer)?);
let mut option = DynamicEnum::default();
option.set_variant("Some", value);
Ok(option)
}
info => Err(make_custom_error(format_args!(
"invalid variant, expected `Some` but got `{}`",
info.name()
))),
}
}
}

View File

@@ -0,0 +1,217 @@
use crate::{PartialReflect, TypeRegistration, TypeRegistry};
use alloc::boxed::Box;
/// Allows overriding the default deserialization behavior of
/// [`ReflectDeserializer`] and [`TypedReflectDeserializer`] for specific
/// [`TypeRegistration`]s.
///
/// When deserializing a reflected value, you may want to override the default
/// behavior and use your own logic for deserialization. This logic may also
/// be context-dependent, and only apply for a single use of your
/// [`ReflectDeserializer`]. To achieve this, you can create a processor and
/// pass it in to your deserializer.
///
/// Whenever the deserializer attempts to deserialize a value, it will first
/// call [`try_deserialize`] on your processor, which may take ownership of the
/// deserializer and give back a [`Box<dyn PartialReflect>`], or return
/// ownership of the deserializer back, and continue with the default logic.
///
/// The serialization equivalent of this is [`ReflectSerializerProcessor`].
///
/// # Compared to [`DeserializeWithRegistry`]
///
/// [`DeserializeWithRegistry`] allows you to define how your type will be
/// deserialized by a [`TypedReflectDeserializer`], given the extra context of
/// the [`TypeRegistry`]. If your type can be deserialized entirely from that,
/// then you should prefer implementing that trait instead of using a processor.
///
/// However, you may need more context-dependent data which is only present in
/// the scope where you create the [`TypedReflectDeserializer`]. For example, in
/// an asset loader, the `&mut LoadContext` you get is only valid from within
/// the `load` function. This is where a processor is useful, as the processor
/// can capture local variables.
///
/// A [`ReflectDeserializerProcessor`] always takes priority over a
/// [`DeserializeWithRegistry`] implementation, so this is also useful for
/// overriding deserialization behavior if you need to do something custom.
///
/// # Examples
///
/// Deserializing a reflected value in an asset loader, and replacing asset
/// handles with a loaded equivalent:
///
/// ```
/// # use bevy_reflect::serde::{ReflectDeserializer, ReflectDeserializerProcessor};
/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistration, TypeRegistry};
/// # use serde::de::{DeserializeSeed, Deserializer, Visitor};
/// # use std::marker::PhantomData;
/// #
/// # #[derive(Debug, Clone, Reflect)]
/// # struct LoadedUntypedAsset;
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Handle<T: Reflect>(T);
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Mesh;
/// #
/// # struct LoadContext;
/// # impl LoadContext {
/// # fn load(&mut self) -> &mut Self { unimplemented!() }
/// # fn with_asset_type_id(&mut self, (): ()) -> &mut Self { unimplemented!() }
/// # fn untyped(&mut self) -> &mut Self { unimplemented!() }
/// # fn load_asset(&mut self, (): ()) -> Handle<LoadedUntypedAsset> { unimplemented!() }
/// # }
/// #
/// # struct ReflectHandle;
/// # impl TypeData for ReflectHandle {
/// # fn clone_type_data(&self) -> Box<dyn TypeData> {
/// # unimplemented!()
/// # }
/// # }
/// # impl ReflectHandle {
/// # fn asset_type_id(&self) {
/// # unimplemented!()
/// # }
/// # }
/// #
/// # struct AssetPathVisitor;
/// # impl<'de> Visitor<'de> for AssetPathVisitor {
/// # type Value = ();
/// # fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() }
/// # }
/// # type AssetError = Box<dyn core::error::Error>;
/// #[derive(Debug, Clone, Reflect)]
/// struct MyAsset {
/// name: String,
/// mesh: Handle<Mesh>,
/// }
///
/// fn load(
/// asset_bytes: &[u8],
/// type_registry: &TypeRegistry,
/// load_context: &mut LoadContext,
/// ) -> Result<MyAsset, AssetError> {
/// struct HandleProcessor<'a> {
/// load_context: &'a mut LoadContext,
/// }
///
/// impl ReflectDeserializerProcessor for HandleProcessor<'_> {
/// fn try_deserialize<'de, D>(
/// &mut self,
/// registration: &TypeRegistration,
/// _registry: &TypeRegistry,
/// deserializer: D,
/// ) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
/// where
/// D: Deserializer<'de>,
/// {
/// let Some(reflect_handle) = registration.data::<ReflectHandle>() else {
/// // we don't want to deserialize this - give the deserializer back
/// return Ok(Err(deserializer));
/// };
///
/// let asset_type_id = reflect_handle.asset_type_id();
/// let asset_path = deserializer.deserialize_str(AssetPathVisitor)?;
///
/// let handle: Handle<LoadedUntypedAsset> = self.load_context
/// .load()
/// .with_asset_type_id(asset_type_id)
/// .untyped()
/// .load_asset(asset_path);
/// # let _: Result<_, ()> = {
/// Ok(Box::new(handle))
/// # };
/// # unimplemented!()
/// }
/// }
///
/// let mut ron_deserializer = ron::Deserializer::from_bytes(asset_bytes)?;
/// let mut processor = HandleProcessor { load_context };
/// let reflect_deserializer =
/// ReflectDeserializer::with_processor(type_registry, &mut processor);
/// let asset = reflect_deserializer.deserialize(&mut ron_deserializer)?;
/// # unimplemented!()
/// }
/// ```
///
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [`try_deserialize`]: Self::try_deserialize
/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry
/// [`ReflectSerializerProcessor`]: crate::serde::ReflectSerializerProcessor
pub trait ReflectDeserializerProcessor {
/// Attempts to deserialize the value which a [`TypedReflectDeserializer`]
/// is currently looking at, and knows the type of.
///
/// If you've read the `registration` and want to override the default
/// deserialization, return `Ok(Ok(value))` with the boxed reflected value
/// that you want to assign this value to. The type inside the box must
/// be the same one as the `registration` is for, otherwise future
/// reflection operations (such as using [`FromReflect`] to convert the
/// resulting [`Box<dyn PartialReflect>`] into a concrete type) will fail.
///
/// If you don't want to override the deserialization, return ownership of
/// the deserializer back via `Ok(Err(deserializer))`.
///
/// Note that, if you do want to return a value, you *must* read from the
/// deserializer passed to this function (you are free to ignore the result
/// though). Otherwise, the deserializer will be in an inconsistent state,
/// and future value parsing will fail.
///
/// # Examples
///
/// Correct way to return a constant value (not using any output from the
/// deserializer):
///
/// ```
/// # use bevy_reflect::{TypeRegistration, PartialReflect, TypeRegistry};
/// # use bevy_reflect::serde::ReflectDeserializerProcessor;
/// # use core::any::TypeId;
/// use serde::de::IgnoredAny;
///
/// struct ConstantI32Processor;
///
/// impl ReflectDeserializerProcessor for ConstantI32Processor {
/// fn try_deserialize<'de, D>(
/// &mut self,
/// registration: &TypeRegistration,
/// _registry: &TypeRegistry,
/// deserializer: D,
/// ) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
/// where
/// D: serde::Deserializer<'de>
/// {
/// if registration.type_id() == TypeId::of::<i32>() {
/// _ = deserializer.deserialize_ignored_any(IgnoredAny);
/// Ok(Ok(Box::new(42_i32)))
/// } else {
/// Ok(Err(deserializer))
/// }
/// }
/// }
/// ```
///
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [`FromReflect`]: crate::FromReflect
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: serde::Deserializer<'de>;
}
impl ReflectDeserializerProcessor for () {
fn try_deserialize<'de, D>(
&mut self,
_registration: &TypeRegistration,
_registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Err(deserializer))
}
}

View File

@@ -0,0 +1,15 @@
use crate::{serde::de::error_utils::make_custom_error, Type, TypeRegistration, TypeRegistry};
use serde::de::Error;
/// Attempts to find the [`TypeRegistration`] for a given [type].
///
/// [type]: Type
pub(super) fn try_get_registration<E: Error>(
ty: Type,
registry: &TypeRegistry,
) -> Result<&TypeRegistration, E> {
let registration = registry.get(ty.id()).ok_or_else(|| {
make_custom_error(format_args!("no registration found for type `{ty:?}`"))
})?;
Ok(registration)
}

View File

@@ -0,0 +1,51 @@
use crate::{serde::de::error_utils::make_custom_error, TypeRegistration, TypeRegistry};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, Error, Visitor};
/// A deserializer for type registrations.
///
/// This will return a [`&TypeRegistration`] corresponding to the given type.
/// This deserializer expects a string containing the _full_ [type path] of the
/// type to find the `TypeRegistration` of.
///
/// [`&TypeRegistration`]: TypeRegistration
/// [type path]: crate::TypePath::type_path
pub struct TypeRegistrationDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a> TypeRegistrationDeserializer<'a> {
pub fn new(registry: &'a TypeRegistry) -> Self {
Self { registry }
}
}
impl<'a, 'de> DeserializeSeed<'de> for TypeRegistrationDeserializer<'a> {
type Value = &'a TypeRegistration;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
struct TypeRegistrationVisitor<'a>(&'a TypeRegistry);
impl<'de, 'a> Visitor<'de> for TypeRegistrationVisitor<'a> {
type Value = &'a TypeRegistration;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("string containing `type` entry for the reflected value")
}
fn visit_str<E>(self, type_path: &str) -> Result<Self::Value, E>
where
E: Error,
{
self.0.get_with_type_path(type_path).ok_or_else(|| {
make_custom_error(format_args!("no registration found for `{type_path}`"))
})
}
}
deserializer.deserialize_str(TypeRegistrationVisitor(self.registry))
}
}

View File

@@ -0,0 +1,42 @@
use crate::{
serde::{de::registration_utils::try_get_registration, TypedReflectDeserializer},
DynamicSet, Set, SetInfo, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Set`] values.
///
/// [`Set`]: crate::Set
pub(super) struct SetVisitor<'a, P> {
pub set_info: &'static SetInfo,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for SetVisitor<'_, P> {
type Value = DynamicSet;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected set value")
}
fn visit_seq<V>(mut self, mut set: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut dynamic_set = DynamicSet::default();
let value_registration = try_get_registration(self.set_info.value_ty(), self.registry)?;
while let Some(value) = set.next_element_seed(TypedReflectDeserializer::new_internal(
value_registration,
self.registry,
self.processor.as_deref_mut(),
))? {
dynamic_set.insert_boxed(value);
}
Ok(dynamic_set)
}
}

View File

@@ -0,0 +1,185 @@
use crate::{
serde::{
de::{
error_utils::make_custom_error,
helpers::{ExpectedValues, Ident},
registration_utils::try_get_registration,
},
SerializationData, TypedReflectDeserializer,
},
DynamicStruct, NamedField, StructInfo, StructVariantInfo, TypeRegistration, TypeRegistry,
};
use alloc::string::ToString;
use core::slice::Iter;
use serde::de::{Error, MapAccess, SeqAccess};
use super::ReflectDeserializerProcessor;
/// A helper trait for accessing type information from struct-like types.
pub(super) trait StructLikeInfo {
fn field<E: Error>(&self, name: &str) -> Result<&NamedField, E>;
fn field_at<E: Error>(&self, index: usize) -> Result<&NamedField, E>;
fn field_len(&self) -> usize;
fn iter_fields(&self) -> Iter<'_, NamedField>;
}
impl StructLikeInfo for StructInfo {
fn field<E: Error>(&self, name: &str) -> Result<&NamedField, E> {
Self::field(self, name).ok_or_else(|| {
make_custom_error(format_args!(
"no field named `{}` on struct `{}`",
name,
self.type_path(),
))
})
}
fn field_at<E: Error>(&self, index: usize) -> Result<&NamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on struct `{}`",
index,
self.type_path(),
))
})
}
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn iter_fields(&self) -> Iter<'_, NamedField> {
self.iter()
}
}
impl StructLikeInfo for StructVariantInfo {
fn field<E: Error>(&self, name: &str) -> Result<&NamedField, E> {
Self::field(self, name).ok_or_else(|| {
make_custom_error(format_args!(
"no field named `{}` on variant `{}`",
name,
self.name(),
))
})
}
fn field_at<E: Error>(&self, index: usize) -> Result<&NamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on variant `{}`",
index,
self.name(),
))
})
}
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn iter_fields(&self) -> Iter<'_, NamedField> {
self.iter()
}
}
/// Deserializes a [struct-like] type from a mapping of fields, returning a [`DynamicStruct`].
///
/// [struct-like]: StructLikeInfo
pub(super) fn visit_struct<'de, T, V, P>(
map: &mut V,
info: &'static T,
registration: &TypeRegistration,
registry: &TypeRegistry,
mut processor: Option<&mut P>,
) -> Result<DynamicStruct, V::Error>
where
T: StructLikeInfo,
V: MapAccess<'de>,
P: ReflectDeserializerProcessor,
{
let mut dynamic_struct = DynamicStruct::default();
while let Some(Ident(key)) = map.next_key::<Ident>()? {
let field = info.field::<V::Error>(&key).map_err(|_| {
let fields = info.iter_fields().map(NamedField::name);
make_custom_error(format_args!(
"unknown field `{}`, expected one of {:?}",
key,
ExpectedValues::from_iter(fields)
))
})?;
let registration = try_get_registration(*field.ty(), registry)?;
let value = map.next_value_seed(TypedReflectDeserializer::new_internal(
registration,
registry,
processor.as_deref_mut(),
))?;
dynamic_struct.insert_boxed(&key, value);
}
if let Some(serialization_data) = registration.data::<SerializationData>() {
for (skipped_index, skipped_field) in serialization_data.iter_skipped() {
let Ok(field) = info.field_at::<V::Error>(*skipped_index) else {
continue;
};
dynamic_struct.insert_boxed(
field.name(),
skipped_field.generate_default().into_partial_reflect(),
);
}
}
Ok(dynamic_struct)
}
/// Deserializes a [struct-like] type from a sequence of fields, returning a [`DynamicStruct`].
///
/// [struct-like]: StructLikeInfo
pub(super) fn visit_struct_seq<'de, T, V, P>(
seq: &mut V,
info: &T,
registration: &TypeRegistration,
registry: &TypeRegistry,
mut processor: Option<&mut P>,
) -> Result<DynamicStruct, V::Error>
where
T: StructLikeInfo,
V: SeqAccess<'de>,
P: ReflectDeserializerProcessor,
{
let mut dynamic_struct = DynamicStruct::default();
let len = info.field_len();
if len == 0 {
// Handle unit structs
return Ok(dynamic_struct);
}
let serialization_data = registration.data::<SerializationData>();
for index in 0..len {
let name = info.field_at::<V::Error>(index)?.name();
if serialization_data
.map(|data| data.is_field_skipped(index))
.unwrap_or_default()
{
if let Some(value) = serialization_data.unwrap().generate_default(index) {
dynamic_struct.insert_boxed(name, value.into_partial_reflect());
}
continue;
}
let value = seq
.next_element_seed(TypedReflectDeserializer::new_internal(
try_get_registration(*info.field_at(index)?.ty(), registry)?,
registry,
processor.as_deref_mut(),
))?
.ok_or_else(|| Error::invalid_length(index, &len.to_string().as_str()))?;
dynamic_struct.insert_boxed(name, value);
}
Ok(dynamic_struct)
}

View File

@@ -0,0 +1,52 @@
use crate::{
serde::de::struct_utils::{visit_struct, visit_struct_seq},
DynamicStruct, StructInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{MapAccess, SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Struct`] values.
///
/// [`Struct`]: crate::Struct
pub(super) struct StructVisitor<'a, P> {
pub struct_info: &'static StructInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVisitor<'_, P> {
type Value = DynamicStruct;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected struct value")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
visit_struct_seq(
&mut seq,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
visit_struct(
&mut map,
self.struct_info,
self.registration,
self.registry,
self.processor,
)
}
}

View File

@@ -0,0 +1,71 @@
use crate::{
serde::{de::tuple_utils::visit_tuple, SerializationData},
DynamicTupleStruct, TupleStructInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{DeserializeSeed, SeqAccess, Visitor};
use super::{registration_utils::try_get_registration, TypedReflectDeserializer};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`TupleStruct`] values.
///
/// [`TupleStruct`]: crate::TupleStruct
pub(super) struct TupleStructVisitor<'a, P> {
pub tuple_struct_info: &'static TupleStructInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleStructVisitor<'_, P> {
type Value = DynamicTupleStruct;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected tuple struct value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
visit_tuple(
&mut seq,
self.tuple_struct_info,
self.registration,
self.registry,
self.processor,
)
.map(DynamicTupleStruct::from)
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut tuple = DynamicTupleStruct::default();
let serialization_data = self.registration.data::<SerializationData>();
if let Some(value) = serialization_data.and_then(|data| data.generate_default(0)) {
tuple.insert_boxed(value.into_partial_reflect());
return Ok(tuple);
}
let registration = try_get_registration(
*self
.tuple_struct_info
.field_at(0)
.ok_or(serde::de::Error::custom("Field at index 0 not found"))?
.ty(),
self.registry,
)?;
let reflect_deserializer =
TypedReflectDeserializer::new_internal(registration, self.registry, self.processor);
let value = reflect_deserializer.deserialize(deserializer)?;
tuple.insert_boxed(value.into_partial_reflect());
Ok(tuple)
}
}

View File

@@ -0,0 +1,110 @@
use crate::{
serde::{
de::{error_utils::make_custom_error, registration_utils::try_get_registration},
SerializationData, TypedReflectDeserializer,
},
DynamicTuple, TupleInfo, TupleStructInfo, TupleVariantInfo, TypeRegistration, TypeRegistry,
UnnamedField,
};
use alloc::string::ToString;
use serde::de::{Error, SeqAccess};
use super::ReflectDeserializerProcessor;
pub(super) trait TupleLikeInfo {
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E>;
fn field_len(&self) -> usize;
}
impl TupleLikeInfo for TupleInfo {
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on tuple `{}`",
index,
self.type_path(),
))
})
}
}
impl TupleLikeInfo for TupleStructInfo {
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on tuple struct `{}`",
index,
self.type_path(),
))
})
}
}
impl TupleLikeInfo for TupleVariantInfo {
fn field_len(&self) -> usize {
Self::field_len(self)
}
fn field_at<E: Error>(&self, index: usize) -> Result<&UnnamedField, E> {
Self::field_at(self, index).ok_or_else(|| {
make_custom_error(format_args!(
"no field at index `{}` on tuple variant `{}`",
index,
self.name(),
))
})
}
}
/// Deserializes a [tuple-like] type from a sequence of elements, returning a [`DynamicTuple`].
///
/// [tuple-like]: TupleLikeInfo
pub(super) fn visit_tuple<'de, T, V, P>(
seq: &mut V,
info: &T,
registration: &TypeRegistration,
registry: &TypeRegistry,
mut processor: Option<&mut P>,
) -> Result<DynamicTuple, V::Error>
where
T: TupleLikeInfo,
V: SeqAccess<'de>,
P: ReflectDeserializerProcessor,
{
let mut tuple = DynamicTuple::default();
let len = info.field_len();
if len == 0 {
// Handle empty tuple/tuple struct
return Ok(tuple);
}
let serialization_data = registration.data::<SerializationData>();
for index in 0..len {
if let Some(value) = serialization_data.and_then(|data| data.generate_default(index)) {
tuple.insert_boxed(value.into_partial_reflect());
continue;
}
let value = seq
.next_element_seed(TypedReflectDeserializer::new_internal(
try_get_registration(*info.field_at(index)?.ty(), registry)?,
registry,
processor.as_deref_mut(),
))?
.ok_or_else(|| Error::invalid_length(index, &len.to_string().as_str()))?;
tuple.insert_boxed(value);
}
Ok(tuple)
}

View File

@@ -0,0 +1,38 @@
use crate::{
serde::de::tuple_utils::visit_tuple, DynamicTuple, TupleInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
/// A [`Visitor`] for deserializing [`Tuple`] values.
///
/// [`Tuple`]: crate::Tuple
pub(super) struct TupleVisitor<'a, P> {
pub tuple_info: &'static TupleInfo,
pub registration: &'a TypeRegistration,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a mut P>,
}
impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleVisitor<'_, P> {
type Value = DynamicTuple;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("reflected tuple value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
visit_tuple(
&mut seq,
self.tuple_info,
self.registration,
self.registry,
self.processor,
)
}
}

476
vendor/bevy_reflect/src/serde/mod.rs vendored Normal file
View File

@@ -0,0 +1,476 @@
mod de;
mod ser;
mod type_data;
pub use de::*;
pub use ser::*;
pub use type_data::*;
#[cfg(test)]
mod tests {
use super::*;
use crate::{
type_registry::TypeRegistry, DynamicStruct, DynamicTupleStruct, FromReflect,
PartialReflect, Reflect, Struct,
};
use serde::de::DeserializeSeed;
#[test]
fn test_serialization_struct() {
#[derive(Debug, Reflect, PartialEq)]
#[reflect(PartialEq)]
struct TestStruct {
a: i32,
#[reflect(ignore)]
b: i32,
#[reflect(skip_serializing)]
c: i32,
#[reflect(skip_serializing)]
#[reflect(default = "custom_default")]
d: i32,
e: i32,
}
fn custom_default() -> i32 {
-1
}
let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();
let test_struct = TestStruct {
a: 3,
b: 4,
c: 5,
d: 6,
e: 7,
};
let serializer = ReflectSerializer::new(&test_struct, &registry);
let serialized =
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let mut expected = DynamicStruct::default();
expected.insert("a", 3);
// Ignored: expected.insert("b", 0);
expected.insert("c", 0);
expected.insert("d", -1);
expected.insert("e", 7);
assert!(
expected
.reflect_partial_eq(deserialized.as_partial_reflect())
.unwrap(),
"Deserialization failed: expected {expected:?} found {deserialized:?}"
);
let expected = TestStruct {
a: 3,
b: 0,
c: 0,
d: -1,
e: 7,
};
let received =
<TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
assert_eq!(
expected, received,
"FromReflect failed: expected {expected:?} found {received:?}"
);
}
#[test]
fn test_serialization_tuple_struct() {
#[derive(Debug, Reflect, PartialEq)]
#[reflect(PartialEq)]
struct TestStruct(
i32,
#[reflect(ignore)] i32,
#[reflect(skip_serializing)] i32,
#[reflect(skip_serializing)]
#[reflect(default = "custom_default")]
i32,
i32,
);
fn custom_default() -> i32 {
-1
}
let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();
let test_struct = TestStruct(3, 4, 5, 6, 7);
let serializer = ReflectSerializer::new(&test_struct, &registry);
let serialized =
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let mut expected = DynamicTupleStruct::default();
expected.insert(3);
// Ignored: expected.insert(0);
expected.insert(0);
expected.insert(-1);
expected.insert(7);
assert!(
expected
.reflect_partial_eq(deserialized.as_partial_reflect())
.unwrap(),
"Deserialization failed: expected {expected:?} found {deserialized:?}"
);
let expected = TestStruct(3, 0, 0, -1, 7);
let received =
<TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
assert_eq!(
expected, received,
"FromReflect failed: expected {expected:?} found {received:?}"
);
}
#[test]
#[should_panic(
expected = "cannot serialize dynamic value without represented type: `bevy_reflect::DynamicStruct`"
)]
fn should_not_serialize_unproxied_dynamic() {
let registry = TypeRegistry::default();
let mut value = DynamicStruct::default();
value.insert("foo", 123_u32);
let serializer = ReflectSerializer::new(&value, &registry);
ron::ser::to_string(&serializer).unwrap();
}
#[test]
fn should_roundtrip_proxied_dynamic() {
#[derive(Reflect)]
struct TestStruct {
a: i32,
b: i32,
}
let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();
let value: DynamicStruct = TestStruct { a: 123, b: 456 }.to_dynamic_struct();
let serializer = ReflectSerializer::new(&value, &registry);
let expected = r#"{"bevy_reflect::serde::tests::TestStruct":(a:123,b:456)}"#;
let result = ron::ser::to_string(&serializer).unwrap();
assert_eq!(expected, result);
let mut deserializer = ron::de::Deserializer::from_str(&result).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let expected = value.to_dynamic();
let result = reflect_deserializer.deserialize(&mut deserializer).unwrap();
assert!(expected
.reflect_partial_eq(result.as_partial_reflect())
.unwrap());
}
mod type_data {
use super::*;
use crate::from_reflect::FromReflect;
use crate::serde::{DeserializeWithRegistry, ReflectDeserializeWithRegistry};
use crate::serde::{ReflectSerializeWithRegistry, SerializeWithRegistry};
use crate::{ReflectFromReflect, TypePath};
use alloc::{format, string::String, vec, vec::Vec};
use bevy_platform::sync::Arc;
use bevy_reflect_derive::reflect_trait;
use core::any::TypeId;
use core::fmt::{Debug, Formatter};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserializer, Serialize, Serializer};
#[reflect_trait]
trait Enemy: Reflect + Debug {
#[expect(dead_code, reason = "this method is purely for testing purposes")]
fn hp(&self) -> u8;
}
// This is needed to support Arc<dyn Enemy>
impl TypePath for dyn Enemy {
fn type_path() -> &'static str {
"dyn bevy_reflect::serde::tests::type_data::Enemy"
}
fn short_type_path() -> &'static str {
"dyn Enemy"
}
}
#[derive(Reflect, Debug)]
#[reflect(Enemy)]
struct Skeleton(u8);
impl Enemy for Skeleton {
fn hp(&self) -> u8 {
self.0
}
}
#[derive(Reflect, Debug)]
#[reflect(Enemy)]
struct Zombie {
health: u8,
walk_speed: f32,
}
impl Enemy for Zombie {
fn hp(&self) -> u8 {
self.health
}
}
#[derive(Reflect, Debug)]
struct Level {
name: String,
enemies: EnemyList,
}
#[derive(Reflect, Debug)]
#[reflect(SerializeWithRegistry, DeserializeWithRegistry)]
// Note that we have to use `Arc` instead of `Box` here due to the
// former being the only one between the two to implement `Reflect`.
struct EnemyList(Vec<Arc<dyn Enemy>>);
impl SerializeWithRegistry for EnemyList {
fn serialize<S>(
&self,
serializer: S,
registry: &TypeRegistry,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_seq(Some(self.0.len()))?;
for enemy in &self.0 {
state.serialize_element(&ReflectSerializer::new(
(**enemy).as_partial_reflect(),
registry,
))?;
}
state.end()
}
}
impl<'de> DeserializeWithRegistry<'de> for EnemyList {
fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct EnemyListVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for EnemyListVisitor<'a> {
type Value = Vec<Arc<dyn Enemy>>;
fn expecting(&self, formatter: &mut Formatter) -> core::fmt::Result {
write!(formatter, "a list of enemies")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut enemies = Vec::new();
while let Some(enemy) =
seq.next_element_seed(ReflectDeserializer::new(self.registry))?
{
let registration = self
.registry
.get_with_type_path(
enemy.get_represented_type_info().unwrap().type_path(),
)
.unwrap();
// 1. Convert any possible dynamic values to concrete ones
let enemy = registration
.data::<ReflectFromReflect>()
.unwrap()
.from_reflect(&*enemy)
.unwrap();
// 2. Convert the concrete value to a boxed trait object
let enemy = registration
.data::<ReflectEnemy>()
.unwrap()
.get_boxed(enemy)
.unwrap();
enemies.push(enemy.into());
}
Ok(enemies)
}
}
deserializer
.deserialize_seq(EnemyListVisitor { registry })
.map(EnemyList)
}
}
fn create_registry() -> TypeRegistry {
let mut registry = TypeRegistry::default();
registry.register::<Level>();
registry.register::<EnemyList>();
registry.register::<Skeleton>();
registry.register::<Zombie>();
registry
}
fn create_arc_dyn_enemy<T: Enemy>(enemy: T) -> Arc<dyn Enemy> {
let arc = Arc::new(enemy);
#[cfg(not(target_has_atomic = "ptr"))]
#[expect(
unsafe_code,
reason = "unsized coercion is an unstable feature for non-std types"
)]
// SAFETY:
// - Coercion from `T` to `dyn Enemy` is valid as `T: Enemy + 'static`
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
let arc = unsafe { Arc::from_raw(Arc::into_raw(arc) as *const dyn Enemy) };
arc
}
#[test]
fn should_serialize_with_serialize_with_registry() {
let registry = create_registry();
let level = Level {
name: String::from("Level 1"),
enemies: EnemyList(vec![
create_arc_dyn_enemy(Skeleton(10)),
create_arc_dyn_enemy(Zombie {
health: 20,
walk_speed: 0.5,
}),
]),
};
let serializer = ReflectSerializer::new(&level, &registry);
let serialized = ron::ser::to_string(&serializer).unwrap();
let expected = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#;
assert_eq!(expected, serialized);
}
#[test]
fn should_deserialize_with_deserialize_with_registry() {
let registry = create_registry();
let input = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#;
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let output = Level::from_reflect(&*value).unwrap();
let expected = Level {
name: String::from("Level 1"),
enemies: EnemyList(vec![
create_arc_dyn_enemy(Skeleton(10)),
create_arc_dyn_enemy(Zombie {
health: 20,
walk_speed: 0.5,
}),
]),
};
// Poor man's comparison since we can't derive PartialEq for Arc<dyn Enemy>
assert_eq!(format!("{:?}", expected), format!("{:?}", output));
let unexpected = Level {
name: String::from("Level 1"),
enemies: EnemyList(vec![
create_arc_dyn_enemy(Skeleton(20)),
create_arc_dyn_enemy(Zombie {
health: 20,
walk_speed: 5.0,
}),
]),
};
// Poor man's comparison since we can't derive PartialEq for Arc<dyn Enemy>
assert_ne!(format!("{:?}", unexpected), format!("{:?}", output));
}
#[test]
fn should_serialize_single_tuple_struct_as_newtype() {
#[derive(Reflect, Serialize, PartialEq, Debug)]
struct TupleStruct(u32);
#[derive(Reflect, Serialize, PartialEq, Debug)]
struct TupleStructWithSkip(
u32,
#[reflect(skip_serializing)]
#[serde(skip)]
u32,
);
#[derive(Reflect, Serialize, PartialEq, Debug)]
enum Enum {
TupleStruct(usize),
NestedTupleStruct(TupleStruct),
NestedTupleStructWithSkip(TupleStructWithSkip),
}
let mut registry = TypeRegistry::default();
registry.register::<TupleStruct>();
registry.register::<TupleStructWithSkip>();
registry.register::<Enum>();
let tuple_struct = TupleStruct(1);
let tuple_struct_with_skip = TupleStructWithSkip(2, 3);
let tuple_struct_enum = Enum::TupleStruct(4);
let nested_tuple_struct = Enum::NestedTupleStruct(TupleStruct(5));
let nested_tuple_struct_with_skip =
Enum::NestedTupleStructWithSkip(TupleStructWithSkip(6, 7));
fn assert_serialize<T: Reflect + FromReflect + Serialize + PartialEq + Debug>(
value: &T,
registry: &TypeRegistry,
) {
let serializer = TypedReflectSerializer::new(value, registry);
let reflect_serialize = serde_json::to_string(&serializer).unwrap();
let serde_serialize = serde_json::to_string(value).unwrap();
assert_eq!(reflect_serialize, serde_serialize);
let registration = registry.get(TypeId::of::<T>()).unwrap();
let reflect_deserializer = TypedReflectDeserializer::new(registration, registry);
let mut deserializer = serde_json::Deserializer::from_str(&serde_serialize);
let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let _ = T::from_reflect(&*reflect_value).unwrap();
}
assert_serialize(&tuple_struct, &registry);
assert_serialize(&tuple_struct_with_skip, &registry);
assert_serialize(&tuple_struct_enum, &registry);
assert_serialize(&nested_tuple_struct, &registry);
assert_serialize(&nested_tuple_struct_with_skip, &registry);
}
}
}

View File

@@ -0,0 +1,28 @@
use crate::{serde::TypedReflectSerializer, Array, TypeRegistry};
use serde::{ser::SerializeTuple, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Array`] values.
pub(super) struct ArraySerializer<'a, P> {
pub array: &'a dyn Array,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for ArraySerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_tuple(self.array.len())?;
for value in self.array.iter() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,62 @@
use crate::serde::ser::error_utils::make_custom_error;
#[cfg(feature = "debug_stack")]
use crate::serde::ser::error_utils::TYPE_INFO_STACK;
use crate::serde::ReflectSerializeWithRegistry;
use crate::{PartialReflect, ReflectSerialize, TypeRegistry};
use core::borrow::Borrow;
use serde::{Serialize, Serializer};
/// Attempts to serialize a [`PartialReflect`] value with custom [`ReflectSerialize`]
/// or [`ReflectSerializeWithRegistry`] type data.
///
/// On success, returns the result of the serialization.
/// On failure, returns the original serializer and the error that occurred.
pub(super) fn try_custom_serialize<S: Serializer>(
value: &dyn PartialReflect,
type_registry: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S::Error>, (S, S::Error)> {
let Some(value) = value.try_as_reflect() else {
return Err((
serializer,
make_custom_error(format_args!(
"type `{}` does not implement `Reflect`",
value.reflect_type_path()
)),
));
};
let info = value.reflect_type_info();
let Some(registration) = type_registry.get(info.type_id()) else {
return Err((
serializer,
make_custom_error(format_args!(
"type `{}` is not registered in the type registry",
info.type_path(),
)),
));
};
if let Some(reflect_serialize) = registration.data::<ReflectSerialize>() {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
Ok(reflect_serialize
.get_serializable(value)
.borrow()
.serialize(serializer))
} else if let Some(reflect_serialize_with_registry) =
registration.data::<ReflectSerializeWithRegistry>()
{
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
Ok(reflect_serialize_with_registry.serialize(value, serializer, type_registry))
} else {
Err((serializer, make_custom_error(format_args!(
"type `{}` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data`",
info.type_path(),
))))
}
}

View File

@@ -0,0 +1,130 @@
use crate::{
serde::{ser::error_utils::make_custom_error, TypedReflectSerializer},
Enum, TypeInfo, TypeRegistry, VariantInfo, VariantType,
};
use serde::{
ser::{SerializeStructVariant, SerializeTupleVariant},
Serialize,
};
use super::ReflectSerializerProcessor;
/// A serializer for [`Enum`] values.
pub(super) struct EnumSerializer<'a, P> {
pub enum_value: &'a dyn Enum,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for EnumSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let type_info = self.enum_value.get_represented_type_info().ok_or_else(|| {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.enum_value.reflect_type_path()
))
})?;
let enum_info = match type_info {
TypeInfo::Enum(enum_info) => enum_info,
info => {
return Err(make_custom_error(format_args!(
"expected enum type but received {info:?}"
)));
}
};
let enum_name = enum_info.type_path_table().ident().unwrap();
let variant_index = self.enum_value.variant_index() as u32;
let variant_info = enum_info
.variant_at(variant_index as usize)
.ok_or_else(|| {
make_custom_error(format_args!(
"variant at index `{variant_index}` does not exist",
))
})?;
let variant_name = variant_info.name();
let variant_type = self.enum_value.variant_type();
let field_len = self.enum_value.field_len();
match variant_type {
VariantType::Unit => {
if type_info.type_path_table().module_path() == Some("core::option")
&& type_info.type_path_table().ident() == Some("Option")
{
serializer.serialize_none()
} else {
serializer.serialize_unit_variant(enum_name, variant_index, variant_name)
}
}
VariantType::Struct => {
let struct_info = match variant_info {
VariantInfo::Struct(struct_info) => struct_info,
info => {
return Err(make_custom_error(format_args!(
"expected struct variant type but received {info:?}",
)));
}
};
let mut state = serializer.serialize_struct_variant(
enum_name,
variant_index,
variant_name,
field_len,
)?;
for (index, field) in self.enum_value.iter_fields().enumerate() {
let field_info = struct_info.field_at(index).unwrap();
state.serialize_field(
field_info.name(),
&TypedReflectSerializer::new_internal(
field.value(),
self.registry,
self.processor,
),
)?;
}
state.end()
}
VariantType::Tuple if field_len == 1 => {
let field = self.enum_value.field_at(0).unwrap();
if type_info.type_path_table().module_path() == Some("core::option")
&& type_info.type_path_table().ident() == Some("Option")
{
serializer.serialize_some(&TypedReflectSerializer::new_internal(
field,
self.registry,
self.processor,
))
} else {
serializer.serialize_newtype_variant(
enum_name,
variant_index,
variant_name,
&TypedReflectSerializer::new_internal(field, self.registry, self.processor),
)
}
}
VariantType::Tuple => {
let mut state = serializer.serialize_tuple_variant(
enum_name,
variant_index,
variant_name,
field_len,
)?;
for field in self.enum_value.iter_fields() {
state.serialize_field(&TypedReflectSerializer::new_internal(
field.value(),
self.registry,
self.processor,
))?;
}
state.end()
}
}
}
}

View File

@@ -0,0 +1,29 @@
use core::fmt::Display;
use serde::ser::Error;
#[cfg(feature = "debug_stack")]
use std::thread_local;
#[cfg(feature = "debug_stack")]
thread_local! {
/// The thread-local [`TypeInfoStack`] used for debugging.
///
/// [`TypeInfoStack`]: crate::type_info_stack::TypeInfoStack
pub(super) static TYPE_INFO_STACK: core::cell::RefCell<crate::type_info_stack::TypeInfoStack> = const { core::cell::RefCell::new(
crate::type_info_stack::TypeInfoStack::new()
) };
}
/// A helper function for generating a custom serialization error message.
///
/// This function should be preferred over [`Error::custom`] as it will include
/// other useful information, such as the [type info stack].
///
/// [type info stack]: crate::type_info_stack::TypeInfoStack
pub(super) fn make_custom_error<E: Error>(msg: impl Display) -> E {
#[cfg(feature = "debug_stack")]
return TYPE_INFO_STACK
.with_borrow(|stack| E::custom(format_args!("{} (stack: {:?})", msg, stack)));
#[cfg(not(feature = "debug_stack"))]
return E::custom(msg);
}

View File

@@ -0,0 +1,28 @@
use crate::{serde::TypedReflectSerializer, List, TypeRegistry};
use serde::{ser::SerializeSeq, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`List`] values.
pub(super) struct ListSerializer<'a, P> {
pub list: &'a dyn List,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for ListSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.list.len()))?;
for value in self.list.iter() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,27 @@
use crate::{serde::TypedReflectSerializer, Map, TypeRegistry};
use serde::{ser::SerializeMap, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Map`] values.
pub(super) struct MapSerializer<'a, P> {
pub map: &'a dyn Map,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for MapSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(self.map.len()))?;
for (key, value) in self.map.iter() {
state.serialize_entry(
&TypedReflectSerializer::new_internal(key, self.registry, self.processor),
&TypedReflectSerializer::new_internal(value, self.registry, self.processor),
)?;
}
state.end()
}
}

733
vendor/bevy_reflect/src/serde/ser/mod.rs vendored Normal file
View File

@@ -0,0 +1,733 @@
pub use processor::*;
pub use serializable::*;
pub use serialize_with_registry::*;
pub use serializer::*;
mod arrays;
mod custom_serialization;
mod enums;
mod error_utils;
mod lists;
mod maps;
mod processor;
mod serializable;
mod serialize_with_registry;
mod serializer;
mod sets;
mod structs;
mod tuple_structs;
mod tuples;
#[cfg(test)]
mod tests {
use crate::{
serde::{ReflectSerializer, ReflectSerializerProcessor},
PartialReflect, Reflect, ReflectSerialize, Struct, TypeRegistry,
};
#[cfg(feature = "functions")]
use alloc::boxed::Box;
use alloc::{
string::{String, ToString},
vec,
vec::Vec,
};
use bevy_platform::collections::{HashMap, HashSet};
use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive};
use ron::{extensions::Extensions, ser::PrettyConfig};
use serde::{Serialize, Serializer};
#[derive(Reflect, Debug, PartialEq)]
struct MyStruct {
primitive_value: i8,
option_value: Option<String>,
option_value_complex: Option<SomeStruct>,
tuple_value: (f32, usize),
list_value: Vec<i32>,
array_value: [i32; 5],
map_value: HashMap<u8, usize>,
set_value: HashSet<u8>,
struct_value: SomeStruct,
tuple_struct_value: SomeTupleStruct,
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum,
newtype_enum: SomeEnum,
tuple_enum: SomeEnum,
struct_enum: SomeEnum,
ignored_struct: SomeIgnoredStruct,
ignored_tuple_struct: SomeIgnoredTupleStruct,
ignored_struct_variant: SomeIgnoredEnum,
ignored_tuple_variant: SomeIgnoredEnum,
custom_serialize: CustomSerialize,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeStruct {
foo: i64,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeTupleStruct(String);
#[derive(Reflect, Debug, PartialEq)]
struct SomeUnitStruct;
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredStruct {
#[reflect(ignore)]
ignored: i32,
}
#[derive(Reflect, Debug, PartialEq)]
struct SomeIgnoredTupleStruct(#[reflect(ignore)] i32);
#[derive(Reflect, Debug, PartialEq)]
enum SomeEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { foo: String },
}
#[derive(Reflect, Debug, PartialEq)]
enum SomeIgnoredEnum {
Tuple(#[reflect(ignore)] f32, #[reflect(ignore)] f32),
Struct {
#[reflect(ignore)]
foo: String,
},
}
#[derive(Reflect, Debug, PartialEq, Serialize)]
struct SomeSerializableStruct {
foo: i64,
}
/// Implements a custom serialize using `#[reflect(Serialize)]`.
///
/// For testing purposes, this just uses the generated one from deriving Serialize.
#[derive(Reflect, Debug, PartialEq, Serialize)]
#[reflect(Serialize)]
struct CustomSerialize {
value: usize,
#[serde(rename = "renamed")]
inner_struct: SomeSerializableStruct,
}
fn get_registry() -> TypeRegistry {
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
registry.register::<SomeStruct>();
registry.register::<SomeTupleStruct>();
registry.register::<SomeUnitStruct>();
registry.register::<SomeIgnoredStruct>();
registry.register::<SomeIgnoredTupleStruct>();
registry.register::<SomeIgnoredEnum>();
registry.register::<CustomSerialize>();
registry.register::<SomeEnum>();
registry.register::<SomeSerializableStruct>();
registry.register_type_data::<SomeSerializableStruct, ReflectSerialize>();
registry.register::<String>();
registry.register::<Option<String>>();
registry.register_type_data::<Option<String>, ReflectSerialize>();
registry
}
fn get_my_struct() -> MyStruct {
let mut map = <HashMap<_, _>>::default();
map.insert(64, 32);
let mut set = <HashSet<_>>::default();
set.insert(64);
MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
set_value: set,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 123 },
ignored_tuple_struct: SomeIgnoredTupleStruct(123),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::from("Struct Variant"),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(1.23, 3.45),
custom_serialize: CustomSerialize {
value: 100,
inner_struct: SomeSerializableStruct { foo: 101 },
},
}
}
#[test]
fn should_serialize() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyStruct": (
primitive_value: 123,
option_value: Some("Hello world!"),
option_value_complex: Some((
foo: 123,
)),
tuple_value: (3.1415927, 1337),
list_value: [
-2,
-1,
0,
1,
2,
],
array_value: (-2, -1, 0, 1, 2),
map_value: {
64: 32,
},
set_value: [
64,
],
struct_value: (
foo: 999999999,
),
tuple_struct_value: ("Tuple Struct"),
unit_struct: (),
unit_enum: Unit,
newtype_enum: NewType(123),
tuple_enum: Tuple(1.23, 3.21),
struct_enum: Struct(
foo: "Struct variant value",
),
ignored_struct: (),
ignored_tuple_struct: (),
ignored_struct_variant: Struct(),
ignored_tuple_variant: Tuple(),
custom_serialize: (
value: 100,
renamed: (
foo: 101,
),
),
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_serialize_option() {
#[derive(Reflect, Debug, PartialEq)]
struct OptionTest {
none: Option<()>,
simple: Option<String>,
complex: Option<SomeStruct>,
}
let value = OptionTest {
none: None,
simple: Some(String::from("Hello world!")),
complex: Some(SomeStruct { foo: 123 }),
};
let registry = get_registry();
let serializer = ReflectSerializer::new(&value, &registry);
// === Normal === //
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::OptionTest": (
none: None,
simple: Some("Hello world!"),
complex: Some((
foo: 123,
)),
),
}"#;
assert_eq!(expected, output);
// === Implicit Some === //
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.extensions(Extensions::IMPLICIT_SOME)
.indentor(String::from(" "));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"#![enable(implicit_some)]
{
"bevy_reflect::serde::ser::tests::OptionTest": (
none: None,
simple: "Hello world!",
complex: (
foo: 123,
),
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn enum_should_serialize() {
#[derive(Reflect)]
enum MyEnum {
Unit,
NewType(usize),
Tuple(f32, f32),
Struct { value: String },
}
let mut registry = get_registry();
registry.register::<MyEnum>();
let config = PrettyConfig::default().new_line(String::from("\n"));
// === Unit Variant === //
let value = MyEnum::Unit;
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": Unit,
}"#;
assert_eq!(expected, output);
// === NewType Variant === //
let value = MyEnum::NewType(123);
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": NewType(123),
}"#;
assert_eq!(expected, output);
// === Tuple Variant === //
let value = MyEnum::Tuple(1.23, 3.21);
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": Tuple(1.23, 3.21),
}"#;
assert_eq!(expected, output);
// === Struct Variant === //
let value = MyEnum::Struct {
value: String::from("I <3 Enums"),
};
let serializer = ReflectSerializer::new(&value, &registry);
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::MyEnum": Struct(
value: "I <3 Enums",
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_serialize_non_self_describing_binary() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let config = bincode::config::standard().with_fixed_int_encoding();
let bytes = bincode::serde::encode_to_vec(&serializer, config).unwrap();
let expected: Vec<u8> = vec![
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 114, 101, 102,
108, 101, 99, 116, 58, 58, 115, 101, 114, 100, 101, 58, 58, 115, 101, 114, 58, 58, 116,
101, 115, 116, 115, 58, 58, 77, 121, 83, 116, 114, 117, 99, 116, 123, 1, 12, 0, 0, 0,
0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 1, 123, 0, 0, 0,
0, 0, 0, 0, 219, 15, 73, 64, 57, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 254, 255,
255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 254, 255, 255, 255,
255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 32,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 255, 201, 154, 59, 0, 0, 0, 0, 12, 0,
0, 0, 0, 0, 0, 0, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 0, 0, 0, 0,
1, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 164, 112, 157, 63, 164, 112, 77, 64,
3, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105,
97, 110, 116, 32, 118, 97, 108, 117, 101, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0,
0, 0, 101, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(expected, bytes);
}
#[test]
fn should_serialize_self_describing_binary() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let bytes: Vec<u8> = rmp_serde::to_vec(&serializer).unwrap();
let expected: Vec<u8> = vec![
129, 217, 41, 98, 101, 118, 121, 95, 114, 101, 102, 108, 101, 99, 116, 58, 58, 115,
101, 114, 100, 101, 58, 58, 115, 101, 114, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77,
121, 83, 116, 114, 117, 99, 116, 220, 0, 20, 123, 172, 72, 101, 108, 108, 111, 32, 119,
111, 114, 108, 100, 33, 145, 123, 146, 202, 64, 73, 15, 219, 205, 5, 57, 149, 254, 255,
0, 1, 2, 149, 254, 255, 0, 1, 2, 129, 64, 32, 145, 64, 145, 206, 59, 154, 201, 255,
172, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 144, 164, 85, 110, 105,
116, 129, 167, 78, 101, 119, 84, 121, 112, 101, 123, 129, 165, 84, 117, 112, 108, 101,
146, 202, 63, 157, 112, 164, 202, 64, 77, 112, 164, 129, 166, 83, 116, 114, 117, 99,
116, 145, 180, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105, 97, 110, 116, 32,
118, 97, 108, 117, 101, 144, 144, 129, 166, 83, 116, 114, 117, 99, 116, 144, 129, 165,
84, 117, 112, 108, 101, 144, 146, 100, 145, 101,
];
assert_eq!(expected, bytes);
}
#[test]
fn should_serialize_dynamic_option() {
#[derive(Default, Reflect)]
struct OtherStruct {
some: Option<SomeStruct>,
none: Option<SomeStruct>,
}
let value = OtherStruct {
some: Some(SomeStruct { foo: 999999999 }),
none: None,
};
let dynamic = value.to_dynamic_struct();
let reflect = dynamic.as_partial_reflect();
let registry = get_registry();
let serializer = ReflectSerializer::new(reflect, &registry);
let mut buf = Vec::new();
let format = serde_json::ser::PrettyFormatter::with_indent(b" ");
let mut ser = serde_json::Serializer::with_formatter(&mut buf, format);
serializer.serialize(&mut ser).unwrap();
let output = core::str::from_utf8(&buf).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::OtherStruct": {
"some": {
"foo": 999999999
},
"none": null
}
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_return_error_if_missing_registration() {
let value = RangeInclusive::<f32>::new(0.0, 1.0);
let registry = TypeRegistry::new();
let serializer = ReflectSerializer::new(&value, &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` is not registered in the type registry (stack: `core::ops::RangeInclusive<f32>`)"
.to_string(),
)
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` is not registered in the type registry"
.to_string(),
)
);
}
#[test]
fn should_return_error_if_missing_type_data() {
let value = RangeInclusive::<f32>::new(0.0, 1.0);
let mut registry = TypeRegistry::new();
registry.register::<RangeInclusive<f32>>();
let serializer = ReflectSerializer::new(&value, &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive<f32>`)".to_string()
)
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()
)
);
}
#[test]
fn should_use_processor_for_custom_serialization() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
qux: i64,
}
struct FooProcessor;
impl ReflectSerializerProcessor for FooProcessor {
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
_: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
let Some(value) = value.try_as_reflect() else {
return Ok(Err(serializer));
};
let type_id = value.reflect_type_info().type_id();
if type_id == TypeId::of::<i64>() {
Ok(Ok(serializer.serialize_str("custom!")?))
} else {
Ok(Err(serializer))
}
}
}
let value = Foo { bar: 123, qux: 456 };
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
let processor = FooProcessor;
let serializer = ReflectSerializer::with_processor(&value, &registry, &processor);
let config = PrettyConfig::default().new_line(String::from("\n"));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::Foo": (
bar: 123,
qux: "custom!",
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_use_processor_for_multiple_registrations() {
#[derive(Reflect, Debug, PartialEq)]
struct Foo {
bar: i32,
sub: SubFoo,
}
#[derive(Reflect, Debug, PartialEq)]
struct SubFoo {
val: i32,
}
struct FooProcessor;
impl ReflectSerializerProcessor for FooProcessor {
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
_: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
let Some(value) = value.try_as_reflect() else {
return Ok(Err(serializer));
};
let type_id = value.reflect_type_info().type_id();
if type_id == TypeId::of::<i32>() {
Ok(Ok(serializer.serialize_str("an i32")?))
} else if type_id == TypeId::of::<SubFoo>() {
Ok(Ok(serializer.serialize_str("a SubFoo")?))
} else {
Ok(Err(serializer))
}
}
}
let value = Foo {
bar: 123,
sub: SubFoo { val: 456 },
};
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
registry.register::<SubFoo>();
let processor = FooProcessor;
let serializer = ReflectSerializer::with_processor(&value, &registry, &processor);
let config = PrettyConfig::default().new_line(String::from("\n"));
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
let expected = r#"{
"bevy_reflect::serde::ser::tests::Foo": (
bar: "an i32",
sub: "a SubFoo",
),
}"#;
assert_eq!(expected, output);
}
#[test]
fn should_propagate_processor_serialize_error() {
struct ErroringProcessor;
impl ReflectSerializerProcessor for ErroringProcessor {
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
_: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
let Some(value) = value.try_as_reflect() else {
return Ok(Err(serializer));
};
let type_id = value.reflect_type_info().type_id();
if type_id == TypeId::of::<i32>() {
Err(serde::ser::Error::custom("my custom serialize error"))
} else {
Ok(Err(serializer))
}
}
}
let value = 123_i32;
let registry = TypeRegistry::new();
let processor = ErroringProcessor;
let serializer = ReflectSerializer::with_processor(&value, &registry, &processor);
let error = ron::ser::to_string_pretty(&serializer, PrettyConfig::default()).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message("my custom serialize error (stack: `i32`)".to_string())
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message("my custom serialize error".to_string())
);
}
#[cfg(feature = "functions")]
mod functions {
use super::*;
use crate::func::{DynamicFunction, IntoFunction};
use alloc::string::ToString;
#[test]
fn should_not_serialize_function() {
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct MyStruct {
func: DynamicFunction<'static>,
}
let value: Box<dyn Reflect> = Box::new(MyStruct {
func: String::new.into_function(),
});
let registry = TypeRegistry::new();
let serializer = ReflectSerializer::new(value.as_partial_reflect(), &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
#[cfg(feature = "debug_stack")]
assert_eq!(
error,
ron::Error::Message("functions cannot be serialized (stack: `bevy_reflect::serde::ser::tests::functions::MyStruct`)".to_string())
);
#[cfg(not(feature = "debug_stack"))]
assert_eq!(
error,
ron::Error::Message("functions cannot be serialized".to_string())
);
}
}
#[cfg(feature = "debug_stack")]
mod debug_stack {
use super::*;
#[test]
fn should_report_context_in_errors() {
#[derive(Reflect)]
struct Foo {
bar: Bar,
}
#[derive(Reflect)]
struct Bar {
some_other_field: Option<u32>,
baz: Baz,
}
#[derive(Reflect)]
struct Baz {
value: Vec<RangeInclusive<f32>>,
}
let value = Foo {
bar: Bar {
some_other_field: Some(123),
baz: Baz {
value: vec![0.0..=1.0],
},
},
};
let registry = TypeRegistry::new();
let serializer = ReflectSerializer::new(&value, &registry);
let error = ron::ser::to_string(&serializer).unwrap_err();
assert_eq!(
error,
ron::Error::Message(
"type `core::ops::RangeInclusive<f32>` is not registered in the type registry (stack: `bevy_reflect::serde::ser::tests::debug_stack::Foo` -> `bevy_reflect::serde::ser::tests::debug_stack::Bar` -> `bevy_reflect::serde::ser::tests::debug_stack::Baz` -> `alloc::vec::Vec<core::ops::RangeInclusive<f32>>` -> `core::ops::RangeInclusive<f32>`)".to_string()
)
);
}
}
}

View File

@@ -0,0 +1,196 @@
use serde::Serializer;
use crate::{PartialReflect, TypeRegistry};
/// Allows overriding the default serialization behavior of
/// [`ReflectSerializer`] and [`TypedReflectSerializer`] for specific values.
///
/// When serializing a reflected value, you may want to override the default
/// behavior and use your own logic for serialization. This logic may also be
/// context-dependent, and only apply for a single use of your
/// [`ReflectSerializer`]. To achieve this, you can create a processor and pass
/// it into your serializer.
///
/// Whenever the serializer attempts to serialize a value, it will first call
/// [`try_serialize`] on your processor, which may take ownership of the
/// serializer and write into the serializer (successfully or not), or return
/// ownership of the serializer back, and continue with the default logic.
///
/// The deserialization equivalent of this is [`ReflectDeserializerProcessor`].
///
/// # Compared to [`SerializeWithRegistry`]
///
/// [`SerializeWithRegistry`] allows you to define how your type will be
/// serialized by a [`TypedReflectSerializer`], given the extra context of the
/// [`TypeRegistry`]. If your type can be serialized entirely using that, then
/// you should prefer implementing that trait instead of using a processor.
///
/// However, you may need more context-dependent data which is only present in
/// the scope where you create the [`TypedReflectSerializer`]. For example, if
/// you need to use a reference to a value while serializing, then there is no
/// way to do this with [`SerializeWithRegistry`] as you can't pass that
/// reference into anywhere. This is where a processor is useful, as the
/// processor can capture local variables.
///
/// A [`ReflectSerializerProcessor`] always takes priority over a
/// [`SerializeWithRegistry`] implementation, so this is also useful for
/// overriding serialization behavior if you need to do something custom.
///
/// # Examples
///
/// Serializing a reflected value when saving an asset to disk, and replacing
/// asset handles with the handle path (if it has one):
///
/// ```
/// # use core::any::Any;
/// # use serde::Serialize;
/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistry};
/// # use bevy_reflect::serde::{ReflectSerializer, ReflectSerializerProcessor};
/// #
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Handle<T>(T);
/// # #[derive(Debug, Clone, Reflect)]
/// # struct Mesh;
/// #
/// # struct ReflectHandle;
/// # impl TypeData for ReflectHandle {
/// # fn clone_type_data(&self) -> Box<dyn TypeData> {
/// # unimplemented!()
/// # }
/// # }
/// # impl ReflectHandle {
/// # fn downcast_handle_untyped(&self, handle: &(dyn Any + 'static)) -> Option<UntypedHandle> {
/// # unimplemented!()
/// # }
/// # }
/// #
/// # #[derive(Debug, Clone)]
/// # struct UntypedHandle;
/// # impl UntypedHandle {
/// # fn path(&self) -> Option<&str> {
/// # unimplemented!()
/// # }
/// # }
/// # type AssetError = Box<dyn core::error::Error>;
/// #
/// #[derive(Debug, Clone, Reflect)]
/// struct MyAsset {
/// name: String,
/// mesh: Handle<Mesh>,
/// }
///
/// struct HandleProcessor;
///
/// impl ReflectSerializerProcessor for HandleProcessor {
/// fn try_serialize<S>(
/// &self,
/// value: &dyn PartialReflect,
/// registry: &TypeRegistry,
/// serializer: S,
/// ) -> Result<Result<S::Ok, S>, S::Error>
/// where
/// S: serde::Serializer,
/// {
/// let Some(value) = value.try_as_reflect() else {
/// // we don't have any info on this type; do the default serialization logic
/// return Ok(Err(serializer));
/// };
/// let type_id = value.reflect_type_info().type_id();
/// let Some(reflect_handle) = registry.get_type_data::<ReflectHandle>(type_id) else {
/// // this isn't a `Handle<T>`
/// return Ok(Err(serializer));
/// };
///
/// let untyped_handle = reflect_handle
/// .downcast_handle_untyped(value.as_any())
/// .unwrap();
/// if let Some(path) = untyped_handle.path() {
/// Ok(Ok(serializer.serialize_str(path)?))
/// } else {
/// Ok(Ok(serializer.serialize_unit()?))
/// }
/// }
/// }
///
/// fn save(type_registry: &TypeRegistry, asset: &MyAsset) -> Result<Vec<u8>, AssetError> {
/// let mut asset_bytes = Vec::new();
///
/// let processor = HandleProcessor;
/// let serializer = ReflectSerializer::with_processor(asset, type_registry, &processor);
/// let mut ron_serializer = ron::Serializer::new(&mut asset_bytes, None)?;
///
/// serializer.serialize(&mut ron_serializer)?;
/// Ok(asset_bytes)
/// }
/// ```
///
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`try_serialize`]: Self::try_serialize
/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry
/// [`ReflectDeserializerProcessor`]: crate::serde::ReflectDeserializerProcessor
pub trait ReflectSerializerProcessor {
/// Attempts to serialize the value which a [`TypedReflectSerializer`] is
/// currently looking at.
///
/// If you want to override the default serialization, return
/// `Ok(Ok(value))` with an `Ok` output from the serializer.
///
/// If you don't want to override the serialization, return ownership of
/// the serializer back via `Ok(Err(serializer))`.
///
/// You can use the type registry to read info about the type you're
/// serializing, or just try to downcast the value directly:
///
/// ```
/// # use bevy_reflect::{TypeRegistration, TypeRegistry, PartialReflect};
/// # use bevy_reflect::serde::ReflectSerializerProcessor;
/// # use core::any::TypeId;
/// struct I32AsStringProcessor;
///
/// impl ReflectSerializerProcessor for I32AsStringProcessor {
/// fn try_serialize<S>(
/// &self,
/// value: &dyn PartialReflect,
/// registry: &TypeRegistry,
/// serializer: S,
/// ) -> Result<Result<S::Ok, S>, S::Error>
/// where
/// S: serde::Serializer
/// {
/// if let Some(value) = value.try_downcast_ref::<i32>() {
/// let value_as_string = format!("{value:?}");
/// Ok(Ok(serializer.serialize_str(&value_as_string)?))
/// } else {
/// // Not an `i32`, just do the default serialization
/// Ok(Err(serializer))
/// }
/// }
/// }
/// ```
///
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`Reflect`]: crate::Reflect
fn try_serialize<S>(
&self,
value: &dyn PartialReflect,
registry: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer;
}
impl ReflectSerializerProcessor for () {
fn try_serialize<S>(
&self,
_value: &dyn PartialReflect,
_registry: &TypeRegistry,
serializer: S,
) -> Result<Result<S::Ok, S>, S::Error>
where
S: Serializer,
{
Ok(Err(serializer))
}
}

View File

@@ -0,0 +1,19 @@
use alloc::boxed::Box;
use core::ops::Deref;
/// A type-erased serializable value.
pub enum Serializable<'a> {
Owned(Box<dyn erased_serde::Serialize + 'a>),
Borrowed(&'a dyn erased_serde::Serialize),
}
impl<'a> Deref for Serializable<'a> {
type Target = dyn erased_serde::Serialize + 'a;
fn deref(&self) -> &Self::Target {
match self {
Serializable::Borrowed(serialize) => serialize,
Serializable::Owned(serialize) => serialize,
}
}
}

View File

@@ -0,0 +1,101 @@
use crate::{FromType, Reflect, TypeRegistry};
use alloc::boxed::Box;
use serde::{Serialize, Serializer};
/// Trait used to provide finer control when serializing a reflected type with one of
/// the reflection serializers.
///
/// This trait is the reflection equivalent of `serde`'s [`Serialize`] trait.
/// The main difference is that this trait provides access to the [`TypeRegistry`],
/// which means that we can use the registry and all its stored type information
/// to serialize our type.
///
/// This can be useful when writing a custom reflection serializer where we may
/// want to handle parts of the serialization process, but temporarily pass control
/// to the standard reflection serializer for other parts.
///
/// For the deserialization equivalent of this trait, see [`DeserializeWithRegistry`].
///
/// # Rationale
///
/// Without this trait and its associated [type data], such a serializer would have to
/// write out all of the serialization logic itself, possibly including
/// unnecessary code duplication and trivial implementations.
///
/// This is because a normal [`Serialize`] implementation has no knowledge of the
/// [`TypeRegistry`] and therefore cannot create a reflection-based serializer for
/// nested items.
///
/// # Implementors
///
/// In order for this to work with the reflection serializers like [`TypedReflectSerializer`]
/// and [`ReflectSerializer`], implementors should be sure to register the
/// [`ReflectSerializeWithRegistry`] type data.
/// This can be done [via the registry] or by adding `#[reflect(SerializeWithRegistry)]` to
/// the type definition.
///
/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry
/// [type data]: ReflectSerializeWithRegistry
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [via the registry]: TypeRegistry::register_type_data
pub trait SerializeWithRegistry {
fn serialize<S>(&self, serializer: S, registry: &TypeRegistry) -> Result<S::Ok, S::Error>
where
S: Serializer;
}
/// Type data used to serialize a [`Reflect`] type with a custom [`SerializeWithRegistry`] implementation.
#[derive(Clone)]
pub struct ReflectSerializeWithRegistry {
serialize: for<'a> fn(
value: &'a dyn Reflect,
registry: &'a TypeRegistry,
) -> Box<dyn erased_serde::Serialize + 'a>,
}
impl ReflectSerializeWithRegistry {
/// Serialize a [`Reflect`] type with this type data's custom [`SerializeWithRegistry`] implementation.
pub fn serialize<S>(
&self,
value: &dyn Reflect,
serializer: S,
registry: &TypeRegistry,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
((self.serialize)(value, registry)).serialize(serializer)
}
}
impl<T: Reflect + SerializeWithRegistry> FromType<T> for ReflectSerializeWithRegistry {
fn from_type() -> Self {
Self {
serialize: |value: &dyn Reflect, registry| {
let value = value.downcast_ref::<T>().unwrap_or_else(|| {
panic!(
"Expected value to be of type {} but received {}",
core::any::type_name::<T>(),
value.reflect_type_path()
)
});
Box::new(SerializableWithRegistry { value, registry })
},
}
}
}
struct SerializableWithRegistry<'a, T: SerializeWithRegistry> {
value: &'a T,
registry: &'a TypeRegistry,
}
impl<'a, T: SerializeWithRegistry> Serialize for SerializableWithRegistry<'a, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.value.serialize(serializer, self.registry)
}
}

View File

@@ -0,0 +1,326 @@
#[cfg(feature = "debug_stack")]
use crate::serde::ser::error_utils::TYPE_INFO_STACK;
use crate::{
serde::ser::{
arrays::ArraySerializer, custom_serialization::try_custom_serialize, enums::EnumSerializer,
error_utils::make_custom_error, lists::ListSerializer, maps::MapSerializer,
sets::SetSerializer, structs::StructSerializer, tuple_structs::TupleStructSerializer,
tuples::TupleSerializer,
},
PartialReflect, ReflectRef, TypeRegistry,
};
use serde::{ser::SerializeMap, Serialize, Serializer};
use super::ReflectSerializerProcessor;
/// A general purpose serializer for reflected types.
///
/// This is the serializer counterpart to [`ReflectDeserializer`].
///
/// See [`TypedReflectSerializer`] for a serializer that serializes a known type.
///
/// # Output
///
/// This serializer will output a map with a single entry,
/// where the key is the _full_ [type path] of the reflected type
/// and the value is the serialized data.
///
/// If you want to override serialization for specific values, you can pass in
/// a reference to a [`ReflectSerializerProcessor`] which will take priority
/// over all other serialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{TypeRegistry, serde::ReflectSerializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// #[type_path = "my_crate"]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = MyStruct { value: 123 };
///
/// let reflect_serializer = ReflectSerializer::new(&input, &registry);
/// let output = ron::to_string(&reflect_serializer).unwrap();
///
/// assert_eq!(output, r#"{"my_crate::MyStruct":(value:123)}"#);
/// ```
///
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [type path]: crate::TypePath::type_path
/// [`with_processor`]: Self::with_processor
pub struct ReflectSerializer<'a, P = ()> {
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: Option<&'a P>,
}
impl<'a> ReflectSerializer<'a, ()> {
/// Creates a serializer with no processor.
///
/// If you want to add custom logic for serializing certain values, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(value: &'a dyn PartialReflect, registry: &'a TypeRegistry) -> Self {
Self {
value,
registry,
processor: None,
}
}
}
impl<'a, P: ReflectSerializerProcessor> ReflectSerializer<'a, P> {
/// Creates a serializer with a processor.
///
/// If you do not need any custom logic for handling certain values, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: &'a P,
) -> Self {
Self {
value,
registry,
processor: Some(processor),
}
}
}
impl<P: ReflectSerializerProcessor> Serialize for ReflectSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_map(Some(1))?;
state.serialize_entry(
self.value
.get_represented_type_info()
.ok_or_else(|| {
if self.value.is_dynamic() {
make_custom_error(format_args!(
"cannot serialize dynamic value without represented type: `{}`",
self.value.reflect_type_path()
))
} else {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.value.reflect_type_path()
))
}
})?
.type_path(),
&TypedReflectSerializer::new_internal(self.value, self.registry, self.processor),
)?;
state.end()
}
}
/// A serializer for reflected types whose type will be known during deserialization.
///
/// This is the serializer counterpart to [`TypedReflectDeserializer`].
///
/// See [`ReflectSerializer`] for a serializer that serializes an unknown type.
///
/// # Output
///
/// Since the type is expected to be known during deserialization,
/// this serializer will not output any additional type information,
/// such as the [type path].
///
/// Instead, it will output just the serialized data.
///
/// If you want to override serialization for specific values, you can pass in
/// a reference to a [`ReflectSerializerProcessor`] which will take priority
/// over all other serialization methods - see [`with_processor`].
///
/// # Example
///
/// ```
/// # use bevy_reflect::prelude::*;
/// # use bevy_reflect::{TypeRegistry, serde::TypedReflectSerializer};
/// #[derive(Reflect, PartialEq, Debug)]
/// #[type_path = "my_crate"]
/// struct MyStruct {
/// value: i32
/// }
///
/// let mut registry = TypeRegistry::default();
/// registry.register::<MyStruct>();
///
/// let input = MyStruct { value: 123 };
///
/// let reflect_serializer = TypedReflectSerializer::new(&input, &registry);
/// let output = ron::to_string(&reflect_serializer).unwrap();
///
/// assert_eq!(output, r#"(value:123)"#);
/// ```
///
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [type path]: crate::TypePath::type_path
/// [`with_processor`]: Self::with_processor
pub struct TypedReflectSerializer<'a, P = ()> {
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: Option<&'a P>,
}
impl<'a> TypedReflectSerializer<'a, ()> {
/// Creates a serializer with no processor.
///
/// If you want to add custom logic for serializing certain values, use
/// [`with_processor`].
///
/// [`with_processor`]: Self::with_processor
pub fn new(value: &'a dyn PartialReflect, registry: &'a TypeRegistry) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
value,
registry,
processor: None,
}
}
}
impl<'a, P> TypedReflectSerializer<'a, P> {
/// Creates a serializer with a processor.
///
/// If you do not need any custom logic for handling certain values, use
/// [`new`].
///
/// [`new`]: Self::new
pub fn with_processor(
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: &'a P,
) -> Self {
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new());
Self {
value,
registry,
processor: Some(processor),
}
}
/// An internal constructor for creating a serializer without resetting the type info stack.
pub(super) fn new_internal(
value: &'a dyn PartialReflect,
registry: &'a TypeRegistry,
processor: Option<&'a P>,
) -> Self {
Self {
value,
registry,
processor,
}
}
}
impl<P: ReflectSerializerProcessor> Serialize for TypedReflectSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[cfg(feature = "debug_stack")]
{
if let Some(info) = self.value.get_represented_type_info() {
TYPE_INFO_STACK.with_borrow_mut(|stack| stack.push(info));
}
}
// First, check if our processor wants to serialize this type
// This takes priority over any other serialization operations
let serializer = if let Some(processor) = self.processor {
match processor.try_serialize(self.value, self.registry, serializer) {
Ok(Ok(value)) => {
return Ok(value);
}
Err(err) => {
return Err(make_custom_error(err));
}
Ok(Err(serializer)) => serializer,
}
} else {
serializer
};
// Handle both Value case and types that have a custom `Serialize`
let (serializer, error) = match try_custom_serialize(self.value, self.registry, serializer)
{
Ok(result) => return result,
Err(value) => value,
};
let output = match self.value.reflect_ref() {
ReflectRef::Struct(struct_value) => StructSerializer {
struct_value,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::TupleStruct(tuple_struct) => TupleStructSerializer {
tuple_struct,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Tuple(tuple) => TupleSerializer {
tuple,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::List(list) => ListSerializer {
list,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Array(array) => ArraySerializer {
array,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Map(map) => MapSerializer {
map,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Set(set) => SetSerializer {
set,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
ReflectRef::Enum(enum_value) => EnumSerializer {
enum_value,
registry: self.registry,
processor: self.processor,
}
.serialize(serializer),
#[cfg(feature = "functions")]
ReflectRef::Function(_) => Err(make_custom_error("functions cannot be serialized")),
ReflectRef::Opaque(_) => Err(error),
};
#[cfg(feature = "debug_stack")]
TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop);
output
}
}

View File

@@ -0,0 +1,28 @@
use crate::{serde::TypedReflectSerializer, Set, TypeRegistry};
use serde::{ser::SerializeSeq, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Set`] values.
pub(super) struct SetSerializer<'a, P> {
pub set: &'a dyn Set,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for SetSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.set.len()))?;
for value in self.set.iter() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,62 @@
use crate::{
serde::{ser::error_utils::make_custom_error, SerializationData, TypedReflectSerializer},
Struct, TypeInfo, TypeRegistry,
};
use serde::{ser::SerializeStruct, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Struct`] values.
pub(super) struct StructSerializer<'a, P> {
pub struct_value: &'a dyn Struct,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for StructSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let type_info = self
.struct_value
.get_represented_type_info()
.ok_or_else(|| {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.struct_value.reflect_type_path()
))
})?;
let struct_info = match type_info {
TypeInfo::Struct(struct_info) => struct_info,
info => {
return Err(make_custom_error(format_args!(
"expected struct type but received {info:?}"
)));
}
};
let serialization_data = self
.registry
.get(type_info.type_id())
.and_then(|registration| registration.data::<SerializationData>());
let ignored_len = serialization_data.map(SerializationData::len).unwrap_or(0);
let mut state = serializer.serialize_struct(
struct_info.type_path_table().ident().unwrap(),
self.struct_value.field_len() - ignored_len,
)?;
for (index, value) in self.struct_value.iter_fields().enumerate() {
if serialization_data.is_some_and(|data| data.is_field_skipped(index)) {
continue;
}
let key = struct_info.field_at(index).unwrap().name();
state.serialize_field(
key,
&TypedReflectSerializer::new_internal(value, self.registry, self.processor),
)?;
}
state.end()
}
}

View File

@@ -0,0 +1,71 @@
use crate::{
serde::{ser::error_utils::make_custom_error, SerializationData, TypedReflectSerializer},
TupleStruct, TypeInfo, TypeRegistry,
};
use serde::{ser::SerializeTupleStruct, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`TupleStruct`] values.
pub(super) struct TupleStructSerializer<'a, P> {
pub tuple_struct: &'a dyn TupleStruct,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for TupleStructSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let type_info = self
.tuple_struct
.get_represented_type_info()
.ok_or_else(|| {
make_custom_error(format_args!(
"cannot get type info for `{}`",
self.tuple_struct.reflect_type_path()
))
})?;
let tuple_struct_info = match type_info {
TypeInfo::TupleStruct(tuple_struct_info) => tuple_struct_info,
info => {
return Err(make_custom_error(format_args!(
"expected tuple struct type but received {info:?}"
)));
}
};
let serialization_data = self
.registry
.get(type_info.type_id())
.and_then(|registration| registration.data::<SerializationData>());
let ignored_len = serialization_data.map(SerializationData::len).unwrap_or(0);
if self.tuple_struct.field_len() == 1 && serialization_data.is_none() {
let field = self.tuple_struct.field(0).unwrap();
return serializer.serialize_newtype_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
&TypedReflectSerializer::new_internal(field, self.registry, self.processor),
);
}
let mut state = serializer.serialize_tuple_struct(
tuple_struct_info.type_path_table().ident().unwrap(),
self.tuple_struct.field_len() - ignored_len,
)?;
for (index, value) in self.tuple_struct.iter_fields().enumerate() {
if serialization_data.is_some_and(|data| data.is_field_skipped(index)) {
continue;
}
state.serialize_field(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,29 @@
use crate::{serde::TypedReflectSerializer, Tuple, TypeRegistry};
use serde::{ser::SerializeTuple, Serialize};
use super::ReflectSerializerProcessor;
/// A serializer for [`Tuple`] values.
pub(super) struct TupleSerializer<'a, P> {
pub tuple: &'a dyn Tuple,
pub registry: &'a TypeRegistry,
pub processor: Option<&'a P>,
}
impl<P: ReflectSerializerProcessor> Serialize for TupleSerializer<'_, P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_tuple(self.tuple.field_len())?;
for value in self.tuple.iter_fields() {
state.serialize_element(&TypedReflectSerializer::new_internal(
value,
self.registry,
self.processor,
))?;
}
state.end()
}
}

View File

@@ -0,0 +1,136 @@
use crate::Reflect;
use alloc::boxed::Box;
use bevy_platform::collections::{hash_map::Iter, HashMap};
/// Contains data relevant to the automatic reflect powered (de)serialization of a type.
#[derive(Debug, Clone)]
pub struct SerializationData {
skipped_fields: HashMap<usize, SkippedField>,
}
impl SerializationData {
/// Creates a new `SerializationData` instance with the given skipped fields.
///
/// # Arguments
///
/// * `skipped_iter`: The iterator of field indices to be skipped during (de)serialization.
/// Indices are assigned only to reflected fields.
/// Ignored fields (i.e. those marked `#[reflect(ignore)]`) are implicitly skipped
/// and do not need to be included in this iterator.
pub fn new<I: Iterator<Item = (usize, SkippedField)>>(skipped_iter: I) -> Self {
Self {
skipped_fields: skipped_iter.collect(),
}
}
/// Returns true if the given index corresponds to a field meant to be skipped during (de)serialization.
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use bevy_reflect::{Reflect, Struct, TypeRegistry, serde::SerializationData};
/// #[derive(Reflect)]
/// struct MyStruct {
/// serialize_me: i32,
/// #[reflect(skip_serializing)]
/// skip_me: i32
/// }
///
/// let mut registry = TypeRegistry::new();
/// registry.register::<MyStruct>();
///
/// let my_struct = MyStruct {
/// serialize_me: 123,
/// skip_me: 321,
/// };
///
/// let serialization_data = registry.get_type_data::<SerializationData>(TypeId::of::<MyStruct>()).unwrap();
///
/// for (idx, field) in my_struct.iter_fields().enumerate(){
/// if serialization_data.is_field_skipped(idx) {
/// // Skipped!
/// assert_eq!(1, idx);
/// } else {
/// // Not Skipped!
/// assert_eq!(0, idx);
/// }
/// }
/// ```
pub fn is_field_skipped(&self, index: usize) -> bool {
self.skipped_fields.contains_key(&index)
}
/// Generates a default instance of the skipped field at the given index.
///
/// Returns `None` if the field is not skipped.
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use bevy_reflect::{Reflect, Struct, TypeRegistry, serde::SerializationData};
/// #[derive(Reflect)]
/// struct MyStruct {
/// serialize_me: i32,
/// #[reflect(skip_serializing)]
/// #[reflect(default = "skip_me_default")]
/// skip_me: i32
/// }
///
/// fn skip_me_default() -> i32 {
/// 789
/// }
///
/// let mut registry = TypeRegistry::new();
/// registry.register::<MyStruct>();
///
/// let serialization_data = registry.get_type_data::<SerializationData>(TypeId::of::<MyStruct>()).unwrap();
/// assert_eq!(789, serialization_data.generate_default(1).unwrap().take::<i32>().unwrap());
/// ```
pub fn generate_default(&self, index: usize) -> Option<Box<dyn Reflect>> {
self.skipped_fields
.get(&index)
.map(SkippedField::generate_default)
}
/// Returns the number of skipped fields.
pub fn len(&self) -> usize {
self.skipped_fields.len()
}
/// Returns true if there are no skipped fields.
pub fn is_empty(&self) -> bool {
self.skipped_fields.is_empty()
}
/// Returns an iterator over the skipped fields.
///
/// Each item in the iterator is a tuple containing:
/// 1. The reflected index of the field
/// 2. The (de)serialization metadata of the field
pub fn iter_skipped(&self) -> Iter<'_, usize, SkippedField> {
self.skipped_fields.iter()
}
}
/// Data needed for (de)serialization of a skipped field.
#[derive(Debug, Clone)]
pub struct SkippedField {
default_fn: fn() -> Box<dyn Reflect>,
}
impl SkippedField {
/// Create a new `SkippedField`.
///
/// # Arguments
///
/// * `default_fn`: A function pointer used to generate a default instance of the field.
pub fn new(default_fn: fn() -> Box<dyn Reflect>) -> Self {
Self { default_fn }
}
/// Generates a default instance of the field.
pub fn generate_default(&self) -> Box<dyn Reflect> {
(self.default_fn)()
}
}

515
vendor/bevy_reflect/src/set.rs vendored Normal file
View File

@@ -0,0 +1,515 @@
use alloc::{boxed::Box, format, vec::Vec};
use core::fmt::{Debug, Formatter};
use bevy_platform::collections::{hash_table::OccupiedEntry as HashTableOccupiedEntry, HashTable};
use bevy_reflect_derive::impl_type_path;
use crate::{
generics::impl_generic_info_methods, hash_error, type_info::impl_type_methods, ApplyError,
Generics, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
TypeInfo, TypePath,
};
/// A trait used to power [set-like] operations via [reflection].
///
/// Sets contain zero or more entries of a fixed type, and correspond to types
/// like [`HashSet`] and [`BTreeSet`].
/// The order of these entries is not guaranteed by this trait.
///
/// # Hashing and equality
///
/// All values are expected to return a valid hash value from [`PartialReflect::reflect_hash`] and be
/// comparable using [`PartialReflect::reflect_partial_eq`].
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding
/// `#[reflect(Hash, PartialEq)]` to the entire struct or enum.
/// The ordering is expected to be total, that is as if the reflected type implements the [`Eq`] trait.
/// This is true even for manual implementors who do not hash or compare values,
/// as it is still relied on by [`DynamicSet`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Set};
/// use std::collections::HashSet;
///
///
/// let foo: &mut dyn Set = &mut HashSet::<u32>::new();
/// foo.insert_boxed(Box::new(123_u32));
/// assert_eq!(foo.len(), 1);
///
/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123_u32));
/// ```
///
/// [`HashSet`]: std::collections::HashSet
/// [`BTreeSet`]: alloc::collections::BTreeSet
/// [set-like]: https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html
/// [reflection]: crate
pub trait Set: PartialReflect {
/// Returns a reference to the value.
///
/// If no value is contained, returns `None`.
fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
/// Returns the number of elements in the set.
fn len(&self) -> usize;
/// Returns `true` if the list contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the values of the set.
fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_>;
/// Drain the values of this set to get a vector of owned values.
///
/// After calling this function, `self` will be empty.
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
/// Clones the set, producing a [`DynamicSet`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_set` instead")]
fn clone_dynamic(&self) -> DynamicSet {
self.to_dynamic_set()
}
/// Creates a new [`DynamicSet`] from this set.
fn to_dynamic_set(&self) -> DynamicSet {
let mut set = DynamicSet::default();
set.set_represented_type(self.get_represented_type_info());
for value in self.iter() {
set.insert_boxed(value.to_dynamic());
}
set
}
/// Inserts a value into the set.
///
/// If the set did not have this value present, `true` is returned.
/// If the set did have this value present, `false` is returned.
fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool;
/// Removes a value from the set.
///
/// If the set did not have this value present, `true` is returned.
/// If the set did have this value present, `false` is returned.
fn remove(&mut self, value: &dyn PartialReflect) -> bool;
/// Checks if the given value is contained in the set
fn contains(&self, value: &dyn PartialReflect) -> bool;
}
/// A container for compile-time set info.
#[derive(Clone, Debug)]
pub struct SetInfo {
ty: Type,
generics: Generics,
value_ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl SetInfo {
/// Create a new [`SetInfo`].
pub fn new<TSet: Set + TypePath, TValue: Reflect + TypePath>() -> Self {
Self {
ty: Type::of::<TSet>(),
generics: Generics::new(),
value_ty: Type::of::<TValue>(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this set.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
impl_type_methods!(ty);
/// The [type] of the value.
///
/// [type]: Type
pub fn value_ty(&self) -> Type {
self.value_ty
}
/// The docstring of this set, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// An ordered set of reflected values.
#[derive(Default)]
pub struct DynamicSet {
represented_type: Option<&'static TypeInfo>,
hash_table: HashTable<Box<dyn PartialReflect>>,
}
impl DynamicSet {
/// Sets the [type] to be represented by this `DynamicSet`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Set`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Set(_)),
"expected TypeInfo::Set but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Inserts a typed value into the set.
pub fn insert<V: Reflect>(&mut self, value: V) {
self.insert_boxed(Box::new(value));
}
fn internal_hash(value: &dyn PartialReflect) -> u64 {
value.reflect_hash().expect(&hash_error!(value))
}
fn internal_eq(
value: &dyn PartialReflect,
) -> impl FnMut(&Box<dyn PartialReflect>) -> bool + '_ {
|other| {
value
.reflect_partial_eq(&**other)
.expect("Underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
}
}
}
impl Set for DynamicSet {
fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
self.hash_table
.find(Self::internal_hash(value), Self::internal_eq(value))
.map(|value| &**value)
}
fn len(&self) -> usize {
self.hash_table.len()
}
fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_> {
let iter = self.hash_table.iter().map(|v| &**v);
Box::new(iter)
}
fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
self.hash_table.drain().collect::<Vec<_>>()
}
fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool {
assert_eq!(
value.reflect_partial_eq(&*value),
Some(true),
"Values inserted in `Set` like types are expected to reflect `PartialEq`"
);
match self
.hash_table
.find_mut(Self::internal_hash(&*value), Self::internal_eq(&*value))
{
Some(old) => {
*old = value;
false
}
None => {
self.hash_table.insert_unique(
Self::internal_hash(value.as_ref()),
value,
|boxed| Self::internal_hash(boxed.as_ref()),
);
true
}
}
}
fn remove(&mut self, value: &dyn PartialReflect) -> bool {
self.hash_table
.find_entry(Self::internal_hash(value), Self::internal_eq(value))
.map(HashTableOccupiedEntry::remove)
.is_ok()
}
fn contains(&self, value: &dyn PartialReflect) -> bool {
self.hash_table
.find(Self::internal_hash(value), Self::internal_eq(value))
.is_some()
}
}
impl PartialReflect for DynamicSet {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
#[inline]
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
set_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
set_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Set
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Set(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Set(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Set(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
set_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicSet(")?;
set_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicSet);
impl Debug for DynamicSet {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicSet {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
let mut this = Self {
represented_type: None,
hash_table: HashTable::new(),
};
for value in values {
this.insert_boxed(value);
}
this
}
}
impl<T: Reflect> FromIterator<T> for DynamicSet {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
let mut this = Self {
represented_type: None,
hash_table: HashTable::new(),
};
for value in values {
this.insert(value);
}
this
}
}
impl IntoIterator for DynamicSet {
type Item = Box<dyn PartialReflect>;
type IntoIter = bevy_platform::collections::hash_table::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.hash_table.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicSet {
type Item = &'a dyn PartialReflect;
type IntoIter = core::iter::Map<
bevy_platform::collections::hash_table::Iter<'a, Box<dyn PartialReflect>>,
fn(&'a Box<dyn PartialReflect>) -> Self::Item,
>;
fn into_iter(self) -> Self::IntoIter {
self.hash_table.iter().map(|v| v.as_ref())
}
}
/// Compares a [`Set`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a set;
/// - `b` is the same length as `a`;
/// - For each value pair in `a`, `b` contains the value too,
/// and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn set_partial_eq<M: Set>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Set(set) = b.reflect_ref() else {
return Some(false);
};
if a.len() != set.len() {
return Some(false);
}
for value in a.iter() {
if let Some(set_value) = set.get(value) {
let eq_result = value.reflect_partial_eq(set_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`Set`] types.
///
/// # Example
/// ```
/// # use std::collections::HashSet;
/// use bevy_reflect::Reflect;
///
/// let mut my_set = HashSet::new();
/// my_set.insert(String::from("Hello"));
/// println!("{:#?}", &my_set as &dyn Reflect);
///
/// // Output:
///
/// // {
/// // "Hello",
/// // }
/// ```
#[inline]
pub fn set_debug(dyn_set: &dyn Set, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_set();
for value in dyn_set.iter() {
debug.entry(&value as &dyn Debug);
}
debug.finish()
}
/// Applies the elements of reflected set `b` to the corresponding elements of set `a`.
///
/// If a value from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Panics
///
/// This function panics if `b` is not a reflected set.
#[inline]
pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
if let ReflectRef::Set(set_value) = b.reflect_ref() {
for b_value in set_value.iter() {
if a.get(b_value).is_none() {
a.insert_boxed(b_value.to_dynamic());
}
}
} else {
panic!("Attempted to apply a non-set type to a set type.");
}
}
/// Tries to apply the elements of reflected set `b` to the corresponding elements of set `a`
/// and returns a Result.
///
/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected set or if
/// applying elements to each other fails.
#[inline]
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let set_value = b.reflect_ref().as_set()?;
for b_value in set_value.iter() {
if a.get(b_value).is_none() {
a.insert_boxed(b_value.to_dynamic());
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::DynamicSet;
use alloc::string::{String, ToString};
#[test]
fn test_into_iter() {
let expected = ["foo", "bar", "baz"];
let mut set = DynamicSet::default();
set.insert(expected[0].to_string());
set.insert(expected[1].to_string());
set.insert(expected[2].to_string());
for item in set.into_iter() {
let value = item
.try_take::<String>()
.expect("couldn't downcast to String");
let index = expected
.iter()
.position(|i| *i == value.as_str())
.expect("Element found in expected array");
assert_eq!(expected[index], value);
}
}
}

24
vendor/bevy_reflect/src/std_traits.rs vendored Normal file
View File

@@ -0,0 +1,24 @@
use crate::{FromType, Reflect};
use alloc::boxed::Box;
/// A struct used to provide the default value of a type.
///
/// A [`ReflectDefault`] for type `T` can be obtained via [`FromType::from_type`].
#[derive(Clone)]
pub struct ReflectDefault {
default: fn() -> Box<dyn Reflect>,
}
impl ReflectDefault {
pub fn default(&self) -> Box<dyn Reflect> {
(self.default)()
}
}
impl<T: Reflect + Default> FromType<T> for ReflectDefault {
fn from_type() -> Self {
ReflectDefault {
default: || Box::<T>::default(),
}
}
}

604
vendor/bevy_reflect/src/struct_trait.rs vendored Normal file
View File

@@ -0,0 +1,604 @@
use crate::generics::impl_generic_info_methods;
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
ApplyError, Generics, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
};
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
use bevy_platform::collections::HashMap;
use bevy_platform::sync::Arc;
use bevy_reflect_derive::impl_type_path;
use core::{
fmt::{Debug, Formatter},
slice::Iter,
};
/// A trait used to power [struct-like] operations via [reflection].
///
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
/// be dynamically addressed by both name and index.
///
/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a standard struct,
/// this trait will be automatically implemented.
/// This goes for [unit structs] as well.
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, Struct};
///
/// #[derive(Reflect)]
/// struct Foo {
/// bar: u32,
/// }
///
/// let foo = Foo { bar: 123 };
///
/// assert_eq!(foo.field_len(), 1);
/// assert_eq!(foo.name_at(0), Some("bar"));
///
/// let field: &dyn PartialReflect = foo.field("bar").unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html
/// [reflection]: crate
/// [unit structs]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
pub trait Struct: PartialReflect {
/// Returns a reference to the value of the field named `name` as a `&dyn
/// PartialReflect`.
fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field named `name` as a
/// `&mut dyn PartialReflect`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn PartialReflect`.
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn PartialReflect`.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the name of the field with index `index`.
fn name_at(&self, index: usize) -> Option<&str>;
/// Returns the number of fields in the struct.
fn field_len(&self) -> usize;
/// Returns an iterator over the values of the reflectable fields for this struct.
fn iter_fields(&self) -> FieldIter;
/// Clones the struct into a [`DynamicStruct`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_struct` instead")]
fn clone_dynamic(&self) -> DynamicStruct {
self.to_dynamic_struct()
}
fn to_dynamic_struct(&self) -> DynamicStruct {
let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.set_represented_type(self.get_represented_type_info());
for (i, value) in self.iter_fields().enumerate() {
dynamic_struct.insert_boxed(self.name_at(i).unwrap(), value.to_dynamic());
}
dynamic_struct
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
self.get_represented_type_info()?.as_struct().ok()
}
}
/// A container for compile-time named struct info.
#[derive(Clone, Debug)]
pub struct StructInfo {
ty: Type,
generics: Generics,
fields: Box<[NamedField]>,
field_names: Box<[&'static str]>,
field_indices: HashMap<&'static str, usize>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl StructInfo {
/// Create a new [`StructInfo`].
///
/// # Arguments
///
/// * `fields`: The fields of this struct in the order they are defined
pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
let field_indices = fields
.iter()
.enumerate()
.map(|(index, field)| (field.name(), index))
.collect::<HashMap<_, _>>();
let field_names = fields.iter().map(NamedField::name).collect();
Self {
ty: Type::of::<T>(),
generics: Generics::new(),
fields: fields.to_vec().into_boxed_slice(),
field_names,
field_indices,
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this struct.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this struct.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// A slice containing the names of all fields in order.
pub fn field_names(&self) -> &[&'static str] {
&self.field_names
}
/// Get the field with the given name.
pub fn field(&self, name: &str) -> Option<&NamedField> {
self.field_indices
.get(name)
.map(|index| &self.fields[*index])
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&NamedField> {
self.fields.get(index)
}
/// Get the index of the field with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
/// Iterate over the fields of this struct.
pub fn iter(&self) -> Iter<'_, NamedField> {
self.fields.iter()
}
/// The total number of fields in this struct.
pub fn field_len(&self) -> usize {
self.fields.len()
}
impl_type_methods!(ty);
/// The docstring of this struct, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "struct");
impl_generic_info_methods!(generics);
}
/// An iterator over the field values of a struct.
pub struct FieldIter<'a> {
pub(crate) struct_val: &'a dyn Struct,
pub(crate) index: usize,
}
impl<'a> FieldIter<'a> {
pub fn new(value: &'a dyn Struct) -> Self {
FieldIter {
struct_val: value,
index: 0,
}
}
}
impl<'a> Iterator for FieldIter<'a> {
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.struct_val.field_at(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.struct_val.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for FieldIter<'a> {}
/// A convenience trait which combines fetching and downcasting of struct
/// fields.
///
/// # Example
///
/// ```
/// use bevy_reflect::{GetField, Reflect};
///
/// #[derive(Reflect)]
/// struct Foo {
/// bar: String,
/// }
///
/// # fn main() {
/// let mut foo = Foo { bar: "Hello, world!".to_string() };
///
/// foo.get_field_mut::<String>("bar").unwrap().truncate(5);
/// assert_eq!(foo.get_field::<String>("bar"), Some(&"Hello".to_string()));
/// # }
/// ```
pub trait GetField {
/// Returns a reference to the value of the field named `name`, downcast to
/// `T`.
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
/// Returns a mutable reference to the value of the field named `name`,
/// downcast to `T`.
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
}
impl<S: Struct> GetField for S {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetField for dyn Struct {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
/// A struct type which allows fields to be added at runtime.
#[derive(Default)]
pub struct DynamicStruct {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn PartialReflect>>,
field_names: Vec<Cow<'static, str>>,
field_indices: HashMap<Cow<'static, str>, usize>,
}
impl DynamicStruct {
/// Sets the [type] to be represented by this `DynamicStruct`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Struct`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Struct(_)),
"expected TypeInfo::Struct but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Inserts a field named `name` with value `value` into the struct.
///
/// If the field already exists, it is overwritten.
pub fn insert_boxed<'a>(
&mut self,
name: impl Into<Cow<'a, str>>,
value: Box<dyn PartialReflect>,
) {
let name: Cow<str> = name.into();
if let Some(index) = self.field_indices.get(&name) {
self.fields[*index] = value;
} else {
self.fields.push(value);
self.field_indices
.insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
self.field_names.push(Cow::Owned(name.into_owned()));
}
}
/// Inserts a field named `name` with the typed value `value` into the struct.
///
/// If the field already exists, it is overwritten.
pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
self.insert_boxed(name, Box::new(value));
}
/// Gets the index of the field with the given name.
pub fn index_of(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
}
impl Struct for DynamicStruct {
#[inline]
fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
self.field_indices
.get(name)
.map(|index| &*self.fields[*index])
}
#[inline]
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
if let Some(index) = self.field_indices.get(name) {
Some(&mut *self.fields[*index])
} else {
None
}
}
#[inline]
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|value| &**value)
}
#[inline]
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|value| &mut **value)
}
#[inline]
fn name_at(&self, index: usize) -> Option<&str> {
self.field_names.get(index).map(AsRef::as_ref)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> FieldIter {
FieldIter {
struct_val: self,
index: 0,
}
}
}
impl PartialReflect for DynamicStruct {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
let struct_value = value.reflect_ref().as_struct()?;
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(v) = self.field_mut(name) {
v.try_apply(value)?;
}
}
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Struct(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
struct_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicStruct(")?;
struct_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicStruct);
impl Debug for DynamicStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
where
N: Into<Cow<'a, str>>,
{
/// Create a dynamic struct that doesn't represent a type from the
/// field name, field value pairs.
fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
let mut dynamic_struct = Self::default();
for (name, value) in fields.into_iter() {
dynamic_struct.insert_boxed(name, value);
}
dynamic_struct
}
}
impl IntoIterator for DynamicStruct {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicStruct {
type Item = &'a dyn PartialReflect;
type IntoIter = FieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Compares a [`Struct`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a struct;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn struct_partial_eq<S: Struct + ?Sized>(a: &S, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
return Some(false);
};
if a.field_len() != struct_value.field_len() {
return Some(false);
}
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(field_value) = a.field(name) {
let eq_result = field_value.reflect_partial_eq(value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`Struct`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
/// #[derive(Reflect)]
/// struct MyStruct {
/// foo: usize
/// }
///
/// let my_struct: &dyn Reflect = &MyStruct { foo: 123 };
/// println!("{:#?}", my_struct);
///
/// // Output:
///
/// // MyStruct {
/// // foo: 123,
/// // }
/// ```
#[inline]
pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_struct(
dyn_struct
.get_represented_type_info()
.map(TypeInfo::type_path)
.unwrap_or("_"),
);
for field_index in 0..dyn_struct.field_len() {
let field = dyn_struct.field_at(field_index).unwrap();
debug.field(
dyn_struct.name_at(field_index).unwrap(),
&field as &dyn Debug,
);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use crate::*;
#[derive(Reflect, Default)]
struct MyStruct {
a: (),
b: (),
c: (),
}
#[test]
fn next_index_increment() {
let my_struct = MyStruct::default();
let mut iter = my_struct.iter_fields();
iter.index = iter.len() - 1;
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
// When None we should no longer increase index
let prev_index = iter.index;
assert!(iter.next().is_none());
assert_eq!(prev_index, iter.index);
assert!(iter.next().is_none());
assert_eq!(prev_index, iter.index);
}
}

804
vendor/bevy_reflect/src/tuple.rs vendored Normal file
View File

@@ -0,0 +1,804 @@
use bevy_reflect_derive::impl_type_path;
use variadics_please::all_tuples;
use crate::generics::impl_generic_info_methods;
use crate::{
type_info::impl_type_methods, utility::GenericTypePathCell, ApplyError, FromReflect, Generics,
GetTypeRegistration, MaybeTyped, PartialReflect, Reflect, ReflectCloneError, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath, TypeRegistration, TypeRegistry,
Typed, UnnamedField,
};
use alloc::{boxed::Box, vec, vec::Vec};
use core::{
any::Any,
fmt::{Debug, Formatter},
slice::Iter,
};
/// A trait used to power [tuple-like] operations via [reflection].
///
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
/// be dynamically addressed by index.
///
/// This trait is automatically implemented for arbitrary tuples of up to 12
/// elements, provided that each element implements [`Reflect`].
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Tuple};
///
/// let foo = (123_u32, true);
/// assert_eq!(foo.field_len(), 2);
///
/// let field: &dyn PartialReflect = foo.field(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [tuple-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
/// [reflection]: crate
pub trait Tuple: PartialReflect {
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
fn field(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn Reflect`.
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of fields in the tuple.
fn field_len(&self) -> usize;
/// Returns an iterator over the values of the tuple's fields.
fn iter_fields(&self) -> TupleFieldIter;
/// Drain the fields of this tuple to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the tuple into a [`DynamicTuple`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_tuple` instead")]
fn clone_dynamic(&self) -> DynamicTuple {
self.to_dynamic_tuple()
}
/// Creates a new [`DynamicTuple`] from this tuple.
fn to_dynamic_tuple(&self) -> DynamicTuple {
DynamicTuple {
represented_type: self.get_represented_type_info(),
fields: self.iter_fields().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_tuple_info(&self) -> Option<&'static TupleInfo> {
self.get_represented_type_info()?.as_tuple().ok()
}
}
/// An iterator over the field values of a tuple.
pub struct TupleFieldIter<'a> {
pub(crate) tuple: &'a dyn Tuple,
pub(crate) index: usize,
}
impl<'a> TupleFieldIter<'a> {
pub fn new(value: &'a dyn Tuple) -> Self {
TupleFieldIter {
tuple: value,
index: 0,
}
}
}
impl<'a> Iterator for TupleFieldIter<'a> {
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple.field(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.tuple.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for TupleFieldIter<'a> {}
/// A convenience trait which combines fetching and downcasting of tuple
/// fields.
///
/// # Example
///
/// ```
/// use bevy_reflect::GetTupleField;
///
/// # fn main() {
/// let foo = ("blue".to_string(), 42_i32);
///
/// assert_eq!(foo.get_field::<String>(0), Some(&"blue".to_string()));
/// assert_eq!(foo.get_field::<i32>(1), Some(&42));
/// # }
/// ```
pub trait GetTupleField {
/// Returns a reference to the value of the field with index `index`,
/// downcast to `T`.
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
/// Returns a mutable reference to the value of the field with index
/// `index`, downcast to `T`.
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
}
impl<S: Tuple> GetTupleField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetTupleField for dyn Tuple {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
/// A container for compile-time tuple info.
#[derive(Clone, Debug)]
pub struct TupleInfo {
ty: Type,
generics: Generics,
fields: Box<[UnnamedField]>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl TupleInfo {
/// Create a new [`TupleInfo`].
///
/// # Arguments
///
/// * `fields`: The fields of this tuple in the order they are defined
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
Self {
ty: Type::of::<T>(),
generics: Generics::new(),
fields: fields.to_vec().into_boxed_slice(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this tuple.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {
self.fields.get(index)
}
/// Iterate over the fields of this tuple.
pub fn iter(&self) -> Iter<'_, UnnamedField> {
self.fields.iter()
}
/// The total number of fields in this tuple.
pub fn field_len(&self) -> usize {
self.fields.len()
}
impl_type_methods!(ty);
/// The docstring of this tuple, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
/// A tuple which allows fields to be added at runtime.
#[derive(Default, Debug)]
pub struct DynamicTuple {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn PartialReflect>>,
}
impl DynamicTuple {
/// Sets the [type] to be represented by this `DynamicTuple`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::Tuple`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::Tuple(_)),
"expected TypeInfo::Tuple but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Appends an element with value `value` to the tuple.
pub fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) {
self.represented_type = None;
self.fields.push(value);
}
/// Appends a typed element with value `value` to the tuple.
pub fn insert<T: PartialReflect>(&mut self, value: T) {
self.represented_type = None;
self.insert_boxed(Box::new(value));
}
}
impl Tuple for DynamicTuple {
#[inline]
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> TupleFieldIter {
TupleFieldIter {
tuple: self,
index: 0,
}
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.fields
}
}
impl PartialReflect for DynamicTuple {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
tuple_apply(self, value);
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Tuple(self)
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
tuple_try_apply(self, value)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
tuple_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicTuple(")?;
tuple_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicTuple);
impl FromIterator<Box<dyn PartialReflect>> for DynamicTuple {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
}
}
}
impl IntoIterator for DynamicTuple {
type Item = Box<dyn PartialReflect>;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicTuple {
type Item = &'a dyn PartialReflect;
type IntoIter = TupleFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// # Panics
///
/// This function panics if `b` is not a tuple.
#[inline]
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) {
if let Err(err) = tuple_try_apply(a, b) {
panic!("{err}");
}
}
/// Tries to apply the elements of `b` to the corresponding elements of `a` and
/// returns a Result.
///
/// # Errors
///
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a tuple or if
/// applying elements to each other fails.
#[inline]
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) -> Result<(), ApplyError> {
let tuple = b.reflect_ref().as_tuple()?;
for (i, value) in tuple.iter_fields().enumerate() {
if let Some(v) = a.field_mut(i) {
v.try_apply(value)?;
}
}
Ok(())
}
/// Compares a [`Tuple`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple;
/// - `b` has the same number of elements as `a`;
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_partial_eq<T: Tuple + ?Sized>(a: &T, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Tuple(b) = b.reflect_ref() else {
return Some(false);
};
if a.field_len() != b.field_len() {
return Some(false);
}
for (a_field, b_field) in a.iter_fields().zip(b.iter_fields()) {
let eq_result = a_field.reflect_partial_eq(b_field);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}
Some(true)
}
/// The default debug formatter for [`Tuple`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
///
/// let my_tuple: &dyn Reflect = &(1, 2, 3);
/// println!("{:#?}", my_tuple);
///
/// // Output:
///
/// // (
/// // 1,
/// // 2,
/// // 3,
/// // )
/// ```
#[inline]
pub fn tuple_debug(dyn_tuple: &dyn Tuple, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut debug = f.debug_tuple("");
for field in dyn_tuple.iter_fields() {
debug.field(&field as &dyn Debug);
}
debug.finish()
}
macro_rules! impl_reflect_tuple {
{$($index:tt : $name:tt),*} => {
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Tuple for ($($name,)*) {
#[inline]
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
match index {
$($index => Some(&self.$index as &dyn PartialReflect),)*
_ => None,
}
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
match index {
$($index => Some(&mut self.$index as &mut dyn PartialReflect),)*
_ => None,
}
}
#[inline]
fn field_len(&self) -> usize {
let indices: &[usize] = &[$($index as usize),*];
indices.len()
}
#[inline]
fn iter_fields(&self) -> TupleFieldIter {
TupleFieldIter {
tuple: self,
index: 0,
}
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
vec![
$(Box::new(self.$index),)*
]
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> PartialReflect for ($($name,)*) {
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info())
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Ok(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
Some(self)
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
Some(self)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Tuple(self)
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
crate::tuple_partial_eq(self, value)
}
fn apply(&mut self, value: &dyn PartialReflect) {
crate::tuple_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
crate::tuple_try_apply(self, value)
}
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new((
$(
self.$index.reflect_clone()?
.take::<$name>()
.expect("`Reflect::reflect_clone` should return the same type"),
)*
)))
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Reflect for ($($name,)*) {
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
}
fn as_reflect(&self) -> &dyn Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
}
impl <$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Typed for ($($name,)*) {
fn type_info() -> &'static TypeInfo {
static CELL: $crate::utility::GenericTypeInfoCell = $crate::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| {
let fields = [
$(UnnamedField::new::<$name>($index),)*
];
let info = TupleInfo::new::<Self>(&fields);
TypeInfo::Tuple(info)
})
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> GetTypeRegistration for ($($name,)*) {
fn get_type_registration() -> TypeRegistration {
TypeRegistration::of::<($($name,)*)>()
}
fn register_type_dependencies(_registry: &mut TypeRegistry) {
$(_registry.register::<$name>();)*
}
}
impl<$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*> FromReflect for ($($name,)*)
{
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
let _ref_tuple = reflect.reflect_ref().as_tuple().ok()?;
Some(
(
$(
<$name as FromReflect>::from_reflect(_ref_tuple.field($index)?)?,
)*
)
)
}
}
}
}
impl_reflect_tuple! {}
impl_reflect_tuple! {0: A}
impl_reflect_tuple! {0: A, 1: B}
impl_reflect_tuple! {0: A, 1: B, 2: C}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L}
macro_rules! impl_type_path_tuple {
($(#[$meta:meta])*) => {
$(#[$meta])*
impl TypePath for () {
fn type_path() -> &'static str {
"()"
}
fn short_type_path() -> &'static str {
"()"
}
}
};
($(#[$meta:meta])* $param:ident) => {
$(#[$meta])*
impl <$param: TypePath> TypePath for ($param,) {
fn type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() + $param::type_path() + ",)"
})
}
fn short_type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() + $param::short_type_path() + ",)"
})
}
}
};
($(#[$meta:meta])* $last:ident $(,$param:ident)*) => {
$(#[$meta])*
impl <$($param: TypePath,)* $last: TypePath> TypePath for ($($param,)* $last) {
fn type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() $(+ $param::type_path() + ", ")* + $last::type_path() + ")"
})
}
fn short_type_path() -> &'static str {
use $crate::__macro_exports::alloc_utils::ToOwned;
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() $(+ $param::short_type_path() + ", ")* + $last::short_type_path() + ")"
})
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_type_path_tuple,
0,
12,
P
);
#[cfg(feature = "functions")]
const _: () = {
macro_rules! impl_get_ownership_tuple {
($(#[$meta:meta])* $($name: ident),*) => {
$(#[$meta])*
$crate::func::args::impl_get_ownership!(($($name,)*); <$($name),*>);
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_get_ownership_tuple,
0,
12,
P
);
macro_rules! impl_from_arg_tuple {
($(#[$meta:meta])* $($name: ident),*) => {
$(#[$meta])*
$crate::func::args::impl_from_arg!(($($name,)*); <$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*>);
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_from_arg_tuple,
0,
12,
P
);
macro_rules! impl_into_return_tuple {
($(#[$meta:meta])* $($name: ident),+) => {
$(#[$meta])*
$crate::func::impl_into_return!(($($name,)*); <$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*>);
};
}
// The unit type (i.e. `()`) is special-cased, so we skip implementing it here.
all_tuples!(
#[doc(fake_variadic)]
impl_into_return_tuple,
1,
12,
P
);
};
#[cfg(test)]
mod tests {
use super::Tuple;
#[test]
fn next_index_increment() {
let mut iter = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).iter_fields();
let size = iter.len();
iter.index = size - 1;
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
// When None we should no longer increase index
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}

510
vendor/bevy_reflect/src/tuple_struct.rs vendored Normal file
View File

@@ -0,0 +1,510 @@
use bevy_reflect_derive::impl_type_path;
use crate::generics::impl_generic_info_methods;
use crate::{
attributes::{impl_custom_attribute_methods, CustomAttributes},
type_info::impl_type_methods,
ApplyError, DynamicTuple, Generics, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, Tuple, Type, TypeInfo, TypePath, UnnamedField,
};
use alloc::{boxed::Box, vec::Vec};
use bevy_platform::sync::Arc;
use core::{
fmt::{Debug, Formatter},
slice::Iter,
};
/// A trait used to power [tuple struct-like] operations via [reflection].
///
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
/// be dynamically addressed by index.
///
/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a tuple struct,
/// this trait will be automatically implemented.
///
/// # Example
///
/// ```
/// use bevy_reflect::{PartialReflect, Reflect, TupleStruct};
///
/// #[derive(Reflect)]
/// struct Foo(u32);
///
/// let foo = Foo(123);
///
/// assert_eq!(foo.field_len(), 1);
///
/// let field: &dyn PartialReflect = foo.field(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [tuple struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types
/// [reflection]: crate
pub trait TupleStruct: PartialReflect {
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
fn field(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn Reflect`.
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of fields in the tuple struct.
fn field_len(&self) -> usize;
/// Returns an iterator over the values of the tuple struct's fields.
fn iter_fields(&self) -> TupleStructFieldIter;
/// Clones the struct into a [`DynamicTupleStruct`].
#[deprecated(since = "0.16.0", note = "use `to_dynamic_tuple_struct` instead")]
fn clone_dynamic(&self) -> DynamicTupleStruct {
self.to_dynamic_tuple_struct()
}
/// Creates a new [`DynamicTupleStruct`] from this tuple struct.
fn to_dynamic_tuple_struct(&self) -> DynamicTupleStruct {
DynamicTupleStruct {
represented_type: self.get_represented_type_info(),
fields: self.iter_fields().map(PartialReflect::to_dynamic).collect(),
}
}
/// Will return `None` if [`TypeInfo`] is not available.
fn get_represented_tuple_struct_info(&self) -> Option<&'static TupleStructInfo> {
self.get_represented_type_info()?.as_tuple_struct().ok()
}
}
/// A container for compile-time tuple struct info.
#[derive(Clone, Debug)]
pub struct TupleStructInfo {
ty: Type,
generics: Generics,
fields: Box<[UnnamedField]>,
custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl TupleStructInfo {
/// Create a new [`TupleStructInfo`].
///
/// # Arguments
///
/// * `fields`: The fields of this struct in the order they are defined
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
Self {
ty: Type::of::<T>(),
generics: Generics::new(),
fields: fields.to_vec().into_boxed_slice(),
custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this struct.
#[cfg(feature = "documentation")]
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
Self { docs, ..self }
}
/// Sets the custom attributes for this struct.
pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
Self {
custom_attributes: Arc::new(custom_attributes),
..self
}
}
/// Get the field at the given index.
pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {
self.fields.get(index)
}
/// Iterate over the fields of this struct.
pub fn iter(&self) -> Iter<'_, UnnamedField> {
self.fields.iter()
}
/// The total number of fields in this struct.
pub fn field_len(&self) -> usize {
self.fields.len()
}
impl_type_methods!(ty);
/// The docstring of this struct, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_custom_attribute_methods!(self.custom_attributes, "struct");
impl_generic_info_methods!(generics);
}
/// An iterator over the field values of a tuple struct.
pub struct TupleStructFieldIter<'a> {
pub(crate) tuple_struct: &'a dyn TupleStruct,
pub(crate) index: usize,
}
impl<'a> TupleStructFieldIter<'a> {
pub fn new(value: &'a dyn TupleStruct) -> Self {
TupleStructFieldIter {
tuple_struct: value,
index: 0,
}
}
}
impl<'a> Iterator for TupleStructFieldIter<'a> {
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple_struct.field(self.index);
self.index += value.is_some() as usize;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.tuple_struct.field_len();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for TupleStructFieldIter<'a> {}
/// A convenience trait which combines fetching and downcasting of tuple
/// struct fields.
///
/// # Example
///
/// ```
/// use bevy_reflect::{GetTupleStructField, Reflect};
///
/// #[derive(Reflect)]
/// struct Foo(String);
///
/// # fn main() {
/// let mut foo = Foo("Hello, world!".to_string());
///
/// foo.get_field_mut::<String>(0).unwrap().truncate(5);
/// assert_eq!(foo.get_field::<String>(0), Some(&"Hello".to_string()));
/// # }
/// ```
pub trait GetTupleStructField {
/// Returns a reference to the value of the field with index `index`,
/// downcast to `T`.
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
/// Returns a mutable reference to the value of the field with index
/// `index`, downcast to `T`.
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
}
impl<S: TupleStruct> GetTupleStructField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetTupleStructField for dyn TupleStruct {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.try_downcast_mut::<T>())
}
}
/// A tuple struct which allows fields to be added at runtime.
#[derive(Default)]
pub struct DynamicTupleStruct {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn PartialReflect>>,
}
impl DynamicTupleStruct {
/// Sets the [type] to be represented by this `DynamicTupleStruct`.
///
/// # Panics
///
/// Panics if the given [type] is not a [`TypeInfo::TupleStruct`].
///
/// [type]: TypeInfo
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
if let Some(represented_type) = represented_type {
assert!(
matches!(represented_type, TypeInfo::TupleStruct(_)),
"expected TypeInfo::TupleStruct but received: {:?}",
represented_type
);
}
self.represented_type = represented_type;
}
/// Appends an element with value `value` to the tuple struct.
pub fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) {
self.fields.push(value);
}
/// Appends a typed element with value `value` to the tuple struct.
pub fn insert<T: PartialReflect>(&mut self, value: T) {
self.insert_boxed(Box::new(value));
}
}
impl TupleStruct for DynamicTupleStruct {
#[inline]
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> TupleStructFieldIter {
TupleStructFieldIter {
tuple_struct: self,
index: 0,
}
}
}
impl PartialReflect for DynamicTupleStruct {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
let tuple_struct = value.reflect_ref().as_tuple_struct()?;
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(v) = self.field_mut(i) {
v.try_apply(value)?;
}
}
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::TupleStruct
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::TupleStruct(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::TupleStruct(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::TupleStruct(self)
}
#[inline]
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
tuple_struct_partial_eq(self, value)
}
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "DynamicTupleStruct(")?;
tuple_struct_debug(self, f)?;
write!(f, ")")
}
#[inline]
fn is_dynamic(&self) -> bool {
true
}
}
impl_type_path!((in bevy_reflect) DynamicTupleStruct);
impl Debug for DynamicTupleStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.debug(f)
}
}
impl From<DynamicTuple> for DynamicTupleStruct {
fn from(value: DynamicTuple) -> Self {
Self {
represented_type: None,
fields: Box::new(value).drain(),
}
}
}
impl FromIterator<Box<dyn PartialReflect>> for DynamicTupleStruct {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
}
}
}
impl IntoIterator for DynamicTupleStruct {
type Item = Box<dyn PartialReflect>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicTupleStruct {
type Item = &'a dyn PartialReflect;
type IntoIter = TupleStructFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Compares a [`TupleStruct`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple struct;
/// - `b` has the same number of fields as `a`;
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_struct_partial_eq<S: TupleStruct + ?Sized>(
a: &S,
b: &dyn PartialReflect,
) -> Option<bool> {
let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() else {
return Some(false);
};
if a.field_len() != tuple_struct.field_len() {
return Some(false);
}
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(field_value) = a.field(i) {
let eq_result = field_value.reflect_partial_eq(value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
}
}
Some(true)
}
/// The default debug formatter for [`TupleStruct`] types.
///
/// # Example
/// ```
/// use bevy_reflect::Reflect;
/// #[derive(Reflect)]
/// struct MyTupleStruct(usize);
///
/// let my_tuple_struct: &dyn Reflect = &MyTupleStruct(123);
/// println!("{:#?}", my_tuple_struct);
///
/// // Output:
///
/// // MyTupleStruct (
/// // 123,
/// // )
/// ```
#[inline]
pub fn tuple_struct_debug(
dyn_tuple_struct: &dyn TupleStruct,
f: &mut Formatter<'_>,
) -> core::fmt::Result {
let mut debug = f.debug_tuple(
dyn_tuple_struct
.get_represented_type_info()
.map(TypeInfo::type_path)
.unwrap_or("_"),
);
for field in dyn_tuple_struct.iter_fields() {
debug.field(&field as &dyn Debug);
}
debug.finish()
}
#[cfg(test)]
mod tests {
use crate::*;
#[derive(Reflect)]
struct Ts(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
#[test]
fn next_index_increment() {
let mut iter = Ts(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).iter_fields();
let size = iter.len();
iter.index = size - 1;
let prev_index = iter.index;
assert!(iter.next().is_some());
assert_eq!(prev_index, iter.index - 1);
// When None we should no longer increase index
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
assert!(iter.next().is_none());
assert_eq!(size, iter.index);
}
}

602
vendor/bevy_reflect/src/type_info.rs vendored Normal file
View File

@@ -0,0 +1,602 @@
use crate::{
ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicStruct, DynamicTuple,
DynamicTupleStruct, EnumInfo, Generics, ListInfo, MapInfo, PartialReflect, Reflect,
ReflectKind, SetInfo, StructInfo, TupleInfo, TupleStructInfo, TypePath, TypePathTable,
};
use core::{
any::{Any, TypeId},
fmt::{Debug, Formatter},
hash::Hash,
};
use thiserror::Error;
/// A static accessor to compile-time type information.
///
/// This trait is automatically implemented by the [`#[derive(Reflect)]`](derive@crate::Reflect) macro
/// and allows type information to be processed without an instance of that type.
///
/// If you need to use this trait as a generic bound along with other reflection traits,
/// for your convenience, consider using [`Reflectable`] instead.
///
/// # Implementing
///
/// While it is recommended to leave implementing this trait to the `#[derive(Reflect)]` macro,
/// it is possible to implement this trait manually. If a manual implementation is needed,
/// you _must_ ensure that the information you provide is correct, otherwise various systems that
/// rely on this trait may fail in unexpected ways.
///
/// Implementors may have difficulty in generating a reference to [`TypeInfo`] with a static
/// lifetime. Luckily, this crate comes with some [utility] structs, to make generating these
/// statics much simpler.
///
/// # Example
///
/// ```
/// # use core::any::Any;
/// # use bevy_reflect::{DynamicTypePath, NamedField, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, TypePath, OpaqueInfo, ApplyError};
/// # use bevy_reflect::utility::NonGenericTypeInfoCell;
/// use bevy_reflect::Typed;
///
/// struct MyStruct {
/// foo: usize,
/// bar: (f32, f32)
/// }
///
/// impl Typed for MyStruct {
/// fn type_info() -> &'static TypeInfo {
/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
/// CELL.get_or_set(|| {
/// let fields = [
/// NamedField::new::<usize >("foo"),
/// NamedField::new::<(f32, f32) >("bar"),
/// ];
/// let info = StructInfo::new::<Self>(&fields);
/// TypeInfo::Struct(info)
/// })
/// }
/// }
///
/// # impl TypePath for MyStruct {
/// # fn type_path() -> &'static str { todo!() }
/// # fn short_type_path() -> &'static str { todo!() }
/// # }
/// # impl PartialReflect for MyStruct {
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> { todo!() }
/// # fn as_partial_reflect(&self) -> &dyn PartialReflect { todo!() }
/// # fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { todo!() }
/// # fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> { todo!() }
/// # fn try_as_reflect(&self) -> Option<&dyn Reflect> { todo!() }
/// # fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { todo!() }
/// # fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { todo!() }
/// # fn reflect_ref(&self) -> ReflectRef { todo!() }
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
/// # }
/// # impl Reflect for MyStruct {
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # }
/// ```
///
/// [`Reflectable`]: crate::Reflectable
/// [utility]: crate::utility
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Typed` so cannot provide static type information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait Typed: Reflect + TypePath {
/// Returns the compile-time [info] for the underlying type.
///
/// [info]: TypeInfo
fn type_info() -> &'static TypeInfo;
}
/// A wrapper trait around [`Typed`].
///
/// This trait is used to provide a way to get compile-time type information for types that
/// do implement `Typed` while also allowing for types that do not implement `Typed` to be used.
/// It's used instead of `Typed` directly to avoid making dynamic types also
/// implement `Typed` in order to be used as active fields.
///
/// This trait has a blanket implementation for all types that implement `Typed`
/// and manual implementations for all dynamic types (which simply return `None`).
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Typed` so cannot provide static type information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait MaybeTyped: PartialReflect {
/// Returns the compile-time [info] for the underlying type, if it exists.
///
/// [info]: TypeInfo
fn maybe_type_info() -> Option<&'static TypeInfo> {
None
}
}
impl<T: Typed> MaybeTyped for T {
fn maybe_type_info() -> Option<&'static TypeInfo> {
Some(T::type_info())
}
}
impl MaybeTyped for DynamicEnum {}
impl MaybeTyped for DynamicTupleStruct {}
impl MaybeTyped for DynamicStruct {}
impl MaybeTyped for DynamicMap {}
impl MaybeTyped for DynamicList {}
impl MaybeTyped for DynamicArray {}
impl MaybeTyped for DynamicTuple {}
/// Dynamic dispatch for [`Typed`].
///
/// Since this is a supertrait of [`Reflect`] its methods can be called on a `dyn Reflect`.
///
/// [`Reflect`]: crate::Reflect
#[diagnostic::on_unimplemented(
message = "`{Self}` can not provide dynamic type information through reflection",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait DynamicTyped {
/// See [`Typed::type_info`].
fn reflect_type_info(&self) -> &'static TypeInfo;
}
impl<T: Typed> DynamicTyped for T {
#[inline]
fn reflect_type_info(&self) -> &'static TypeInfo {
Self::type_info()
}
}
/// A [`TypeInfo`]-specific error.
#[derive(Debug, Error)]
pub enum TypeInfoError {
/// Caused when a type was expected to be of a certain [kind], but was not.
///
/// [kind]: ReflectKind
#[error("kind mismatch: expected {expected:?}, received {received:?}")]
KindMismatch {
expected: ReflectKind,
received: ReflectKind,
},
}
/// Compile-time type information for various reflected types.
///
/// Generally, for any given type, this value can be retrieved in one of four ways:
///
/// 1. [`Typed::type_info`]
/// 2. [`DynamicTyped::reflect_type_info`]
/// 3. [`PartialReflect::get_represented_type_info`]
/// 4. [`TypeRegistry::get_type_info`]
///
/// Each return a static reference to [`TypeInfo`], but they all have their own use cases.
/// For example, if you know the type at compile time, [`Typed::type_info`] is probably
/// the simplest. If you have a `dyn Reflect` you can use [`DynamicTyped::reflect_type_info`].
/// If all you have is a `dyn PartialReflect`, you'll probably want [`PartialReflect::get_represented_type_info`].
/// Lastly, if all you have is a [`TypeId`] or [type path], you will need to go through
/// [`TypeRegistry::get_type_info`].
///
/// You may also opt to use [`TypeRegistry::get_type_info`] in place of the other methods simply because
/// it can be more performant. This is because those other methods may require attaining a lock on
/// the static [`TypeInfo`], while the registry simply checks a map.
///
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
/// [`PartialReflect::get_represented_type_info`]: crate::PartialReflect::get_represented_type_info
/// [type path]: TypePath::type_path
#[derive(Debug, Clone)]
pub enum TypeInfo {
Struct(StructInfo),
TupleStruct(TupleStructInfo),
Tuple(TupleInfo),
List(ListInfo),
Array(ArrayInfo),
Map(MapInfo),
Set(SetInfo),
Enum(EnumInfo),
Opaque(OpaqueInfo),
}
impl TypeInfo {
/// The underlying Rust [type].
///
/// [type]: Type
pub fn ty(&self) -> &Type {
match self {
Self::Struct(info) => info.ty(),
Self::TupleStruct(info) => info.ty(),
Self::Tuple(info) => info.ty(),
Self::List(info) => info.ty(),
Self::Array(info) => info.ty(),
Self::Map(info) => info.ty(),
Self::Set(info) => info.ty(),
Self::Enum(info) => info.ty(),
Self::Opaque(info) => info.ty(),
}
}
/// The [`TypeId`] of the underlying type.
#[inline]
pub fn type_id(&self) -> TypeId {
self.ty().id()
}
/// A representation of the type path of the underlying type.
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
self.ty().type_path_table()
}
/// The [stable, full type path] of the underlying type.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.ty().path()
}
/// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
pub fn is<T: Any>(&self) -> bool {
self.ty().is::<T>()
}
/// The docstring of the underlying type, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&str> {
match self {
Self::Struct(info) => info.docs(),
Self::TupleStruct(info) => info.docs(),
Self::Tuple(info) => info.docs(),
Self::List(info) => info.docs(),
Self::Array(info) => info.docs(),
Self::Map(info) => info.docs(),
Self::Set(info) => info.docs(),
Self::Enum(info) => info.docs(),
Self::Opaque(info) => info.docs(),
}
}
/// Returns the [kind] of this `TypeInfo`.
///
/// [kind]: ReflectKind
pub fn kind(&self) -> ReflectKind {
match self {
Self::Struct(_) => ReflectKind::Struct,
Self::TupleStruct(_) => ReflectKind::TupleStruct,
Self::Tuple(_) => ReflectKind::Tuple,
Self::List(_) => ReflectKind::List,
Self::Array(_) => ReflectKind::Array,
Self::Map(_) => ReflectKind::Map,
Self::Set(_) => ReflectKind::Set,
Self::Enum(_) => ReflectKind::Enum,
Self::Opaque(_) => ReflectKind::Opaque,
}
}
impl_generic_info_methods!(self => {
match self {
Self::Struct(info) => info.generics(),
Self::TupleStruct(info) => info.generics(),
Self::Tuple(info) => info.generics(),
Self::List(info) => info.generics(),
Self::Array(info) => info.generics(),
Self::Map(info) => info.generics(),
Self::Set(info) => info.generics(),
Self::Enum(info) => info.generics(),
Self::Opaque(info) => info.generics(),
}
});
}
macro_rules! impl_cast_method {
($name:ident : $kind:ident => $info:ident) => {
#[doc = concat!("Attempts a cast to [`", stringify!($info), "`].")]
#[doc = concat!("\n\nReturns an error if `self` is not [`TypeInfo::", stringify!($kind), "`].")]
pub fn $name(&self) -> Result<&$info, TypeInfoError> {
match self {
Self::$kind(info) => Ok(info),
_ => Err(TypeInfoError::KindMismatch {
expected: ReflectKind::$kind,
received: self.kind(),
}),
}
}
};
}
/// Conversion convenience methods for [`TypeInfo`].
impl TypeInfo {
impl_cast_method!(as_struct: Struct => StructInfo);
impl_cast_method!(as_tuple_struct: TupleStruct => TupleStructInfo);
impl_cast_method!(as_tuple: Tuple => TupleInfo);
impl_cast_method!(as_list: List => ListInfo);
impl_cast_method!(as_array: Array => ArrayInfo);
impl_cast_method!(as_map: Map => MapInfo);
impl_cast_method!(as_enum: Enum => EnumInfo);
impl_cast_method!(as_opaque: Opaque => OpaqueInfo);
}
/// The base representation of a Rust type.
///
/// When possible, it is recommended to use [`&'static TypeInfo`] instead of this
/// as it provides more information as well as being smaller
/// (since a reference only takes the same number of bytes as a `usize`).
///
/// However, where a static reference to [`TypeInfo`] is not possible,
/// such as with trait objects and other types that can't implement [`Typed`],
/// this type can be used instead.
///
/// It only requires that the type implements [`TypePath`].
///
/// And unlike [`TypeInfo`], this type implements [`Copy`], [`Eq`], and [`Hash`],
/// making it useful as a key type.
///
/// It's especially helpful when compared to [`TypeId`] as it can provide the
/// actual [type path] when debugging, while still having the same performance
/// as hashing/comparing [`TypeId`] directly—at the cost of a little more memory.
///
/// # Examples
///
/// ```
/// use bevy_reflect::{Type, TypePath};
///
/// fn assert_char<T: ?Sized + TypePath>(t: &T) -> Result<(), String> {
/// let ty = Type::of::<T>();
/// if Type::of::<char>() == ty {
/// Ok(())
/// } else {
/// Err(format!("expected `char`, got `{}`", ty.path()))
/// }
/// }
///
/// assert_eq!(
/// assert_char(&'a'),
/// Ok(())
/// );
/// assert_eq!(
/// assert_char(&String::from("Hello, world!")),
/// Err(String::from("expected `char`, got `alloc::string::String`"))
/// );
/// ```
///
/// [`&'static TypeInfo`]: TypeInfo
#[derive(Copy, Clone)]
pub struct Type {
type_path_table: TypePathTable,
type_id: TypeId,
}
impl Type {
/// Create a new [`Type`] from a type that implements [`TypePath`].
pub fn of<T: TypePath + ?Sized>() -> Self {
Self {
type_path_table: TypePathTable::of::<T>(),
type_id: TypeId::of::<T>(),
}
}
/// Returns the [`TypeId`] of the type.
#[inline]
pub fn id(&self) -> TypeId {
self.type_id
}
/// See [`TypePath::type_path`].
pub fn path(&self) -> &'static str {
self.type_path_table.path()
}
/// See [`TypePath::short_type_path`].
pub fn short_path(&self) -> &'static str {
self.type_path_table.short_path()
}
/// See [`TypePath::type_ident`].
pub fn ident(&self) -> Option<&'static str> {
self.type_path_table.ident()
}
/// See [`TypePath::crate_name`].
pub fn crate_name(&self) -> Option<&'static str> {
self.type_path_table.crate_name()
}
/// See [`TypePath::module_path`].
pub fn module_path(&self) -> Option<&'static str> {
self.type_path_table.module_path()
}
/// A representation of the type path of this.
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path_table
}
/// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
}
/// This implementation will only output the [type path] of the type.
///
/// If you need to include the [`TypeId`] in the output,
/// you can access it through [`Type::id`].
///
/// [type path]: TypePath
impl Debug for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.type_path_table.path())
}
}
impl Eq for Type {}
/// This implementation purely relies on the [`TypeId`] of the type,
/// and not on the [type path].
///
/// [type path]: TypePath
impl PartialEq for Type {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.type_id == other.type_id
}
}
/// This implementation purely relies on the [`TypeId`] of the type,
/// and not on the [type path].
///
/// [type path]: TypePath
impl Hash for Type {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.type_id.hash(state);
}
}
macro_rules! impl_type_methods {
// Generates the type methods based off a single field.
($field:ident) => {
$crate::type_info::impl_type_methods!(self => {
&self.$field
});
};
// Generates the type methods based off a custom expression.
($self:ident => $expr:expr) => {
/// The underlying Rust [type].
///
/// [type]: crate::type_info::Type
pub fn ty(&$self) -> &$crate::type_info::Type {
$expr
}
/// The [`TypeId`] of this type.
///
/// [`TypeId`]: core::any::TypeId
pub fn type_id(&self) -> ::core::any::TypeId {
self.ty().id()
}
/// The [stable, full type path] of this type.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.ty().path()
}
/// A representation of the type path of this type.
///
/// Provides dynamic access to all methods on [`TypePath`].
///
/// [`TypePath`]: crate::type_path::TypePath
pub fn type_path_table(&self) -> &$crate::type_path::TypePathTable {
&self.ty().type_path_table()
}
/// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
///
/// [`TypeId`]: core::any::TypeId
/// [`TypePath`]: crate::type_path::TypePath
pub fn is<T: ::core::any::Any>(&self) -> bool {
self.ty().is::<T>()
}
};
}
use crate::generics::impl_generic_info_methods;
pub(crate) use impl_type_methods;
/// A container for compile-time info related to reflection-opaque types, including primitives.
///
/// This typically represents a type which cannot be broken down any further. This is often
/// due to technical reasons (or by definition), but it can also be a purposeful choice.
///
/// For example, [`i32`] cannot be broken down any further, so it is represented by an [`OpaqueInfo`].
/// And while [`String`] itself is a struct, its fields are private, so we don't really treat
/// it _as_ a struct. It therefore makes more sense to represent it as an [`OpaqueInfo`].
///
/// [`String`]: alloc::string::String
#[derive(Debug, Clone)]
pub struct OpaqueInfo {
ty: Type,
generics: Generics,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl OpaqueInfo {
pub fn new<T: Reflect + TypePath + ?Sized>() -> Self {
Self {
ty: Type::of::<T>(),
generics: Generics::new(),
#[cfg(feature = "documentation")]
docs: None,
}
}
/// Sets the docstring for this type.
#[cfg(feature = "documentation")]
pub fn with_docs(self, doc: Option<&'static str>) -> Self {
Self { docs: doc, ..self }
}
impl_type_methods!(ty);
/// The docstring of this dynamic type, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs
}
impl_generic_info_methods!(generics);
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
#[test]
fn should_return_error_on_invalid_cast() {
let info = <Vec<i32> as Typed>::type_info();
assert!(matches!(
info.as_struct(),
Err(TypeInfoError::KindMismatch {
expected: ReflectKind::Struct,
received: ReflectKind::List
})
));
}
}

View File

@@ -0,0 +1,52 @@
use crate::TypeInfo;
use alloc::vec::Vec;
use core::{
fmt::{Debug, Formatter},
slice::Iter,
};
/// Helper struct for managing a stack of [`TypeInfo`] instances.
///
/// This is useful for tracking the type hierarchy when serializing and deserializing types.
#[derive(Default, Clone)]
pub(crate) struct TypeInfoStack {
stack: Vec<&'static TypeInfo>,
}
impl TypeInfoStack {
/// Create a new empty [`TypeInfoStack`].
pub const fn new() -> Self {
Self { stack: Vec::new() }
}
/// Push a new [`TypeInfo`] onto the stack.
pub fn push(&mut self, type_info: &'static TypeInfo) {
self.stack.push(type_info);
}
/// Pop the last [`TypeInfo`] off the stack.
pub fn pop(&mut self) {
self.stack.pop();
}
/// Get an iterator over the stack in the order they were pushed.
pub fn iter(&self) -> Iter<&'static TypeInfo> {
self.stack.iter()
}
}
impl Debug for TypeInfoStack {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut iter = self.iter();
if let Some(first) = iter.next() {
write!(f, "`{}`", first.type_path())?;
}
for info in iter {
write!(f, " -> `{}`", info.type_path())?;
}
Ok(())
}
}

243
vendor/bevy_reflect/src/type_path.rs vendored Normal file
View File

@@ -0,0 +1,243 @@
use core::fmt;
/// A static accessor to type paths and names.
///
/// The engine uses this trait over [`core::any::type_name`] for stability and flexibility.
///
/// This trait is automatically implemented by the `#[derive(Reflect)]` macro
/// and allows type path information to be processed without an instance of that type.
///
/// Implementors may have difficulty in generating references with static
/// lifetimes. Luckily, this crate comes with some [utility] structs, to make generating these
/// statics much simpler.
///
/// # Stability
///
/// Certain parts of the engine, e.g. [(de)serialization], rely on type paths as identifiers
/// for matching dynamic values to concrete types.
///
/// Using [`core::any::type_name`], a scene containing `my_crate::foo::MyComponent` would break,
/// failing to deserialize if the component was moved from the `foo` module to the `bar` module,
/// becoming `my_crate::bar::MyComponent`.
/// This trait, through attributes when deriving itself or [`Reflect`], can ensure breaking changes are avoidable.
///
/// The only external factor we rely on for stability when deriving is the [`module_path!`] macro,
/// only if the derive does not provide a `#[type_path = "..."]` attribute.
///
/// # Anonymity
///
/// Some methods on this trait return `Option<&'static str>` over `&'static str`
/// because not all types define all parts of a type path, for example the array type `[T; N]`.
///
/// Such types are 'anonymous' in that they have only a defined [`type_path`] and [`short_type_path`]
/// and the methods [`crate_name`], [`module_path`] and [`type_ident`] all return `None`.
///
/// Primitives are treated like anonymous types, except they also have a defined [`type_ident`].
///
/// # Example
///
/// ```
/// use bevy_reflect::TypePath;
///
/// // This type path will not change with compiler versions or recompiles,
/// // although it will not be the same if the definition is moved.
/// #[derive(TypePath)]
/// struct NonStableTypePath;
///
/// // This type path will never change, even if the definition is moved.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo"]
/// struct StableTypePath;
///
/// // Type paths can have any number of path segments.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo::bar::baz"]
/// struct DeeplyNestedStableTypePath;
///
/// // Including just a crate name!
/// #[derive(TypePath)]
/// #[type_path = "my_crate"]
/// struct ShallowStableTypePath;
///
/// // We can also rename the identifier/name of types.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo"]
/// #[type_name = "RenamedStableTypePath"]
/// struct NamedStableTypePath;
///
/// // Generics are also supported.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo"]
/// struct StableGenericTypePath<T, const N: usize>([T; N]);
/// ```
///
/// [utility]: crate::utility
/// [(de)serialization]: crate::serde::ReflectDeserializer
/// [`Reflect`]: crate::Reflect
/// [`type_path`]: TypePath::type_path
/// [`short_type_path`]: TypePath::short_type_path
/// [`crate_name`]: TypePath::crate_name
/// [`module_path`]: TypePath::module_path
/// [`type_ident`]: TypePath::type_ident
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `TypePath` so cannot provide static type path information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]` or `#[derive(TypePath)]`"
)]
pub trait TypePath: 'static {
/// Returns the fully qualified path of the underlying type.
///
/// Generic parameter types are also fully expanded.
///
/// For `Option<Vec<usize>>`, this is `"std::option::Option<std::vec::Vec<usize>>"`.
fn type_path() -> &'static str;
/// Returns a short, pretty-print enabled path to the type.
///
/// Generic parameter types are also shortened.
///
/// For `Option<Vec<usize>>`, this is `"Option<Vec<usize>>"`.
fn short_type_path() -> &'static str;
/// Returns the name of the type, or [`None`] if it is [anonymous].
///
/// Primitive types will return [`Some`].
///
/// For `Option<Vec<usize>>`, this is `"Option"`.
///
/// [anonymous]: TypePath#anonymity
fn type_ident() -> Option<&'static str> {
None
}
/// Returns the name of the crate the type is in, or [`None`] if it is [anonymous].
///
/// For `Option<Vec<usize>>`, this is `"core"`.
///
/// [anonymous]: TypePath#anonymity
fn crate_name() -> Option<&'static str> {
None
}
/// Returns the path to the module the type is in, or [`None`] if it is [anonymous].
///
/// For `Option<Vec<usize>>`, this is `"std::option"`.
///
/// [anonymous]: TypePath#anonymity
fn module_path() -> Option<&'static str> {
None
}
}
/// Dynamic dispatch for [`TypePath`].
///
/// Since this is a supertrait of [`Reflect`] its methods can be called on a `dyn Reflect`.
///
/// [`Reflect`]: crate::Reflect
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `TypePath` so cannot provide dynamic type path information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]` or `#[derive(TypePath)]`"
)]
pub trait DynamicTypePath {
/// See [`TypePath::type_path`].
fn reflect_type_path(&self) -> &str;
/// See [`TypePath::short_type_path`].
fn reflect_short_type_path(&self) -> &str;
/// See [`TypePath::type_ident`].
fn reflect_type_ident(&self) -> Option<&str>;
/// See [`TypePath::crate_name`].
fn reflect_crate_name(&self) -> Option<&str>;
/// See [`TypePath::module_path`].
fn reflect_module_path(&self) -> Option<&str>;
}
impl<T: TypePath> DynamicTypePath for T {
#[inline]
fn reflect_type_path(&self) -> &str {
Self::type_path()
}
#[inline]
fn reflect_short_type_path(&self) -> &str {
Self::short_type_path()
}
#[inline]
fn reflect_type_ident(&self) -> Option<&str> {
Self::type_ident()
}
#[inline]
fn reflect_crate_name(&self) -> Option<&str> {
Self::crate_name()
}
#[inline]
fn reflect_module_path(&self) -> Option<&str> {
Self::module_path()
}
}
/// Provides dynamic access to all methods on [`TypePath`].
#[derive(Clone, Copy)]
pub struct TypePathTable {
// Cache the type path as it is likely the only one that will be used.
type_path: &'static str,
short_type_path: fn() -> &'static str,
type_ident: fn() -> Option<&'static str>,
crate_name: fn() -> Option<&'static str>,
module_path: fn() -> Option<&'static str>,
}
impl fmt::Debug for TypePathTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypePathVtable")
.field("type_path", &self.type_path)
.field("short_type_path", &(self.short_type_path)())
.field("type_ident", &(self.type_ident)())
.field("crate_name", &(self.crate_name)())
.field("module_path", &(self.module_path)())
.finish()
}
}
impl TypePathTable {
/// Creates a new table from a type.
pub fn of<T: TypePath + ?Sized>() -> Self {
Self {
type_path: T::type_path(),
short_type_path: T::short_type_path,
type_ident: T::type_ident,
crate_name: T::crate_name,
module_path: T::module_path,
}
}
/// See [`TypePath::type_path`].
pub fn path(&self) -> &'static str {
self.type_path
}
/// See [`TypePath::short_type_path`].
pub fn short_path(&self) -> &'static str {
(self.short_type_path)()
}
/// See [`TypePath::type_ident`].
pub fn ident(&self) -> Option<&'static str> {
(self.type_ident)()
}
/// See [`TypePath::crate_name`].
pub fn crate_name(&self) -> Option<&'static str> {
(self.crate_name)()
}
/// See [`TypePath::module_path`].
pub fn module_path(&self) -> Option<&'static str> {
(self.module_path)()
}
}

988
vendor/bevy_reflect/src/type_registry.rs vendored Normal file
View File

@@ -0,0 +1,988 @@
use crate::{serde::Serializable, FromReflect, Reflect, TypeInfo, TypePath, Typed};
use alloc::{boxed::Box, string::String};
use bevy_platform::{
collections::{HashMap, HashSet},
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use bevy_ptr::{Ptr, PtrMut};
use bevy_utils::TypeIdMap;
use core::{
any::TypeId,
fmt::Debug,
ops::{Deref, DerefMut},
};
use downcast_rs::{impl_downcast, Downcast};
use serde::Deserialize;
/// A registry of [reflected] types.
///
/// This struct is used as the central store for type information.
/// [Registering] a type will generate a new [`TypeRegistration`] entry in this store
/// using a type's [`GetTypeRegistration`] implementation
/// (which is automatically implemented when using [`#[derive(Reflect)]`](derive@crate::Reflect)).
///
/// See the [crate-level documentation] for more information.
///
/// [reflected]: crate
/// [Registering]: TypeRegistry::register
/// [crate-level documentation]: crate
pub struct TypeRegistry {
registrations: TypeIdMap<TypeRegistration>,
short_path_to_id: HashMap<&'static str, TypeId>,
type_path_to_id: HashMap<&'static str, TypeId>,
ambiguous_names: HashSet<&'static str>,
}
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't
// need a TypeRegistry ref
/// A synchronized wrapper around a [`TypeRegistry`].
#[derive(Clone, Default)]
pub struct TypeRegistryArc {
pub internal: Arc<RwLock<TypeRegistry>>,
}
impl Debug for TypeRegistryArc {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.internal
.read()
.unwrap_or_else(PoisonError::into_inner)
.type_path_to_id
.keys()
.fmt(f)
}
}
/// A trait which allows a type to generate its [`TypeRegistration`]
/// for registration into the [`TypeRegistry`].
///
/// This trait is automatically implemented for items using [`#[derive(Reflect)]`](derive@crate::Reflect).
/// The macro also allows [`TypeData`] to be more easily registered.
///
/// If you need to use this trait as a generic bound along with other reflection traits,
/// for your convenience, consider using [`Reflectable`] instead.
///
/// See the [crate-level documentation] for more information on type registration.
///
/// [`Reflectable`]: crate::Reflectable
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `GetTypeRegistration` so cannot provide type registration information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetTypeRegistration: 'static {
/// Returns the default [`TypeRegistration`] for this type.
fn get_type_registration() -> TypeRegistration;
/// Registers other types needed by this type.
///
/// This method is called by [`TypeRegistry::register`] to register any other required types.
/// Often, this is done for fields of structs and enum variants to ensure all types are properly registered.
fn register_type_dependencies(_registry: &mut TypeRegistry) {}
}
impl Default for TypeRegistry {
fn default() -> Self {
Self::new()
}
}
impl TypeRegistry {
/// Create a type registry with *no* registered types.
pub fn empty() -> Self {
Self {
registrations: Default::default(),
short_path_to_id: Default::default(),
type_path_to_id: Default::default(),
ambiguous_names: Default::default(),
}
}
/// Create a type registry with default registrations for primitive types.
pub fn new() -> Self {
let mut registry = Self::empty();
registry.register::<bool>();
registry.register::<char>();
registry.register::<u8>();
registry.register::<u16>();
registry.register::<u32>();
registry.register::<u64>();
registry.register::<u128>();
registry.register::<usize>();
registry.register::<i8>();
registry.register::<i16>();
registry.register::<i32>();
registry.register::<i64>();
registry.register::<i128>();
registry.register::<isize>();
registry.register::<f32>();
registry.register::<f64>();
registry.register::<String>();
registry
}
/// Attempts to register the type `T` if it has not yet been registered already.
///
/// This will also recursively register any type dependencies as specified by [`GetTypeRegistration::register_type_dependencies`].
/// When deriving `Reflect`, this will generally be all the fields of the struct or enum variant.
/// As with any type registration, these type dependencies will not be registered more than once.
///
/// If the registration for type `T` already exists, it will not be registered again and neither will its type dependencies.
/// To register the type, overwriting any existing registration, use [register](Self::overwrite_registration) instead.
///
/// Additionally, this will add any reflect [type data](TypeData) as specified in the [`Reflect`] derive.
///
/// # Example
///
/// ```
/// # use core::any::TypeId;
/// # use bevy_reflect::{Reflect, TypeRegistry, std_traits::ReflectDefault};
/// #[derive(Reflect, Default)]
/// #[reflect(Default)]
/// struct Foo {
/// name: Option<String>,
/// value: i32
/// }
///
/// let mut type_registry = TypeRegistry::default();
///
/// type_registry.register::<Foo>();
///
/// // The main type
/// assert!(type_registry.contains(TypeId::of::<Foo>()));
///
/// // Its type dependencies
/// assert!(type_registry.contains(TypeId::of::<Option<String>>()));
/// assert!(type_registry.contains(TypeId::of::<i32>()));
///
/// // Its type data
/// assert!(type_registry.get_type_data::<ReflectDefault>(TypeId::of::<Foo>()).is_some());
/// ```
pub fn register<T>(&mut self)
where
T: GetTypeRegistration,
{
if self.register_internal(TypeId::of::<T>(), T::get_type_registration) {
T::register_type_dependencies(self);
}
}
/// Attempts to register the referenced type `T` if it has not yet been registered.
///
/// See [`register`] for more details.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{Reflect, TypeRegistry};
/// # use core::any::TypeId;
/// #
/// # let mut type_registry = TypeRegistry::default();
/// #
/// #[derive(Reflect)]
/// struct Foo {
/// bar: Bar,
/// }
///
/// #[derive(Reflect)]
/// struct Bar;
///
/// let foo = Foo { bar: Bar };
///
/// // Equivalent to `type_registry.register::<Foo>()`
/// type_registry.register_by_val(&foo);
///
/// assert!(type_registry.contains(TypeId::of::<Foo>()));
/// assert!(type_registry.contains(TypeId::of::<Bar>()));
/// ```
///
/// [`register`]: Self::register
pub fn register_by_val<T>(&mut self, _: &T)
where
T: GetTypeRegistration,
{
self.register::<T>();
}
/// Attempts to register the type described by `registration`.
///
/// If the registration for the type already exists, it will not be registered again.
///
/// To forcibly register the type, overwriting any existing registration, use the
/// [`overwrite_registration`](Self::overwrite_registration) method instead.
///
/// This method will _not_ register type dependencies.
/// Use [`register`](Self::register) to register a type with its dependencies.
///
/// Returns `true` if the registration was added and `false` if it already exists.
pub fn add_registration(&mut self, registration: TypeRegistration) -> bool {
let type_id = registration.type_id();
self.register_internal(type_id, || registration)
}
/// Registers the type described by `registration`.
///
/// If the registration for the type already exists, it will be overwritten.
///
/// To avoid overwriting existing registrations, it's recommended to use the
/// [`register`](Self::register) or [`add_registration`](Self::add_registration) methods instead.
///
/// This method will _not_ register type dependencies.
/// Use [`register`](Self::register) to register a type with its dependencies.
pub fn overwrite_registration(&mut self, registration: TypeRegistration) {
Self::update_registration_indices(
&registration,
&mut self.short_path_to_id,
&mut self.type_path_to_id,
&mut self.ambiguous_names,
);
self.registrations
.insert(registration.type_id(), registration);
}
/// Internal method to register a type with a given [`TypeId`] and [`TypeRegistration`].
///
/// By using this method, we are able to reduce the number of `TypeId` hashes and lookups needed
/// to register a type.
///
/// This method is internal to prevent users from accidentally registering a type with a `TypeId`
/// that does not match the type in the `TypeRegistration`.
fn register_internal(
&mut self,
type_id: TypeId,
get_registration: impl FnOnce() -> TypeRegistration,
) -> bool {
use bevy_platform::collections::hash_map::Entry;
match self.registrations.entry(type_id) {
Entry::Occupied(_) => false,
Entry::Vacant(entry) => {
let registration = get_registration();
Self::update_registration_indices(
&registration,
&mut self.short_path_to_id,
&mut self.type_path_to_id,
&mut self.ambiguous_names,
);
entry.insert(registration);
true
}
}
}
/// Internal method to register additional lookups for a given [`TypeRegistration`].
fn update_registration_indices(
registration: &TypeRegistration,
short_path_to_id: &mut HashMap<&'static str, TypeId>,
type_path_to_id: &mut HashMap<&'static str, TypeId>,
ambiguous_names: &mut HashSet<&'static str>,
) {
let short_name = registration.type_info().type_path_table().short_path();
if short_path_to_id.contains_key(short_name) || ambiguous_names.contains(short_name) {
// name is ambiguous. fall back to long names for all ambiguous types
short_path_to_id.remove(short_name);
ambiguous_names.insert(short_name);
} else {
short_path_to_id.insert(short_name, registration.type_id());
}
type_path_to_id.insert(registration.type_info().type_path(), registration.type_id());
}
/// Registers the type data `D` for type `T`.
///
/// Most of the time [`TypeRegistry::register`] can be used instead to register a type you derived [`Reflect`] for.
/// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive,
/// or where the type is generic and cannot register e.g. [`ReflectSerialize`] unconditionally without knowing the specific type parameters,
/// this method can be used to insert additional type data.
///
/// # Example
/// ```
/// use bevy_reflect::{TypeRegistry, ReflectSerialize, ReflectDeserialize};
///
/// let mut type_registry = TypeRegistry::default();
/// type_registry.register::<Option<String>>();
/// type_registry.register_type_data::<Option<String>, ReflectSerialize>();
/// type_registry.register_type_data::<Option<String>, ReflectDeserialize>();
/// ```
pub fn register_type_data<T: Reflect + TypePath, D: TypeData + FromType<T>>(&mut self) {
let data = self.get_mut(TypeId::of::<T>()).unwrap_or_else(|| {
panic!(
"attempted to call `TypeRegistry::register_type_data` for type `{T}` with data `{D}` without registering `{T}` first",
T = T::type_path(),
D = core::any::type_name::<D>(),
)
});
data.insert(D::from_type());
}
pub fn contains(&self, type_id: TypeId) -> bool {
self.registrations.contains_key(&type_id)
}
/// Returns a reference to the [`TypeRegistration`] of the type with the
/// given [`TypeId`].
///
/// If the specified type has not been registered, returns `None`.
#[inline]
pub fn get(&self, type_id: TypeId) -> Option<&TypeRegistration> {
self.registrations.get(&type_id)
}
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
/// the given [`TypeId`].
///
/// If the specified type has not been registered, returns `None`.
pub fn get_mut(&mut self, type_id: TypeId) -> Option<&mut TypeRegistration> {
self.registrations.get_mut(&type_id)
}
/// Returns a reference to the [`TypeRegistration`] of the type with the
/// given [type path].
///
/// If no type with the given path has been registered, returns `None`.
///
/// [type path]: TypePath::type_path
pub fn get_with_type_path(&self, type_path: &str) -> Option<&TypeRegistration> {
self.type_path_to_id
.get(type_path)
.and_then(|id| self.get(*id))
}
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
/// the given [type path].
///
/// If no type with the given type path has been registered, returns `None`.
///
/// [type path]: TypePath::type_path
pub fn get_with_type_path_mut(&mut self, type_path: &str) -> Option<&mut TypeRegistration> {
self.type_path_to_id
.get(type_path)
.cloned()
.and_then(move |id| self.get_mut(id))
}
/// Returns a reference to the [`TypeRegistration`] of the type with
/// the given [short type path].
///
/// If the short type path is ambiguous, or if no type with the given path
/// has been registered, returns `None`.
///
/// [short type path]: TypePath::short_type_path
pub fn get_with_short_type_path(&self, short_type_path: &str) -> Option<&TypeRegistration> {
self.short_path_to_id
.get(short_type_path)
.and_then(|id| self.registrations.get(id))
}
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
/// the given [short type path].
///
/// If the short type path is ambiguous, or if no type with the given path
/// has been registered, returns `None`.
///
/// [short type path]: TypePath::short_type_path
pub fn get_with_short_type_path_mut(
&mut self,
short_type_path: &str,
) -> Option<&mut TypeRegistration> {
self.short_path_to_id
.get(short_type_path)
.and_then(|id| self.registrations.get_mut(id))
}
/// Returns `true` if the given [short type path] is ambiguous, that is, it matches multiple registered types.
///
/// # Example
/// ```
/// # use bevy_reflect::TypeRegistry;
/// # mod foo {
/// # use bevy_reflect::Reflect;
/// # #[derive(Reflect)]
/// # pub struct MyType;
/// # }
/// # mod bar {
/// # use bevy_reflect::Reflect;
/// # #[derive(Reflect)]
/// # pub struct MyType;
/// # }
/// let mut type_registry = TypeRegistry::default();
/// type_registry.register::<foo::MyType>();
/// type_registry.register::<bar::MyType>();
/// assert_eq!(type_registry.is_ambiguous("MyType"), true);
/// ```
///
/// [short type path]: TypePath::short_type_path
pub fn is_ambiguous(&self, short_type_path: &str) -> bool {
self.ambiguous_names.contains(short_type_path)
}
/// Returns a reference to the [`TypeData`] of type `T` associated with the given [`TypeId`].
///
/// The returned value may be used to downcast [`Reflect`] trait objects to
/// trait objects of the trait used to generate `T`, provided that the
/// underlying reflected type has the proper `#[reflect(DoThing)]`
/// attribute.
///
/// If the specified type has not been registered, or if `T` is not present
/// in its type registration, returns `None`.
pub fn get_type_data<T: TypeData>(&self, type_id: TypeId) -> Option<&T> {
self.get(type_id)
.and_then(|registration| registration.data::<T>())
}
/// Returns a mutable reference to the [`TypeData`] of type `T` associated with the given [`TypeId`].
///
/// If the specified type has not been registered, or if `T` is not present
/// in its type registration, returns `None`.
pub fn get_type_data_mut<T: TypeData>(&mut self, type_id: TypeId) -> Option<&mut T> {
self.get_mut(type_id)
.and_then(|registration| registration.data_mut::<T>())
}
/// Returns the [`TypeInfo`] associated with the given [`TypeId`].
///
/// If the specified type has not been registered, returns `None`.
pub fn get_type_info(&self, type_id: TypeId) -> Option<&'static TypeInfo> {
self.get(type_id).map(TypeRegistration::type_info)
}
/// Returns an iterator over the [`TypeRegistration`]s of the registered
/// types.
pub fn iter(&self) -> impl Iterator<Item = &TypeRegistration> {
self.registrations.values()
}
/// Returns a mutable iterator over the [`TypeRegistration`]s of the registered
/// types.
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut TypeRegistration> {
self.registrations.values_mut()
}
/// Checks to see if the [`TypeData`] of type `T` is associated with each registered type,
/// returning a ([`TypeRegistration`], [`TypeData`]) iterator for all entries where data of that type was found.
pub fn iter_with_data<T: TypeData>(&self) -> impl Iterator<Item = (&TypeRegistration, &T)> {
self.registrations.values().filter_map(|item| {
let type_data = item.data::<T>();
type_data.map(|data| (item, data))
})
}
}
impl TypeRegistryArc {
/// Takes a read lock on the underlying [`TypeRegistry`].
pub fn read(&self) -> RwLockReadGuard<'_, TypeRegistry> {
self.internal.read().unwrap_or_else(PoisonError::into_inner)
}
/// Takes a write lock on the underlying [`TypeRegistry`].
pub fn write(&self) -> RwLockWriteGuard<'_, TypeRegistry> {
self.internal
.write()
.unwrap_or_else(PoisonError::into_inner)
}
}
/// Runtime storage for type metadata, registered into the [`TypeRegistry`].
///
/// An instance of `TypeRegistration` can be created using the [`TypeRegistration::of`] method,
/// but is more often automatically generated using [`#[derive(Reflect)]`](derive@crate::Reflect) which itself generates
/// an implementation of the [`GetTypeRegistration`] trait.
///
/// Along with the type's [`TypeInfo`],
/// this struct also contains a type's registered [`TypeData`].
///
/// See the [crate-level documentation] for more information on type registration.
///
/// # Example
///
/// ```
/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault, FromType};
/// let mut registration = TypeRegistration::of::<Option<String>>();
///
/// assert_eq!("core::option::Option<alloc::string::String>", registration.type_info().type_path());
/// assert_eq!("Option<String>", registration.type_info().type_path_table().short_path());
///
/// registration.insert::<ReflectDefault>(FromType::<Option<String>>::from_type());
/// assert!(registration.data::<ReflectDefault>().is_some())
/// ```
///
/// [crate-level documentation]: crate
pub struct TypeRegistration {
data: TypeIdMap<Box<dyn TypeData>>,
type_info: &'static TypeInfo,
}
impl Debug for TypeRegistration {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TypeRegistration")
.field("type_info", &self.type_info)
.finish()
}
}
impl TypeRegistration {
/// Creates type registration information for `T`.
pub fn of<T: Reflect + Typed + TypePath>() -> Self {
Self {
data: Default::default(),
type_info: T::type_info(),
}
}
/// Returns the [`TypeId`] of the type.
#[inline]
pub fn type_id(&self) -> TypeId {
self.type_info.type_id()
}
/// Returns a reference to the registration's [`TypeInfo`]
pub fn type_info(&self) -> &'static TypeInfo {
self.type_info
}
/// Inserts an instance of `T` into this registration's [type data].
///
/// If another instance of `T` was previously inserted, it is replaced.
///
/// [type data]: TypeData
pub fn insert<T: TypeData>(&mut self, data: T) {
self.data.insert(TypeId::of::<T>(), Box::new(data));
}
/// Returns a reference to the value of type `T` in this registration's
/// [type data].
///
/// Returns `None` if no such value exists.
///
/// For a dynamic version of this method, see [`data_by_id`].
///
/// [type data]: TypeData
/// [`data_by_id`]: Self::data_by_id
pub fn data<T: TypeData>(&self) -> Option<&T> {
self.data
.get(&TypeId::of::<T>())
.and_then(|value| value.downcast_ref())
}
/// Returns a reference to the value with the given [`TypeId`] in this registration's
/// [type data].
///
/// Returns `None` if no such value exists.
///
/// For a static version of this method, see [`data`].
///
/// [type data]: TypeData
/// [`data`]: Self::data
pub fn data_by_id(&self, type_id: TypeId) -> Option<&dyn TypeData> {
self.data.get(&type_id).map(Deref::deref)
}
/// Returns a mutable reference to the value of type `T` in this registration's
/// [type data].
///
/// Returns `None` if no such value exists.
///
/// For a dynamic version of this method, see [`data_mut_by_id`].
///
/// [type data]: TypeData
/// [`data_mut_by_id`]: Self::data_mut_by_id
pub fn data_mut<T: TypeData>(&mut self) -> Option<&mut T> {
self.data
.get_mut(&TypeId::of::<T>())
.and_then(|value| value.downcast_mut())
}
/// Returns a mutable reference to the value with the given [`TypeId`] in this registration's
/// [type data].
///
/// Returns `None` if no such value exists.
///
/// For a static version of this method, see [`data_mut`].
///
/// [type data]: TypeData
/// [`data_mut`]: Self::data_mut
pub fn data_mut_by_id(&mut self, type_id: TypeId) -> Option<&mut dyn TypeData> {
self.data.get_mut(&type_id).map(DerefMut::deref_mut)
}
/// Returns true if this registration contains the given [type data].
///
/// For a dynamic version of this method, see [`contains_by_id`].
///
/// [type data]: TypeData
/// [`contains_by_id`]: Self::contains_by_id
pub fn contains<T: TypeData>(&self) -> bool {
self.data.contains_key(&TypeId::of::<T>())
}
/// Returns true if this registration contains the given [type data] with [`TypeId`].
///
/// For a static version of this method, see [`contains`].
///
/// [type data]: TypeData
/// [`contains`]: Self::contains
pub fn contains_by_id(&self, type_id: TypeId) -> bool {
self.data.contains_key(&type_id)
}
/// The total count of [type data] in this registration.
///
/// [type data]: TypeData
pub fn len(&self) -> usize {
self.data.len()
}
/// Returns true if this registration has no [type data].
///
/// [type data]: TypeData
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
/// Returns an iterator over all [type data] in this registration.
///
/// The iterator yields a tuple of the [`TypeId`] and its corresponding type data.
///
/// [type data]: TypeData
pub fn iter(&self) -> impl ExactSizeIterator<Item = (TypeId, &dyn TypeData)> {
self.data.iter().map(|(id, data)| (*id, data.deref()))
}
/// Returns a mutable iterator over all [type data] in this registration.
///
/// The iterator yields a tuple of the [`TypeId`] and its corresponding type data.
///
/// [type data]: TypeData
pub fn iter_mut(&mut self) -> impl ExactSizeIterator<Item = (TypeId, &mut dyn TypeData)> {
self.data
.iter_mut()
.map(|(id, data)| (*id, data.deref_mut()))
}
}
impl Clone for TypeRegistration {
fn clone(&self) -> Self {
let mut data = TypeIdMap::default();
for (id, type_data) in &self.data {
data.insert(*id, (*type_data).clone_type_data());
}
TypeRegistration {
data,
type_info: self.type_info,
}
}
}
/// A trait used to type-erase type metadata.
///
/// Type data can be registered to the [`TypeRegistry`] and stored on a type's [`TypeRegistration`].
///
/// While type data is often generated using the [`#[reflect_trait]`](crate::reflect_trait) macro,
/// almost any type that implements [`Clone`] can be considered "type data".
/// This is because it has a blanket implementation over all `T` where `T: Clone + Send + Sync + 'static`.
///
/// See the [crate-level documentation] for more information on type data and type registration.
///
/// [crate-level documentation]: crate
pub trait TypeData: Downcast + Send + Sync {
fn clone_type_data(&self) -> Box<dyn TypeData>;
}
impl_downcast!(TypeData);
impl<T: 'static + Send + Sync> TypeData for T
where
T: Clone,
{
fn clone_type_data(&self) -> Box<dyn TypeData> {
Box::new(self.clone())
}
}
/// Trait used to generate [`TypeData`] for trait reflection.
///
/// This is used by the `#[derive(Reflect)]` macro to generate an implementation
/// of [`TypeData`] to pass to [`TypeRegistration::insert`].
pub trait FromType<T> {
fn from_type() -> Self;
}
/// A struct used to serialize reflected instances of a type.
///
/// A `ReflectSerialize` for type `T` can be obtained via
/// [`FromType::from_type`].
#[derive(Clone)]
pub struct ReflectSerialize {
get_serializable: fn(value: &dyn Reflect) -> Serializable,
}
impl<T: TypePath + FromReflect + erased_serde::Serialize> FromType<T> for ReflectSerialize {
fn from_type() -> Self {
ReflectSerialize {
get_serializable: |value| {
value
.downcast_ref::<T>()
.map(|value| Serializable::Borrowed(value))
.or_else(|| T::from_reflect(value.as_partial_reflect()).map(|value| Serializable::Owned(Box::new(value))))
.unwrap_or_else(|| {
panic!(
"FromReflect::from_reflect failed when called on type `{}` with this value: {value:?}",
T::type_path(),
);
})
},
}
}
}
impl ReflectSerialize {
/// Turn the value into a serializable representation
pub fn get_serializable<'a>(&self, value: &'a dyn Reflect) -> Serializable<'a> {
(self.get_serializable)(value)
}
}
/// A struct used to deserialize reflected instances of a type.
///
/// A `ReflectDeserialize` for type `T` can be obtained via
/// [`FromType::from_type`].
#[derive(Clone)]
pub struct ReflectDeserialize {
pub func: fn(
deserializer: &mut dyn erased_serde::Deserializer,
) -> Result<Box<dyn Reflect>, erased_serde::Error>,
}
impl ReflectDeserialize {
/// Deserializes a reflected value.
///
/// The underlying type of the reflected value, and thus the expected
/// structure of the serialized data, is determined by the type used to
/// construct this `ReflectDeserialize` value.
pub fn deserialize<'de, D>(&self, deserializer: D) -> Result<Box<dyn Reflect>, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut erased = <dyn erased_serde::Deserializer>::erase(deserializer);
(self.func)(&mut erased)
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
}
}
impl<T: for<'a> Deserialize<'a> + Reflect> FromType<T> for ReflectDeserialize {
fn from_type() -> Self {
ReflectDeserialize {
func: |deserializer| Ok(Box::new(T::deserialize(deserializer)?)),
}
}
}
/// [`Reflect`] values are commonly used in situations where the actual types of values
/// are not known at runtime. In such situations you might have access to a `*const ()` pointer
/// that you know implements [`Reflect`], but have no way of turning it into a `&dyn Reflect`.
///
/// This is where [`ReflectFromPtr`] comes in, when creating a [`ReflectFromPtr`] for a given type `T: Reflect`.
/// Internally, this saves a concrete function `*const T -> const dyn Reflect` which lets you create a trait object of [`Reflect`]
/// from a pointer.
///
/// # Example
/// ```
/// use bevy_reflect::{TypeRegistry, Reflect, ReflectFromPtr};
/// use bevy_ptr::Ptr;
/// use core::ptr::NonNull;
///
/// #[derive(Reflect)]
/// struct Reflected(String);
///
/// let mut type_registry = TypeRegistry::default();
/// type_registry.register::<Reflected>();
///
/// let mut value = Reflected("Hello world!".to_string());
/// let value = Ptr::from(&value);
///
/// let reflect_data = type_registry.get(core::any::TypeId::of::<Reflected>()).unwrap();
/// let reflect_from_ptr = reflect_data.data::<ReflectFromPtr>().unwrap();
/// // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for
/// let value = unsafe { reflect_from_ptr.as_reflect(value) };
///
/// assert_eq!(value.downcast_ref::<Reflected>().unwrap().0, "Hello world!");
/// ```
#[derive(Clone)]
pub struct ReflectFromPtr {
type_id: TypeId,
from_ptr: unsafe fn(Ptr) -> &dyn Reflect,
from_ptr_mut: unsafe fn(PtrMut) -> &mut dyn Reflect,
}
#[expect(
unsafe_code,
reason = "We must interact with pointers here, which are inherently unsafe."
)]
impl ReflectFromPtr {
/// Returns the [`TypeId`] that the [`ReflectFromPtr`] was constructed for.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Convert `Ptr` into `&dyn Reflect`.
///
/// # Safety
///
/// `val` must be a pointer to value of the type that the [`ReflectFromPtr`] was constructed for.
/// This can be verified by checking that the type id returned by [`ReflectFromPtr::type_id`] is the expected one.
pub unsafe fn as_reflect<'a>(&self, val: Ptr<'a>) -> &'a dyn Reflect {
// SAFETY: contract uphold by the caller.
unsafe { (self.from_ptr)(val) }
}
/// Convert `PtrMut` into `&mut dyn Reflect`.
///
/// # Safety
///
/// `val` must be a pointer to a value of the type that the [`ReflectFromPtr`] was constructed for
/// This can be verified by checking that the type id returned by [`ReflectFromPtr::type_id`] is the expected one.
pub unsafe fn as_reflect_mut<'a>(&self, val: PtrMut<'a>) -> &'a mut dyn Reflect {
// SAFETY: contract uphold by the caller.
unsafe { (self.from_ptr_mut)(val) }
}
/// Get a function pointer to turn a `Ptr` into `&dyn Reflect` for
/// the type this [`ReflectFromPtr`] was constructed for.
///
/// # Safety
///
/// When calling the unsafe function returned by this method you must ensure that:
/// - The input `Ptr` points to the `Reflect` type this `ReflectFromPtr`
/// was constructed for.
pub fn from_ptr(&self) -> unsafe fn(Ptr) -> &dyn Reflect {
self.from_ptr
}
/// Get a function pointer to turn a `PtrMut` into `&mut dyn Reflect` for
/// the type this [`ReflectFromPtr`] was constructed for.
///
/// # Safety
///
/// When calling the unsafe function returned by this method you must ensure that:
/// - The input `PtrMut` points to the `Reflect` type this `ReflectFromPtr`
/// was constructed for.
pub fn from_ptr_mut(&self) -> unsafe fn(PtrMut) -> &mut dyn Reflect {
self.from_ptr_mut
}
}
#[expect(
unsafe_code,
reason = "We must interact with pointers here, which are inherently unsafe."
)]
impl<T: Reflect> FromType<T> for ReflectFromPtr {
fn from_type() -> Self {
ReflectFromPtr {
type_id: TypeId::of::<T>(),
from_ptr: |ptr| {
// SAFETY: `from_ptr_mut` is either called in `ReflectFromPtr::as_reflect`
// or returned by `ReflectFromPtr::from_ptr`, both lay out the invariants
// required by `deref`
unsafe { ptr.deref::<T>() as &dyn Reflect }
},
from_ptr_mut: |ptr| {
// SAFETY: same as above, but for `as_reflect_mut`, `from_ptr_mut` and `deref_mut`.
unsafe { ptr.deref_mut::<T>() as &mut dyn Reflect }
},
}
}
}
#[cfg(test)]
#[expect(
unsafe_code,
reason = "We must interact with pointers here, which are inherently unsafe."
)]
mod test {
use super::*;
#[test]
fn test_reflect_from_ptr() {
#[derive(Reflect)]
struct Foo {
a: f32,
}
let foo_registration = <Foo as GetTypeRegistration>::get_type_registration();
let reflect_from_ptr = foo_registration.data::<ReflectFromPtr>().unwrap();
// not required in this situation because we no nobody messed with the TypeRegistry,
// but in the general case somebody could have replaced the ReflectFromPtr with an
// instance for another type, so then we'd need to check that the type is the expected one
assert_eq!(reflect_from_ptr.type_id(), TypeId::of::<Foo>());
let mut value = Foo { a: 1.0 };
{
let value = PtrMut::from(&mut value);
// SAFETY: reflect_from_ptr was constructed for the correct type
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_mut(value) };
match dyn_reflect.reflect_mut() {
bevy_reflect::ReflectMut::Struct(strukt) => {
strukt.field_mut("a").unwrap().apply(&2.0f32);
}
_ => panic!("invalid reflection"),
}
}
{
// SAFETY: reflect_from_ptr was constructed for the correct type
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect(Ptr::from(&value)) };
match dyn_reflect.reflect_ref() {
bevy_reflect::ReflectRef::Struct(strukt) => {
let a = strukt
.field("a")
.unwrap()
.try_downcast_ref::<f32>()
.unwrap();
assert_eq!(*a, 2.0);
}
_ => panic!("invalid reflection"),
}
}
}
#[test]
fn type_data_iter() {
#[derive(Reflect)]
struct Foo;
#[derive(Clone)]
struct DataA(i32);
let mut registration = TypeRegistration::of::<Foo>();
registration.insert(DataA(123));
let mut iter = registration.iter();
let (id, data) = iter.next().unwrap();
assert_eq!(id, TypeId::of::<DataA>());
assert_eq!(data.downcast_ref::<DataA>().unwrap().0, 123);
assert!(iter.next().is_none());
}
#[test]
fn type_data_iter_mut() {
#[derive(Reflect)]
struct Foo;
#[derive(Clone)]
struct DataA(i32);
let mut registration = TypeRegistration::of::<Foo>();
registration.insert(DataA(123));
{
let mut iter = registration.iter_mut();
let (_, data) = iter.next().unwrap();
data.downcast_mut::<DataA>().unwrap().0 = 456;
assert!(iter.next().is_none());
}
let data = registration.data::<DataA>().unwrap();
assert_eq!(data.0, 456);
}
}

307
vendor/bevy_reflect/src/utility.rs vendored Normal file
View File

@@ -0,0 +1,307 @@
//! Helpers for working with Bevy reflection.
use crate::TypeInfo;
use alloc::boxed::Box;
use bevy_platform::{
hash::{DefaultHasher, FixedHasher, NoOpHash},
sync::{OnceLock, PoisonError, RwLock},
};
use bevy_utils::TypeIdMap;
use core::{
any::{Any, TypeId},
hash::BuildHasher,
};
/// A type that can be stored in a ([`Non`])[`GenericTypeCell`].
///
/// [`Non`]: NonGenericTypeCell
pub trait TypedProperty: sealed::Sealed {
type Stored: 'static;
}
/// Used to store a [`String`] in a [`GenericTypePathCell`] as part of a [`TypePath`] implementation.
///
/// [`TypePath`]: crate::TypePath
/// [`String`]: alloc::string::String
pub struct TypePathComponent;
mod sealed {
use super::{TypeInfo, TypePathComponent, TypedProperty};
use alloc::string::String;
pub trait Sealed {}
impl Sealed for TypeInfo {}
impl Sealed for TypePathComponent {}
impl TypedProperty for TypeInfo {
type Stored = Self;
}
impl TypedProperty for TypePathComponent {
type Stored = String;
}
}
/// A container for [`TypeInfo`] over non-generic types, allowing instances to be stored statically.
///
/// This is specifically meant for use with _non_-generic types. If your type _is_ generic,
/// then use [`GenericTypeCell`] instead. Otherwise, it will not take into account all
/// monomorphizations of your type.
///
/// Non-generic [`TypePath`]s should be trivially generated with string literals and [`concat!`].
///
/// ## Example
///
/// ```
/// # use core::any::Any;
/// # use bevy_reflect::{DynamicTypePath, NamedField, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, Typed, TypeInfo, TypePath, ApplyError};
/// use bevy_reflect::utility::NonGenericTypeInfoCell;
///
/// struct Foo {
/// bar: i32
/// }
///
/// impl Typed for Foo {
/// fn type_info() -> &'static TypeInfo {
/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
/// CELL.get_or_set(|| {
/// let fields = [NamedField::new::<i32>("bar")];
/// let info = StructInfo::new::<Self>(&fields);
/// TypeInfo::Struct(info)
/// })
/// }
/// }
/// # impl TypePath for Foo {
/// # fn type_path() -> &'static str { todo!() }
/// # fn short_type_path() -> &'static str { todo!() }
/// # }
/// # impl PartialReflect for Foo {
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> { todo!() }
/// # fn as_partial_reflect(&self) -> &dyn PartialReflect { todo!() }
/// # fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { todo!() }
/// # fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> { todo!() }
/// # fn try_as_reflect(&self) -> Option<&dyn Reflect> { todo!() }
/// # fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { todo!() }
/// # fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { todo!() }
/// # fn reflect_ref(&self) -> ReflectRef { todo!() }
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
/// # }
/// # impl Reflect for Foo {
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # }
/// ```
///
/// [`TypePath`]: crate::TypePath
pub struct NonGenericTypeCell<T: TypedProperty>(OnceLock<T::Stored>);
/// See [`NonGenericTypeCell`].
pub type NonGenericTypeInfoCell = NonGenericTypeCell<TypeInfo>;
impl<T: TypedProperty> NonGenericTypeCell<T> {
/// Initialize a [`NonGenericTypeCell`] for non-generic types.
pub const fn new() -> Self {
Self(OnceLock::new())
}
/// Returns a reference to the [`TypedProperty`] stored in the cell.
///
/// If there is no entry found, a new one will be generated from the given function.
pub fn get_or_set<F>(&self, f: F) -> &T::Stored
where
F: FnOnce() -> T::Stored,
{
self.0.get_or_init(f)
}
}
impl<T: TypedProperty> Default for NonGenericTypeCell<T> {
fn default() -> Self {
Self::new()
}
}
/// A container for [`TypedProperty`] over generic types, allowing instances to be stored statically.
///
/// This is specifically meant for use with generic types. If your type isn't generic,
/// then use [`NonGenericTypeCell`] instead as it should be much more performant.
///
/// `#[derive(TypePath)]` and [`impl_type_path`] should always be used over [`GenericTypePathCell`]
/// where possible.
///
/// ## Examples
///
/// Implementing [`TypeInfo`] with generics.
///
/// ```
/// # use core::any::Any;
/// # use bevy_reflect::{DynamicTypePath, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TupleStructInfo, Typed, TypeInfo, TypePath, UnnamedField, ApplyError, Generics, TypeParamInfo};
/// use bevy_reflect::utility::GenericTypeInfoCell;
///
/// struct Foo<T>(T);
///
/// impl<T: Reflect + Typed + TypePath> Typed for Foo<T> {
/// fn type_info() -> &'static TypeInfo {
/// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
/// CELL.get_or_insert::<Self, _>(|| {
/// let fields = [UnnamedField::new::<T>(0)];
/// let info = TupleStructInfo::new::<Self>(&fields)
/// .with_generics(Generics::from_iter([TypeParamInfo::new::<T>("T")]));
/// TypeInfo::TupleStruct(info)
/// })
/// }
/// }
/// # impl<T: TypePath> TypePath for Foo<T> {
/// # fn type_path() -> &'static str { todo!() }
/// # fn short_type_path() -> &'static str { todo!() }
/// # }
/// # impl<T: PartialReflect + TypePath> PartialReflect for Foo<T> {
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> { todo!() }
/// # fn as_partial_reflect(&self) -> &dyn PartialReflect { todo!() }
/// # fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { todo!() }
/// # fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> { todo!() }
/// # fn try_as_reflect(&self) -> Option<&dyn Reflect> { todo!() }
/// # fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { todo!() }
/// # fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { todo!() }
/// # fn reflect_ref(&self) -> ReflectRef { todo!() }
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
/// # }
/// # impl<T: Reflect + Typed + TypePath> Reflect for Foo<T> {
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # }
/// ```
///
/// Implementing [`TypePath`] with generics.
///
/// ```
/// # use core::any::Any;
/// # use bevy_reflect::TypePath;
/// use bevy_reflect::utility::GenericTypePathCell;
///
/// struct Foo<T>(T);
///
/// impl<T: TypePath> TypePath for Foo<T> {
/// fn type_path() -> &'static str {
/// static CELL: GenericTypePathCell = GenericTypePathCell::new();
/// CELL.get_or_insert::<Self, _>(|| format!("my_crate::foo::Foo<{}>", T::type_path()))
/// }
///
/// fn short_type_path() -> &'static str {
/// static CELL: GenericTypePathCell = GenericTypePathCell::new();
/// CELL.get_or_insert::<Self, _>(|| format!("Foo<{}>", T::short_type_path()))
/// }
///
/// fn type_ident() -> Option<&'static str> {
/// Some("Foo")
/// }
///
/// fn module_path() -> Option<&'static str> {
/// Some("my_crate::foo")
/// }
///
/// fn crate_name() -> Option<&'static str> {
/// Some("my_crate")
/// }
/// }
/// ```
/// [`impl_type_path`]: crate::impl_type_path
/// [`TypePath`]: crate::TypePath
pub struct GenericTypeCell<T: TypedProperty>(RwLock<TypeIdMap<&'static T::Stored>>);
/// See [`GenericTypeCell`].
pub type GenericTypeInfoCell = GenericTypeCell<TypeInfo>;
/// See [`GenericTypeCell`].
pub type GenericTypePathCell = GenericTypeCell<TypePathComponent>;
impl<T: TypedProperty> GenericTypeCell<T> {
/// Initialize a [`GenericTypeCell`] for generic types.
pub const fn new() -> Self {
Self(RwLock::new(TypeIdMap::with_hasher(NoOpHash)))
}
/// Returns a reference to the [`TypedProperty`] stored in the cell.
///
/// This method will then return the correct [`TypedProperty`] reference for the given type `T`.
/// If there is no entry found, a new one will be generated from the given function.
pub fn get_or_insert<G, F>(&self, f: F) -> &T::Stored
where
G: Any + ?Sized,
F: FnOnce() -> T::Stored,
{
self.get_or_insert_by_type_id(TypeId::of::<G>(), f)
}
/// Returns a reference to the [`TypedProperty`] stored in the cell, if any.
///
/// This method will then return the correct [`TypedProperty`] reference for the given type `T`.
fn get_by_type_id(&self, type_id: TypeId) -> Option<&T::Stored> {
self.0
.read()
.unwrap_or_else(PoisonError::into_inner)
.get(&type_id)
.copied()
}
/// Returns a reference to the [`TypedProperty`] stored in the cell.
///
/// This method will then return the correct [`TypedProperty`] reference for the given type `T`.
/// If there is no entry found, a new one will be generated from the given function.
fn get_or_insert_by_type_id<F>(&self, type_id: TypeId, f: F) -> &T::Stored
where
F: FnOnce() -> T::Stored,
{
match self.get_by_type_id(type_id) {
Some(info) => info,
None => self.insert_by_type_id(type_id, f()),
}
}
fn insert_by_type_id(&self, type_id: TypeId, value: T::Stored) -> &T::Stored {
let mut write_lock = self.0.write().unwrap_or_else(PoisonError::into_inner);
write_lock
.entry(type_id)
.insert({
// We leak here in order to obtain a `&'static` reference.
// Otherwise, we won't be able to return a reference due to the `RwLock`.
// This should be okay, though, since we expect it to remain statically
// available over the course of the application.
Box::leak(Box::new(value))
})
.get()
}
}
impl<T: TypedProperty> Default for GenericTypeCell<T> {
fn default() -> Self {
Self::new()
}
}
/// Deterministic fixed state hasher to be used by implementors of [`Reflect::reflect_hash`].
///
/// Hashes should be deterministic across processes so hashes can be used as
/// checksums for saved scenes, rollback snapshots etc. This function returns
/// such a hasher.
///
/// [`Reflect::reflect_hash`]: crate::Reflect
#[inline]
pub fn reflect_hasher() -> DefaultHasher {
FixedHasher.build_hasher()
}