bevy_reflect: Add ReflectRef/ReflectMut/ReflectOwned convenience casting methods (#15235)
# Objective #13320 added convenience methods for casting a `TypeInfo` into its respective variant: ```rust let info: &TypeInfo = <Vec<i32> as Typed>::type_info(); // We know `info` contains a `ListInfo`, so we can simply cast it: let list_info: &ListInfo = info.as_list().unwrap(); ``` This is especially helpful when you have already verified a type is a certain kind via `ReflectRef`, `ReflectMut`, `ReflectOwned`, or `ReflectKind`. As mentioned in that PR, though, it would be useful to add similar convenience methods to those types as well. ## Solution Added convenience casting methods to `ReflectRef`, `ReflectMut`, and `ReflectOwned`. With these methods, I was able to reduce our nesting in certain places throughout the crate. Additionally, I took this opportunity to move these types (and `ReflectKind`) to their own module to help clean up the `reflect` module. ## Testing You can test locally by running: ``` cargo test --package bevy_reflect --all-features ``` --- ## Showcase Convenience methods for casting `ReflectRef`, `ReflectMut`, and `ReflectOwned` into their respective variants has been added! This allows you to write cleaner code if you already know the kind of your reflected data: ```rust // BEFORE let ReflectRef::List(list) = list.reflect_ref() else { panic!("expected list"); }; // AFTER let list = list.reflect_ref().as_list().unwrap(); ``` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
This commit is contained in:
parent
f78856b3bd
commit
4d0961cc8a
@ -249,7 +249,7 @@ mod tests {
|
|||||||
use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset, UntypedHandle};
|
use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset, UntypedHandle};
|
||||||
use bevy_app::App;
|
use bevy_app::App;
|
||||||
use bevy_ecs::reflect::AppTypeRegistry;
|
use bevy_ecs::reflect::AppTypeRegistry;
|
||||||
use bevy_reflect::{Reflect, ReflectMut};
|
use bevy_reflect::Reflect;
|
||||||
|
|
||||||
#[derive(Asset, Reflect)]
|
#[derive(Asset, Reflect)]
|
||||||
struct AssetType {
|
struct AssetType {
|
||||||
@ -278,13 +278,13 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let handle = reflect_asset.add(app.world_mut(), &value);
|
let handle = reflect_asset.add(app.world_mut(), &value);
|
||||||
let ReflectMut::Struct(strukt) = reflect_asset
|
// struct is a reserved keyword, so we can't use it here
|
||||||
|
let strukt = reflect_asset
|
||||||
.get_mut(app.world_mut(), handle)
|
.get_mut(app.world_mut(), handle)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.reflect_mut()
|
.reflect_mut()
|
||||||
else {
|
.as_struct()
|
||||||
unreachable!();
|
.unwrap();
|
||||||
};
|
|
||||||
strukt
|
strukt
|
||||||
.field_mut("field")
|
.field_mut("field")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@ -436,23 +436,20 @@ pub fn array_try_apply<A: Array>(
|
|||||||
array: &mut A,
|
array: &mut A,
|
||||||
reflect: &dyn PartialReflect,
|
reflect: &dyn PartialReflect,
|
||||||
) -> Result<(), ApplyError> {
|
) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
|
let reflect_array = reflect.reflect_ref().as_array()?;
|
||||||
if array.len() != reflect_array.len() {
|
|
||||||
return Err(ApplyError::DifferentSize {
|
if array.len() != reflect_array.len() {
|
||||||
from_size: reflect_array.len(),
|
return Err(ApplyError::DifferentSize {
|
||||||
to_size: array.len(),
|
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)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: reflect.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::Array,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i, value) in reflect_array.iter().enumerate() {
|
||||||
|
let v = array.get_mut(i).unwrap();
|
||||||
|
v.try_apply(value)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +504,7 @@ pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> std::fmt::Re
|
|||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{Reflect, ReflectRef};
|
use crate::Reflect;
|
||||||
#[test]
|
#[test]
|
||||||
fn next_index_increment() {
|
fn next_index_increment() {
|
||||||
const SIZE: usize = if cfg!(debug_assertions) {
|
const SIZE: usize = if cfg!(debug_assertions) {
|
||||||
@ -519,9 +516,7 @@ mod tests {
|
|||||||
|
|
||||||
let b = Box::new([(); SIZE]).into_reflect();
|
let b = Box::new([(); SIZE]).into_reflect();
|
||||||
|
|
||||||
let ReflectRef::Array(array) = b.reflect_ref() else {
|
let array = b.reflect_ref().as_array().unwrap();
|
||||||
panic!("Not an array...");
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut iter = array.iter();
|
let mut iter = array.iter();
|
||||||
iter.index = SIZE - 1;
|
iter.index = SIZE - 1;
|
||||||
|
|||||||
@ -322,55 +322,50 @@ impl PartialReflect for DynamicEnum {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
|
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::Enum(value) = value.reflect_ref() {
|
let value = value.reflect_ref().as_enum()?;
|
||||||
if Enum::variant_name(self) == value.variant_name() {
|
|
||||||
// Same variant -> just update fields
|
if Enum::variant_name(self) == value.variant_name() {
|
||||||
match value.variant_type() {
|
// Same variant -> just update fields
|
||||||
VariantType::Struct => {
|
match value.variant_type() {
|
||||||
for field in value.iter_fields() {
|
VariantType::Struct => {
|
||||||
let name = field.name().unwrap();
|
for field in value.iter_fields() {
|
||||||
if let Some(v) = Enum::field_mut(self, name) {
|
let name = field.name().unwrap();
|
||||||
v.try_apply(field.value())?;
|
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 {
|
VariantType::Tuple => {
|
||||||
// New variant -> perform a switch
|
for (index, field) in value.iter_fields().enumerate() {
|
||||||
let dyn_variant = match value.variant_type() {
|
if let Some(v) = Enum::field_at_mut(self, index) {
|
||||||
VariantType::Unit => DynamicVariant::Unit,
|
v.try_apply(field.value())?;
|
||||||
VariantType::Tuple => {
|
|
||||||
let mut dyn_tuple = DynamicTuple::default();
|
|
||||||
for field in value.iter_fields() {
|
|
||||||
dyn_tuple.insert_boxed(field.value().clone_value());
|
|
||||||
}
|
}
|
||||||
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().clone_value());
|
|
||||||
}
|
|
||||||
DynamicVariant::Struct(dyn_struct)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.set_variant(value.variant_name(), dyn_variant);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ApplyError::MismatchedKinds {
|
// New variant -> perform a switch
|
||||||
from_kind: value.reflect_kind(),
|
let dyn_variant = match value.variant_type() {
|
||||||
to_kind: ReflectKind::Enum,
|
VariantType::Unit => DynamicVariant::Unit,
|
||||||
});
|
VariantType::Tuple => {
|
||||||
|
let mut dyn_tuple = DynamicTuple::default();
|
||||||
|
for field in value.iter_fields() {
|
||||||
|
dyn_tuple.insert_boxed(field.value().clone_value());
|
||||||
|
}
|
||||||
|
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().clone_value());
|
||||||
|
}
|
||||||
|
DynamicVariant::Struct(dyn_struct)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.set_variant(value.variant_name(), dyn_variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -194,15 +194,15 @@ where
|
|||||||
T::Item: FromReflect + MaybeTyped + TypePath,
|
T::Item: FromReflect + MaybeTyped + TypePath,
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
|
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() {
|
let mut new_list = Self::with_capacity(ref_list.len());
|
||||||
new_list.push(<T as SmallArray>::Item::from_reflect(field)?);
|
|
||||||
}
|
for field in ref_list.iter() {
|
||||||
Some(new_list)
|
new_list.push(<T as SmallArray>::Item::from_reflect(field)?);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(new_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -544,15 +544,15 @@ macro_rules! impl_reflect_for_veclike {
|
|||||||
|
|
||||||
impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration> FromReflect for $ty {
|
impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration> FromReflect for $ty {
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
|
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() {
|
let mut new_list = Self::with_capacity(ref_list.len());
|
||||||
$push(&mut new_list, T::from_reflect(field)?);
|
|
||||||
}
|
for field in ref_list.iter() {
|
||||||
Some(new_list)
|
$push(&mut new_list, T::from_reflect(field)?);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(new_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -792,17 +792,17 @@ macro_rules! impl_reflect_for_hashmap {
|
|||||||
S: TypePath + BuildHasher + Default + Send + Sync,
|
S: TypePath + BuildHasher + Default + Send + Sync,
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
|
let ref_map = reflect.reflect_ref().as_map().ok()?;
|
||||||
let mut new_map = Self::with_capacity_and_hasher(ref_map.len(), S::default());
|
|
||||||
for (key, value) in ref_map.iter() {
|
let mut new_map = Self::with_capacity_and_hasher(ref_map.len(), S::default());
|
||||||
let new_key = K::from_reflect(key)?;
|
|
||||||
let new_value = V::from_reflect(value)?;
|
for (key, value) in ref_map.iter() {
|
||||||
new_map.insert(new_key, new_value);
|
let new_key = K::from_reflect(key)?;
|
||||||
}
|
let new_value = V::from_reflect(value)?;
|
||||||
Some(new_map)
|
new_map.insert(new_key, new_value);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(new_map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1013,16 +1013,16 @@ macro_rules! impl_reflect_for_hashset {
|
|||||||
S: TypePath + BuildHasher + Default + Send + Sync,
|
S: TypePath + BuildHasher + Default + Send + Sync,
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::Set(ref_set) = reflect.reflect_ref() {
|
let ref_set = reflect.reflect_ref().as_set().ok()?;
|
||||||
let mut new_set = Self::with_capacity_and_hasher(ref_set.len(), S::default());
|
|
||||||
for value in ref_set.iter() {
|
let mut new_set = Self::with_capacity_and_hasher(ref_set.len(), S::default());
|
||||||
let new_value = V::from_reflect(value)?;
|
|
||||||
new_set.insert(new_value);
|
for value in ref_set.iter() {
|
||||||
}
|
let new_value = V::from_reflect(value)?;
|
||||||
Some(new_set)
|
new_set.insert(new_value);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(new_set)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1251,17 +1251,17 @@ where
|
|||||||
V: FromReflect + MaybeTyped + TypePath + GetTypeRegistration,
|
V: FromReflect + MaybeTyped + TypePath + GetTypeRegistration,
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
|
let ref_map = reflect.reflect_ref().as_map().ok()?;
|
||||||
let mut new_map = Self::new();
|
|
||||||
for (key, value) in ref_map.iter() {
|
let mut new_map = Self::new();
|
||||||
let new_key = K::from_reflect(key)?;
|
|
||||||
let new_value = V::from_reflect(value)?;
|
for (key, value) in ref_map.iter() {
|
||||||
new_map.insert(new_key, new_value);
|
let new_key = K::from_reflect(key)?;
|
||||||
}
|
let new_value = V::from_reflect(value)?;
|
||||||
Some(new_map)
|
new_map.insert(new_key, new_value);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(new_map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1422,15 +1422,15 @@ impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration, const N: usiz
|
|||||||
for [T; N]
|
for [T; N]
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::Array(ref_array) = reflect.reflect_ref() {
|
let ref_array = reflect.reflect_ref().as_array().ok()?;
|
||||||
let mut temp_vec = Vec::with_capacity(ref_array.len());
|
|
||||||
for field in ref_array.iter() {
|
let mut temp_vec = Vec::with_capacity(ref_array.len());
|
||||||
temp_vec.push(T::from_reflect(field)?);
|
|
||||||
}
|
for field in ref_array.iter() {
|
||||||
temp_vec.try_into().ok()
|
temp_vec.push(T::from_reflect(field)?);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
temp_vec.try_into().ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1795,15 +1795,15 @@ impl<T: FromReflect + MaybeTyped + Clone + TypePath + GetTypeRegistration> FromR
|
|||||||
for Cow<'static, [T]>
|
for Cow<'static, [T]>
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
|
let ref_list = reflect.reflect_ref().as_list().ok()?;
|
||||||
let mut temp_vec = Vec::with_capacity(ref_list.len());
|
|
||||||
for field in ref_list.iter() {
|
let mut temp_vec = Vec::with_capacity(ref_list.len());
|
||||||
temp_vec.push(T::from_reflect(field)?);
|
|
||||||
}
|
for field in ref_list.iter() {
|
||||||
Some(temp_vec.into())
|
temp_vec.push(T::from_reflect(field)?);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(temp_vec.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
326
crates/bevy_reflect/src/kind.rs
Normal file
326
crates/bevy_reflect/src/kind.rs
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
#[cfg(feature = "functions")]
|
||||||
|
use crate::func::Function;
|
||||||
|
use crate::{Array, Enum, List, Map, PartialReflect, Set, Struct, Tuple, TupleStruct};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// A zero-sized 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,
|
||||||
|
/// A value-like type.
|
||||||
|
///
|
||||||
|
/// This most often represents a primitive or opaque type,
|
||||||
|
/// where it is not possible, difficult, or not useful to reflect the type further.
|
||||||
|
///
|
||||||
|
/// For example, `u32` and `String` are examples of value-like types.
|
||||||
|
/// Additionally, any type that derives [`Reflect`] with the `#[reflect_value]` attribute
|
||||||
|
/// will be considered a value-like type.
|
||||||
|
///
|
||||||
|
/// [`Reflect`]: crate::Reflect
|
||||||
|
Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ReflectKind {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::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::Value => f.pad("value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Value(_) => ReflectKind::Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Value(_) => Self::Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 : Value => $retval:ty) => {
|
||||||
|
#[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
|
||||||
|
#[doc = "\n\nReturns an error if `self` is not the [`Self::Value`] variant."]
|
||||||
|
pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
|
||||||
|
match self {
|
||||||
|
Self::Value(value) => Ok(value),
|
||||||
|
_ => Err(ReflectKindMismatchError {
|
||||||
|
expected: ReflectKind::Value,
|
||||||
|
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),
|
||||||
|
Value(&'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_value: Value => &'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),
|
||||||
|
Value(&'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_value: Value => &'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>),
|
||||||
|
Value(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: Value => Box<dyn PartialReflect>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[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::new();
|
||||||
|
|
||||||
|
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
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -156,7 +156,7 @@
|
|||||||
//! ```
|
//! ```
|
||||||
//! # use bevy_reflect::{PartialReflect, ReflectRef};
|
//! # use bevy_reflect::{PartialReflect, ReflectRef};
|
||||||
//! let my_tuple: Box<dyn PartialReflect> = Box::new((1, 2, 3));
|
//! let my_tuple: Box<dyn PartialReflect> = Box::new((1, 2, 3));
|
||||||
//! let ReflectRef::Tuple(my_tuple) = my_tuple.reflect_ref() else { unreachable!() };
|
//! let my_tuple = my_tuple.reflect_ref().as_tuple().unwrap();
|
||||||
//! assert_eq!(3, my_tuple.field_len());
|
//! assert_eq!(3, my_tuple.field_len());
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
@ -545,6 +545,7 @@ mod fields;
|
|||||||
mod from_reflect;
|
mod from_reflect;
|
||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
pub mod func;
|
pub mod func;
|
||||||
|
mod kind;
|
||||||
mod list;
|
mod list;
|
||||||
mod map;
|
mod map;
|
||||||
mod path;
|
mod path;
|
||||||
@ -603,6 +604,7 @@ pub use array::*;
|
|||||||
pub use enums::*;
|
pub use enums::*;
|
||||||
pub use fields::*;
|
pub use fields::*;
|
||||||
pub use from_reflect::*;
|
pub use from_reflect::*;
|
||||||
|
pub use kind::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
pub use path::*;
|
pub use path::*;
|
||||||
@ -773,11 +775,8 @@ mod tests {
|
|||||||
|
|
||||||
// nested retrieval
|
// nested retrieval
|
||||||
let c = foo.field("c").unwrap();
|
let c = foo.field("c").unwrap();
|
||||||
if let ReflectRef::Struct(value) = c.reflect_ref() {
|
let value = c.reflect_ref().as_struct().unwrap();
|
||||||
assert_eq!(*value.get_field::<u32>("x").unwrap(), 1);
|
assert_eq!(*value.get_field::<u32>("x").unwrap(), 1);
|
||||||
} else {
|
|
||||||
panic!("Expected a struct.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// patch Foo with a dynamic struct
|
// patch Foo with a dynamic struct
|
||||||
let mut dynamic_struct = DynamicStruct::default();
|
let mut dynamic_struct = DynamicStruct::default();
|
||||||
|
|||||||
@ -447,22 +447,18 @@ pub fn list_apply<L: List>(a: &mut L, b: &dyn PartialReflect) {
|
|||||||
/// applying elements to each other fails.
|
/// applying elements to each other fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::List(list_value) = b.reflect_ref() {
|
let list_value = b.reflect_ref().as_list()?;
|
||||||
for (i, value) in list_value.iter().enumerate() {
|
|
||||||
if i < a.len() {
|
for (i, value) in list_value.iter().enumerate() {
|
||||||
if let Some(v) = a.get_mut(i) {
|
if i < a.len() {
|
||||||
v.try_apply(value)?;
|
if let Some(v) = a.get_mut(i) {
|
||||||
}
|
v.try_apply(value)?;
|
||||||
} else {
|
|
||||||
List::push(a, value.clone_value());
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
List::push(a, value.clone_value());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: b.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::List,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +519,7 @@ pub fn list_debug(dyn_list: &dyn List, f: &mut Formatter<'_>) -> std::fmt::Resul
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::DynamicList;
|
use super::DynamicList;
|
||||||
use crate::{Reflect, ReflectRef};
|
use crate::Reflect;
|
||||||
use std::assert_eq;
|
use std::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -551,9 +547,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let b = Box::new(vec![(); SIZE]).into_reflect();
|
let b = Box::new(vec![(); SIZE]).into_reflect();
|
||||||
|
|
||||||
let ReflectRef::List(list) = b.reflect_ref() else {
|
let list = b.reflect_ref().as_list().unwrap();
|
||||||
panic!("Not a list...");
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut iter = list.iter();
|
let mut iter = list.iter();
|
||||||
iter.index = SIZE - 1;
|
iter.index = SIZE - 1;
|
||||||
|
|||||||
@ -552,20 +552,16 @@ pub fn map_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) {
|
|||||||
/// applying elements to each other fails.
|
/// applying elements to each other fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::Map(map_value) = b.reflect_ref() {
|
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) {
|
for (key, b_value) in map_value.iter() {
|
||||||
a_value.try_apply(b_value)?;
|
if let Some(a_value) = a.get_mut(key) {
|
||||||
} else {
|
a_value.try_apply(b_value)?;
|
||||||
a.insert_boxed(key.clone_value(), b_value.clone_value());
|
} else {
|
||||||
}
|
a.insert_boxed(key.clone_value(), b_value.clone_value());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: b.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::Map,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
array_debug, enum_debug, list_debug, map_debug, serde::Serializable, set_debug, struct_debug,
|
array_debug, enum_debug, list_debug, map_debug, serde::Serializable, set_debug, struct_debug,
|
||||||
tuple_debug, tuple_struct_debug, Array, DynamicTypePath, DynamicTyped, Enum, List, Map, Set,
|
tuple_debug, tuple_struct_debug, DynamicTypePath, DynamicTyped, ReflectKind,
|
||||||
Struct, Tuple, TupleStruct, TypeInfo, TypePath, Typed, ValueInfo,
|
ReflectKindMismatchError, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, Typed,
|
||||||
|
ValueInfo,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
@ -12,110 +13,6 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use crate::utility::NonGenericTypeInfoCell;
|
use crate::utility::NonGenericTypeInfoCell;
|
||||||
|
|
||||||
macro_rules! impl_reflect_enum {
|
|
||||||
($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::Value(_) => ReflectKind::Value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::Value(_) => Self::Value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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`].
|
|
||||||
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 crate::func::Function),
|
|
||||||
Value(&'a dyn PartialReflect),
|
|
||||||
}
|
|
||||||
impl_reflect_enum!(ReflectRef<'_>);
|
|
||||||
|
|
||||||
/// 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`].
|
|
||||||
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 crate::func::Function),
|
|
||||||
Value(&'a mut dyn PartialReflect),
|
|
||||||
}
|
|
||||||
impl_reflect_enum!(ReflectMut<'_>);
|
|
||||||
|
|
||||||
/// 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`].
|
|
||||||
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 crate::func::Function>),
|
|
||||||
Value(Box<dyn PartialReflect>),
|
|
||||||
}
|
|
||||||
impl_reflect_enum!(ReflectOwned);
|
|
||||||
|
|
||||||
/// A enumeration of all error outcomes that might happen when running [`try_apply`](PartialReflect::try_apply).
|
/// A enumeration of all error outcomes that might happen when running [`try_apply`](PartialReflect::try_apply).
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ApplyError {
|
pub enum ApplyError {
|
||||||
@ -152,39 +49,11 @@ pub enum ApplyError {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A zero-sized enumeration of the "kinds" of a reflected type.
|
impl From<ReflectKindMismatchError> for ApplyError {
|
||||||
///
|
fn from(value: ReflectKindMismatchError) -> Self {
|
||||||
/// A [`ReflectKind`] is obtained via [`PartialReflect::reflect_kind`],
|
Self::MismatchedKinds {
|
||||||
/// or via [`ReflectRef::kind`],[`ReflectMut::kind`] or [`ReflectOwned::kind`].
|
from_kind: value.received,
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
to_kind: value.expected,
|
||||||
pub enum ReflectKind {
|
|
||||||
Struct,
|
|
||||||
TupleStruct,
|
|
||||||
Tuple,
|
|
||||||
List,
|
|
||||||
Array,
|
|
||||||
Map,
|
|
||||||
Set,
|
|
||||||
Enum,
|
|
||||||
#[cfg(feature = "functions")]
|
|
||||||
Function,
|
|
||||||
Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for ReflectKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::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::Value => f.pad("value"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,6 +71,9 @@ impl std::fmt::Display for ReflectKind {
|
|||||||
///
|
///
|
||||||
/// [`bevy_reflect`]: crate
|
/// [`bevy_reflect`]: crate
|
||||||
/// [the derive macro for `Reflect`]: bevy_reflect_derive::Reflect
|
/// [the derive macro for `Reflect`]: bevy_reflect_derive::Reflect
|
||||||
|
/// [`Struct`]: crate::Struct
|
||||||
|
/// [`TupleStruct`]: crate::TupleStruct
|
||||||
|
/// [`Enum`]: crate::Enum
|
||||||
/// [crate-level documentation]: crate
|
/// [crate-level documentation]: crate
|
||||||
#[diagnostic::on_unimplemented(
|
#[diagnostic::on_unimplemented(
|
||||||
message = "`{Self}` does not implement `PartialReflect` so cannot be introspected",
|
message = "`{Self}` does not implement `PartialReflect` so cannot be introspected",
|
||||||
@ -289,6 +161,13 @@ where
|
|||||||
/// [`list_apply`] and [`map_apply`] helper functions when implementing this method.
|
/// [`list_apply`] and [`map_apply`] helper functions when implementing this method.
|
||||||
///
|
///
|
||||||
/// [introspection subtrait]: crate#the-introspection-subtraits
|
/// [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
|
/// [`list_apply`]: crate::list_apply
|
||||||
/// [`map_apply`]: crate::map_apply
|
/// [`map_apply`]: crate::map_apply
|
||||||
///
|
///
|
||||||
@ -344,6 +223,12 @@ where
|
|||||||
/// or [`Enum::clone_dynamic`], respectively.
|
/// or [`Enum::clone_dynamic`], respectively.
|
||||||
/// Implementors of other `Reflect` subtraits (e.g. [`List`], [`Map`]) should
|
/// Implementors of other `Reflect` subtraits (e.g. [`List`], [`Map`]) should
|
||||||
/// use those subtraits' respective `clone_dynamic` methods.
|
/// use those subtraits' respective `clone_dynamic` methods.
|
||||||
|
///
|
||||||
|
/// [`Struct::clone_dynamic`]: crate::Struct::clone_dynamic
|
||||||
|
/// [`TupleStruct::clone_dynamic`]: crate::TupleStruct::clone_dynamic
|
||||||
|
/// [`Enum::clone_dynamic`]: crate::Enum::clone_dynamic
|
||||||
|
/// [`List`]: crate::List
|
||||||
|
/// [`Map`]: crate::Map
|
||||||
fn clone_value(&self) -> Box<dyn PartialReflect>;
|
fn clone_value(&self) -> Box<dyn PartialReflect>;
|
||||||
|
|
||||||
/// Returns a hash of the value (which includes the type).
|
/// Returns a hash of the value (which includes the type).
|
||||||
@ -366,6 +251,8 @@ where
|
|||||||
/// (e.g. [`List`], [`Map`]), will default to the format: `"Reflect(type_path)"`,
|
/// (e.g. [`List`], [`Map`]), will default to the format: `"Reflect(type_path)"`,
|
||||||
/// where `type_path` is the [type path] of the underlying type.
|
/// where `type_path` is the [type path] of the underlying type.
|
||||||
///
|
///
|
||||||
|
/// [`List`]: crate::List
|
||||||
|
/// [`Map`]: crate::Map
|
||||||
/// [type path]: TypePath::type_path
|
/// [type path]: TypePath::type_path
|
||||||
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self.reflect_ref() {
|
match self.reflect_ref() {
|
||||||
@ -423,6 +310,9 @@ where
|
|||||||
///
|
///
|
||||||
/// [`bevy_reflect`]: crate
|
/// [`bevy_reflect`]: crate
|
||||||
/// [the derive macro]: bevy_reflect_derive::Reflect
|
/// [the derive macro]: bevy_reflect_derive::Reflect
|
||||||
|
/// [`Struct`]: crate::Struct
|
||||||
|
/// [`TupleStruct`]: crate::TupleStruct
|
||||||
|
/// [`Enum`]: crate::Enum
|
||||||
/// [`Reflectable`]: crate::Reflectable
|
/// [`Reflectable`]: crate::Reflectable
|
||||||
/// [crate-level documentation]: crate
|
/// [crate-level documentation]: crate
|
||||||
#[diagnostic::on_unimplemented(
|
#[diagnostic::on_unimplemented(
|
||||||
|
|||||||
@ -473,18 +473,14 @@ pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
|
|||||||
/// applying elements to each other fails.
|
/// applying elements to each other fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::Set(set_value) = b.reflect_ref() {
|
let set_value = b.reflect_ref().as_set()?;
|
||||||
for b_value in set_value.iter() {
|
|
||||||
if a.get(b_value).is_none() {
|
for b_value in set_value.iter() {
|
||||||
a.insert_boxed(b_value.clone_value());
|
if a.get(b_value).is_none() {
|
||||||
}
|
a.insert_boxed(b_value.clone_value());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: b.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::Set,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -406,19 +406,15 @@ impl PartialReflect for DynamicStruct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
|
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::Struct(struct_value) = value.reflect_ref() {
|
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();
|
for (i, value) in struct_value.iter_fields().enumerate() {
|
||||||
if let Some(v) = self.field_mut(name) {
|
let name = struct_value.name_at(i).unwrap();
|
||||||
v.try_apply(value)?;
|
if let Some(v) = self.field_mut(name) {
|
||||||
}
|
v.try_apply(value)?;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: value.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::Struct,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -403,18 +403,14 @@ pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) {
|
|||||||
/// applying elements to each other fails.
|
/// applying elements to each other fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
|
let tuple = b.reflect_ref().as_tuple()?;
|
||||||
for (i, value) in tuple.iter_fields().enumerate() {
|
|
||||||
if let Some(v) = a.field_mut(i) {
|
for (i, value) in tuple.iter_fields().enumerate() {
|
||||||
v.try_apply(value)?;
|
if let Some(v) = a.field_mut(i) {
|
||||||
}
|
v.try_apply(value)?;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: b.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::Tuple,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,17 +641,15 @@ macro_rules! impl_reflect_tuple {
|
|||||||
impl<$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*> FromReflect for ($($name,)*)
|
impl<$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*> FromReflect for ($($name,)*)
|
||||||
{
|
{
|
||||||
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
|
||||||
if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() {
|
let _ref_tuple = reflect.reflect_ref().as_tuple().ok()?;
|
||||||
Some(
|
|
||||||
(
|
Some(
|
||||||
$(
|
(
|
||||||
<$name as FromReflect>::from_reflect(_ref_tuple.field($index)?)?,
|
$(
|
||||||
)*
|
<$name as FromReflect>::from_reflect(_ref_tuple.field($index)?)?,
|
||||||
)
|
)*
|
||||||
)
|
)
|
||||||
} else {
|
)
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -314,18 +314,14 @@ impl PartialReflect for DynamicTupleStruct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
|
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
|
||||||
if let ReflectRef::TupleStruct(tuple_struct) = value.reflect_ref() {
|
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) {
|
for (i, value) in tuple_struct.iter_fields().enumerate() {
|
||||||
v.try_apply(value)?;
|
if let Some(v) = self.field_mut(i) {
|
||||||
}
|
v.try_apply(value)?;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ApplyError::MismatchedKinds {
|
|
||||||
from_kind: value.reflect_kind(),
|
|
||||||
to_kind: ReflectKind::TupleStruct,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use bevy::reflect::{
|
|||||||
reflect_trait, serde::TypedReflectDeserializer, std_traits::ReflectDefault, DynamicArray,
|
reflect_trait, serde::TypedReflectDeserializer, std_traits::ReflectDefault, DynamicArray,
|
||||||
DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
|
DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
|
||||||
DynamicTupleStruct, DynamicVariant, FromReflect, PartialReflect, Reflect, ReflectFromReflect,
|
DynamicTupleStruct, DynamicVariant, FromReflect, PartialReflect, Reflect, ReflectFromReflect,
|
||||||
ReflectRef, Set, TypeRegistry, Typed,
|
Set, TypeRegistry, Typed,
|
||||||
};
|
};
|
||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -56,9 +56,7 @@ fn main() {
|
|||||||
|
|
||||||
// This dynamic type is used to represent (or "proxy") the original type,
|
// This dynamic type is used to represent (or "proxy") the original type,
|
||||||
// so that we can continue to access its fields and overall structure.
|
// so that we can continue to access its fields and overall structure.
|
||||||
let ReflectRef::Struct(cloned_ref) = cloned.reflect_ref() else {
|
let cloned_ref = cloned.reflect_ref().as_struct().unwrap();
|
||||||
panic!("expected struct")
|
|
||||||
};
|
|
||||||
let id = cloned_ref.field("id").unwrap().try_downcast_ref::<u32>();
|
let id = cloned_ref.field("id").unwrap().try_downcast_ref::<u32>();
|
||||||
assert_eq!(id, Some(&123));
|
assert_eq!(id, Some(&123));
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user