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 bevy_app::App;
 | 
			
		||||
    use bevy_ecs::reflect::AppTypeRegistry;
 | 
			
		||||
    use bevy_reflect::{Reflect, ReflectMut};
 | 
			
		||||
    use bevy_reflect::Reflect;
 | 
			
		||||
 | 
			
		||||
    #[derive(Asset, Reflect)]
 | 
			
		||||
    struct AssetType {
 | 
			
		||||
@ -278,13 +278,13 @@ mod tests {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .reflect_mut()
 | 
			
		||||
        else {
 | 
			
		||||
            unreachable!();
 | 
			
		||||
        };
 | 
			
		||||
            .as_struct()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        strukt
 | 
			
		||||
            .field_mut("field")
 | 
			
		||||
            .unwrap()
 | 
			
		||||
 | 
			
		||||
@ -436,23 +436,20 @@ pub fn array_try_apply<A: Array>(
 | 
			
		||||
    array: &mut A,
 | 
			
		||||
    reflect: &dyn PartialReflect,
 | 
			
		||||
) -> Result<(), ApplyError> {
 | 
			
		||||
    if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
 | 
			
		||||
        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)?;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
            from_kind: reflect.reflect_kind(),
 | 
			
		||||
            to_kind: ReflectKind::Array,
 | 
			
		||||
    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(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -507,7 +504,7 @@ pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> std::fmt::Re
 | 
			
		||||
}
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::{Reflect, ReflectRef};
 | 
			
		||||
    use crate::Reflect;
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn next_index_increment() {
 | 
			
		||||
        const SIZE: usize = if cfg!(debug_assertions) {
 | 
			
		||||
@ -519,9 +516,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
        let b = Box::new([(); SIZE]).into_reflect();
 | 
			
		||||
 | 
			
		||||
        let ReflectRef::Array(array) = b.reflect_ref() else {
 | 
			
		||||
            panic!("Not an array...");
 | 
			
		||||
        };
 | 
			
		||||
        let array = b.reflect_ref().as_array().unwrap();
 | 
			
		||||
 | 
			
		||||
        let mut iter = array.iter();
 | 
			
		||||
        iter.index = SIZE - 1;
 | 
			
		||||
 | 
			
		||||
@ -322,55 +322,50 @@ impl PartialReflect for DynamicEnum {
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
 | 
			
		||||
        if let ReflectRef::Enum(value) = value.reflect_ref() {
 | 
			
		||||
            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())?;
 | 
			
		||||
                            }
 | 
			
		||||
        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().clone_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())?;
 | 
			
		||||
                        }
 | 
			
		||||
                        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 {
 | 
			
		||||
            return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
                from_kind: value.reflect_kind(),
 | 
			
		||||
                to_kind: ReflectKind::Enum,
 | 
			
		||||
            });
 | 
			
		||||
            // 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().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(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -194,15 +194,15 @@ where
 | 
			
		||||
    T::Item: FromReflect + MaybeTyped + TypePath,
 | 
			
		||||
{
 | 
			
		||||
    fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
        if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
 | 
			
		||||
            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)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -544,15 +544,15 @@ macro_rules! impl_reflect_for_veclike {
 | 
			
		||||
 | 
			
		||||
        impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration> FromReflect for $ty {
 | 
			
		||||
            fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
                if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
 | 
			
		||||
                    let mut new_list = Self::with_capacity(ref_list.len());
 | 
			
		||||
                    for field in ref_list.iter() {
 | 
			
		||||
                        $push(&mut new_list, T::from_reflect(field)?);
 | 
			
		||||
                    }
 | 
			
		||||
                    Some(new_list)
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                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() {
 | 
			
		||||
                    $push(&mut new_list, T::from_reflect(field)?);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Some(new_list)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@ -792,17 +792,17 @@ macro_rules! impl_reflect_for_hashmap {
 | 
			
		||||
            S: TypePath + BuildHasher + Default + Send + Sync,
 | 
			
		||||
        {
 | 
			
		||||
            fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
                if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
 | 
			
		||||
                    let mut new_map = Self::with_capacity_and_hasher(ref_map.len(), S::default());
 | 
			
		||||
                    for (key, value) in ref_map.iter() {
 | 
			
		||||
                        let new_key = K::from_reflect(key)?;
 | 
			
		||||
                        let new_value = V::from_reflect(value)?;
 | 
			
		||||
                        new_map.insert(new_key, new_value);
 | 
			
		||||
                    }
 | 
			
		||||
                    Some(new_map)
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                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 new_key = K::from_reflect(key)?;
 | 
			
		||||
                    let new_value = V::from_reflect(value)?;
 | 
			
		||||
                    new_map.insert(new_key, new_value);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Some(new_map)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@ -1013,16 +1013,16 @@ macro_rules! impl_reflect_for_hashset {
 | 
			
		||||
            S: TypePath + BuildHasher + Default + Send + Sync,
 | 
			
		||||
        {
 | 
			
		||||
            fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
                if let ReflectRef::Set(ref_set) = reflect.reflect_ref() {
 | 
			
		||||
                    let mut new_set = Self::with_capacity_and_hasher(ref_set.len(), S::default());
 | 
			
		||||
                    for value in ref_set.iter() {
 | 
			
		||||
                        let new_value = V::from_reflect(value)?;
 | 
			
		||||
                        new_set.insert(new_value);
 | 
			
		||||
                    }
 | 
			
		||||
                    Some(new_set)
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                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 new_value = V::from_reflect(value)?;
 | 
			
		||||
                    new_set.insert(new_value);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Some(new_set)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@ -1251,17 +1251,17 @@ where
 | 
			
		||||
    V: FromReflect + MaybeTyped + TypePath + GetTypeRegistration,
 | 
			
		||||
{
 | 
			
		||||
    fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
        if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
 | 
			
		||||
            let mut new_map = Self::new();
 | 
			
		||||
            for (key, value) in ref_map.iter() {
 | 
			
		||||
                let new_key = K::from_reflect(key)?;
 | 
			
		||||
                let new_value = V::from_reflect(value)?;
 | 
			
		||||
                new_map.insert(new_key, new_value);
 | 
			
		||||
            }
 | 
			
		||||
            Some(new_map)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        let ref_map = reflect.reflect_ref().as_map().ok()?;
 | 
			
		||||
 | 
			
		||||
        let mut new_map = Self::new();
 | 
			
		||||
 | 
			
		||||
        for (key, value) in ref_map.iter() {
 | 
			
		||||
            let new_key = K::from_reflect(key)?;
 | 
			
		||||
            let new_value = V::from_reflect(value)?;
 | 
			
		||||
            new_map.insert(new_key, new_value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Some(new_map)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1422,15 +1422,15 @@ impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration, const N: usiz
 | 
			
		||||
    for [T; N]
 | 
			
		||||
{
 | 
			
		||||
    fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
        if let ReflectRef::Array(ref_array) = reflect.reflect_ref() {
 | 
			
		||||
            let mut temp_vec = Vec::with_capacity(ref_array.len());
 | 
			
		||||
            for field in ref_array.iter() {
 | 
			
		||||
                temp_vec.push(T::from_reflect(field)?);
 | 
			
		||||
            }
 | 
			
		||||
            temp_vec.try_into().ok()
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        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() {
 | 
			
		||||
            temp_vec.push(T::from_reflect(field)?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        temp_vec.try_into().ok()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1795,15 +1795,15 @@ impl<T: FromReflect + MaybeTyped + Clone + TypePath + GetTypeRegistration> FromR
 | 
			
		||||
    for Cow<'static, [T]>
 | 
			
		||||
{
 | 
			
		||||
    fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
        if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
 | 
			
		||||
            let mut temp_vec = Vec::with_capacity(ref_list.len());
 | 
			
		||||
            for field in ref_list.iter() {
 | 
			
		||||
                temp_vec.push(T::from_reflect(field)?);
 | 
			
		||||
            }
 | 
			
		||||
            Some(temp_vec.into())
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        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() {
 | 
			
		||||
            temp_vec.push(T::from_reflect(field)?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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};
 | 
			
		||||
//! 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());
 | 
			
		||||
//! ```
 | 
			
		||||
//!
 | 
			
		||||
@ -545,6 +545,7 @@ mod fields;
 | 
			
		||||
mod from_reflect;
 | 
			
		||||
#[cfg(feature = "functions")]
 | 
			
		||||
pub mod func;
 | 
			
		||||
mod kind;
 | 
			
		||||
mod list;
 | 
			
		||||
mod map;
 | 
			
		||||
mod path;
 | 
			
		||||
@ -603,6 +604,7 @@ pub use array::*;
 | 
			
		||||
pub use enums::*;
 | 
			
		||||
pub use fields::*;
 | 
			
		||||
pub use from_reflect::*;
 | 
			
		||||
pub use kind::*;
 | 
			
		||||
pub use list::*;
 | 
			
		||||
pub use map::*;
 | 
			
		||||
pub use path::*;
 | 
			
		||||
@ -773,11 +775,8 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
        // nested retrieval
 | 
			
		||||
        let c = foo.field("c").unwrap();
 | 
			
		||||
        if let ReflectRef::Struct(value) = c.reflect_ref() {
 | 
			
		||||
            assert_eq!(*value.get_field::<u32>("x").unwrap(), 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            panic!("Expected a struct.");
 | 
			
		||||
        }
 | 
			
		||||
        let value = c.reflect_ref().as_struct().unwrap();
 | 
			
		||||
        assert_eq!(*value.get_field::<u32>("x").unwrap(), 1);
 | 
			
		||||
 | 
			
		||||
        // patch Foo with a dynamic struct
 | 
			
		||||
        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.
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
 | 
			
		||||
    if let ReflectRef::List(list_value) = b.reflect_ref() {
 | 
			
		||||
        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.clone_value());
 | 
			
		||||
    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.clone_value());
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
            from_kind: b.reflect_kind(),
 | 
			
		||||
            to_kind: ReflectKind::List,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -523,7 +519,7 @@ pub fn list_debug(dyn_list: &dyn List, f: &mut Formatter<'_>) -> std::fmt::Resul
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::DynamicList;
 | 
			
		||||
    use crate::{Reflect, ReflectRef};
 | 
			
		||||
    use crate::Reflect;
 | 
			
		||||
    use std::assert_eq;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -551,9 +547,7 @@ mod tests {
 | 
			
		||||
        };
 | 
			
		||||
        let b = Box::new(vec![(); SIZE]).into_reflect();
 | 
			
		||||
 | 
			
		||||
        let ReflectRef::List(list) = b.reflect_ref() else {
 | 
			
		||||
            panic!("Not a list...");
 | 
			
		||||
        };
 | 
			
		||||
        let list = b.reflect_ref().as_list().unwrap();
 | 
			
		||||
 | 
			
		||||
        let mut iter = list.iter();
 | 
			
		||||
        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.
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
 | 
			
		||||
    if let ReflectRef::Map(map_value) = b.reflect_ref() {
 | 
			
		||||
        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.clone_value(), b_value.clone_value());
 | 
			
		||||
            }
 | 
			
		||||
    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.clone_value(), b_value.clone_value());
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
            from_kind: b.reflect_kind(),
 | 
			
		||||
            to_kind: ReflectKind::Map,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    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,
 | 
			
		||||
    Struct, Tuple, TupleStruct, TypeInfo, TypePath, Typed, ValueInfo,
 | 
			
		||||
    tuple_debug, tuple_struct_debug, DynamicTypePath, DynamicTyped, ReflectKind,
 | 
			
		||||
    ReflectKindMismatchError, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, Typed,
 | 
			
		||||
    ValueInfo,
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    any::{Any, TypeId},
 | 
			
		||||
@ -12,110 +13,6 @@ use thiserror::Error;
 | 
			
		||||
 | 
			
		||||
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).
 | 
			
		||||
#[derive(Error, Debug)]
 | 
			
		||||
pub enum ApplyError {
 | 
			
		||||
@ -152,39 +49,11 @@ pub enum ApplyError {
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A zero-sized enumeration of the "kinds" of a reflected 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 {
 | 
			
		||||
    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"),
 | 
			
		||||
impl From<ReflectKindMismatchError> for ApplyError {
 | 
			
		||||
    fn from(value: ReflectKindMismatchError) -> Self {
 | 
			
		||||
        Self::MismatchedKinds {
 | 
			
		||||
            from_kind: value.received,
 | 
			
		||||
            to_kind: value.expected,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -202,6 +71,9 @@ impl std::fmt::Display for ReflectKind {
 | 
			
		||||
///
 | 
			
		||||
/// [`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",
 | 
			
		||||
@ -289,6 +161,13 @@ where
 | 
			
		||||
    /// [`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
 | 
			
		||||
    ///
 | 
			
		||||
@ -344,6 +223,12 @@ where
 | 
			
		||||
    /// or [`Enum::clone_dynamic`], respectively.
 | 
			
		||||
    /// Implementors of other `Reflect` subtraits (e.g. [`List`], [`Map`]) should
 | 
			
		||||
    /// 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>;
 | 
			
		||||
 | 
			
		||||
    /// 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)"`,
 | 
			
		||||
    /// 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 std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        match self.reflect_ref() {
 | 
			
		||||
@ -423,6 +310,9 @@ where
 | 
			
		||||
///
 | 
			
		||||
/// [`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(
 | 
			
		||||
 | 
			
		||||
@ -473,18 +473,14 @@ pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
 | 
			
		||||
/// applying elements to each other fails.
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
 | 
			
		||||
    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.clone_value());
 | 
			
		||||
            }
 | 
			
		||||
    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.clone_value());
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
            from_kind: b.reflect_kind(),
 | 
			
		||||
            to_kind: ReflectKind::Set,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -406,19 +406,15 @@ impl PartialReflect for DynamicStruct {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
 | 
			
		||||
        if let ReflectRef::Struct(struct_value) = value.reflect_ref() {
 | 
			
		||||
            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)?;
 | 
			
		||||
                }
 | 
			
		||||
        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)?;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
                from_kind: value.reflect_kind(),
 | 
			
		||||
                to_kind: ReflectKind::Struct,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -403,18 +403,14 @@ pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) {
 | 
			
		||||
/// applying elements to each other fails.
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) -> Result<(), ApplyError> {
 | 
			
		||||
    if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
 | 
			
		||||
        for (i, value) in tuple.iter_fields().enumerate() {
 | 
			
		||||
            if let Some(v) = a.field_mut(i) {
 | 
			
		||||
                v.try_apply(value)?;
 | 
			
		||||
            }
 | 
			
		||||
    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)?;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
            from_kind: b.reflect_kind(),
 | 
			
		||||
            to_kind: ReflectKind::Tuple,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -645,17 +641,15 @@ macro_rules! impl_reflect_tuple {
 | 
			
		||||
        impl<$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*> FromReflect for ($($name,)*)
 | 
			
		||||
        {
 | 
			
		||||
            fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
 | 
			
		||||
                if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() {
 | 
			
		||||
                    Some(
 | 
			
		||||
                        (
 | 
			
		||||
                            $(
 | 
			
		||||
                                <$name as FromReflect>::from_reflect(_ref_tuple.field($index)?)?,
 | 
			
		||||
                            )*
 | 
			
		||||
                        )
 | 
			
		||||
                let _ref_tuple = reflect.reflect_ref().as_tuple().ok()?;
 | 
			
		||||
 | 
			
		||||
                Some(
 | 
			
		||||
                    (
 | 
			
		||||
                        $(
 | 
			
		||||
                            <$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> {
 | 
			
		||||
        if let ReflectRef::TupleStruct(tuple_struct) = value.reflect_ref() {
 | 
			
		||||
            for (i, value) in tuple_struct.iter_fields().enumerate() {
 | 
			
		||||
                if let Some(v) = self.field_mut(i) {
 | 
			
		||||
                    v.try_apply(value)?;
 | 
			
		||||
                }
 | 
			
		||||
        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)?;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            return Err(ApplyError::MismatchedKinds {
 | 
			
		||||
                from_kind: value.reflect_kind(),
 | 
			
		||||
                to_kind: ReflectKind::TupleStruct,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ use bevy::reflect::{
 | 
			
		||||
    reflect_trait, serde::TypedReflectDeserializer, std_traits::ReflectDefault, DynamicArray,
 | 
			
		||||
    DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
 | 
			
		||||
    DynamicTupleStruct, DynamicVariant, FromReflect, PartialReflect, Reflect, ReflectFromReflect,
 | 
			
		||||
    ReflectRef, Set, TypeRegistry, Typed,
 | 
			
		||||
    Set, TypeRegistry, Typed,
 | 
			
		||||
};
 | 
			
		||||
use serde::de::DeserializeSeed;
 | 
			
		||||
use std::collections::{HashMap, HashSet};
 | 
			
		||||
@ -56,9 +56,7 @@ fn main() {
 | 
			
		||||
 | 
			
		||||
    // This dynamic type is used to represent (or "proxy") the original type,
 | 
			
		||||
    // so that we can continue to access its fields and overall structure.
 | 
			
		||||
    let ReflectRef::Struct(cloned_ref) = cloned.reflect_ref() else {
 | 
			
		||||
        panic!("expected struct")
 | 
			
		||||
    };
 | 
			
		||||
    let cloned_ref = cloned.reflect_ref().as_struct().unwrap();
 | 
			
		||||
    let id = cloned_ref.field("id").unwrap().try_downcast_ref::<u32>();
 | 
			
		||||
    assert_eq!(id, Some(&123));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user