 4d05eb19be
			
		
	
	
		4d05eb19be
		
	
	
	
	
		
			
			# Objective
`glam` is an optional feature in `bevy_reflect` and there is a separate `mod test { #[cfg(feature = "glam")] mod glam { .. }}`.
The `reflect_downcast` test is not in that module and doesn't depend on glam, which breaks `cargo test -p bevy_reflect` without the `glam` feature.
## Solution
- Remove the glam types from the test, they're not relevant to it
		
	
			
		
			
				
	
	
		
			986 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			986 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| #![doc = include_str!("../README.md")]
 | |
| 
 | |
| mod array;
 | |
| mod fields;
 | |
| mod list;
 | |
| mod map;
 | |
| mod path;
 | |
| mod reflect;
 | |
| mod struct_trait;
 | |
| mod tuple;
 | |
| mod tuple_struct;
 | |
| mod type_info;
 | |
| mod type_registry;
 | |
| mod type_uuid;
 | |
| mod impls {
 | |
|     #[cfg(feature = "glam")]
 | |
|     mod glam;
 | |
|     #[cfg(feature = "smallvec")]
 | |
|     mod smallvec;
 | |
|     mod std;
 | |
| 
 | |
|     #[cfg(feature = "glam")]
 | |
|     pub use self::glam::*;
 | |
|     #[cfg(feature = "smallvec")]
 | |
|     pub use self::smallvec::*;
 | |
|     pub use self::std::*;
 | |
| }
 | |
| 
 | |
| pub mod serde;
 | |
| pub mod std_traits;
 | |
| pub mod utility;
 | |
| 
 | |
| pub mod prelude {
 | |
|     pub use crate::std_traits::*;
 | |
|     #[doc(hidden)]
 | |
|     pub use crate::{
 | |
|         reflect_trait, GetField, GetTupleStructField, Reflect, ReflectDeserialize,
 | |
|         ReflectSerialize, Struct, TupleStruct,
 | |
|     };
 | |
| }
 | |
| 
 | |
| pub use array::*;
 | |
| pub use fields::*;
 | |
| pub use impls::*;
 | |
| pub use list::*;
 | |
| pub use map::*;
 | |
| pub use path::*;
 | |
| pub use reflect::*;
 | |
| pub use struct_trait::*;
 | |
| pub use tuple::*;
 | |
| pub use tuple_struct::*;
 | |
| pub use type_info::*;
 | |
| pub use type_registry::*;
 | |
| pub use type_uuid::*;
 | |
| 
 | |
| pub use bevy_reflect_derive::*;
 | |
| pub use erased_serde;
 | |
| 
 | |
| #[doc(hidden)]
 | |
| pub mod __macro_exports {
 | |
|     use crate::Uuid;
 | |
| 
 | |
|     /// Generates a new UUID from the given UUIDs `a` and `b`,
 | |
|     /// where the bytes are generated by a bitwise `a ^ b.rotate_right(1)`.
 | |
|     /// The generated UUID will be a `UUIDv4` (meaning that the bytes should be random, not e.g. derived from the system time).
 | |
|     #[allow(clippy::unusual_byte_groupings)] // unusual byte grouping is meant to signal the relevant bits
 | |
|     pub const fn generate_composite_uuid(a: Uuid, b: Uuid) -> Uuid {
 | |
|         let mut new = [0; 16];
 | |
|         let mut i = 0;
 | |
|         while i < new.len() {
 | |
|             // rotating ensures different uuids for A<B<C>> and B<A<C>> because: A ^ (B ^ C) = B ^ (A ^ C)
 | |
|             // notice that you have to rotate the second parameter: A.rr ^ (B.rr ^ C) = B.rr ^ (A.rr ^ C)
 | |
|             // Solution: A ^ (B ^ C.rr).rr != B ^ (A ^ C.rr).rr
 | |
|             new[i] = a.as_bytes()[i] ^ b.as_bytes()[i].rotate_right(1);
 | |
| 
 | |
|             i += 1;
 | |
|         }
 | |
| 
 | |
|         // Version: the most significant 4 bits in the 6th byte: 11110000
 | |
|         new[6] = new[6] & 0b0000_1111 | 0b0100_0000; // set version to v4
 | |
| 
 | |
|         // Variant: the most significant 3 bits in the 8th byte: 11100000
 | |
|         new[8] = new[8] & 0b000_11111 | 0b100_00000; // set variant to rfc4122
 | |
| 
 | |
|         Uuid::from_bytes(new)
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(test)]
 | |
| #[allow(clippy::blacklisted_name, clippy::approx_constant)]
 | |
| mod tests {
 | |
|     #[cfg(feature = "glam")]
 | |
|     use ::glam::{vec3, Vec3};
 | |
|     use ::serde::de::DeserializeSeed;
 | |
|     use bevy_utils::HashMap;
 | |
|     use ron::{
 | |
|         ser::{to_string_pretty, PrettyConfig},
 | |
|         Deserializer,
 | |
|     };
 | |
|     use std::fmt::{Debug, Formatter};
 | |
| 
 | |
|     use super::prelude::*;
 | |
|     use super::*;
 | |
|     use crate as bevy_reflect;
 | |
|     use crate::serde::{ReflectDeserializer, ReflectSerializer};
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_struct() {
 | |
|         #[derive(Reflect)]
 | |
|         struct Foo {
 | |
|             a: u32,
 | |
|             b: f32,
 | |
|             c: Bar,
 | |
|         }
 | |
|         #[derive(Reflect)]
 | |
|         struct Bar {
 | |
|             x: u32,
 | |
|         }
 | |
| 
 | |
|         let mut foo = Foo {
 | |
|             a: 42,
 | |
|             b: 3.14,
 | |
|             c: Bar { x: 1 },
 | |
|         };
 | |
| 
 | |
|         let a = *foo.get_field::<u32>("a").unwrap();
 | |
|         assert_eq!(a, 42);
 | |
| 
 | |
|         *foo.get_field_mut::<u32>("a").unwrap() += 1;
 | |
|         assert_eq!(foo.a, 43);
 | |
| 
 | |
|         let bar = foo.get_field::<Bar>("c").unwrap();
 | |
|         assert_eq!(bar.x, 1);
 | |
| 
 | |
|         // 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.");
 | |
|         }
 | |
| 
 | |
|         // patch Foo with a dynamic struct
 | |
|         let mut dynamic_struct = DynamicStruct::default();
 | |
|         dynamic_struct.insert("a", 123u32);
 | |
|         dynamic_struct.insert("should_be_ignored", 456);
 | |
| 
 | |
|         foo.apply(&dynamic_struct);
 | |
|         assert_eq!(foo.a, 123);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_map() {
 | |
|         #[derive(Reflect, Hash)]
 | |
|         #[reflect(Hash)]
 | |
|         struct Foo {
 | |
|             a: u32,
 | |
|             b: String,
 | |
|         }
 | |
| 
 | |
|         let key_a = Foo {
 | |
|             a: 1,
 | |
|             b: "k1".to_string(),
 | |
|         };
 | |
| 
 | |
|         let key_b = Foo {
 | |
|             a: 1,
 | |
|             b: "k1".to_string(),
 | |
|         };
 | |
| 
 | |
|         let key_c = Foo {
 | |
|             a: 3,
 | |
|             b: "k3".to_string(),
 | |
|         };
 | |
| 
 | |
|         let mut map = DynamicMap::default();
 | |
|         map.insert(key_a, 10u32);
 | |
|         assert_eq!(10, *map.get(&key_b).unwrap().downcast_ref::<u32>().unwrap());
 | |
|         assert!(map.get(&key_c).is_none());
 | |
|         *map.get_mut(&key_b).unwrap().downcast_mut::<u32>().unwrap() = 20;
 | |
|         assert_eq!(20, *map.get(&key_b).unwrap().downcast_ref::<u32>().unwrap());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     #[allow(clippy::blacklisted_name)]
 | |
|     fn reflect_unit_struct() {
 | |
|         #[derive(Reflect)]
 | |
|         struct Foo(u32, u64);
 | |
| 
 | |
|         let mut foo = Foo(1, 2);
 | |
|         assert_eq!(1, *foo.get_field::<u32>(0).unwrap());
 | |
|         assert_eq!(2, *foo.get_field::<u64>(1).unwrap());
 | |
| 
 | |
|         let mut patch = DynamicTupleStruct::default();
 | |
|         patch.insert(3u32);
 | |
|         patch.insert(4u64);
 | |
|         assert_eq!(3, *patch.field(0).unwrap().downcast_ref::<u32>().unwrap());
 | |
|         assert_eq!(4, *patch.field(1).unwrap().downcast_ref::<u64>().unwrap());
 | |
| 
 | |
|         foo.apply(&patch);
 | |
|         assert_eq!(3, foo.0);
 | |
|         assert_eq!(4, foo.1);
 | |
| 
 | |
|         let mut iter = patch.iter_fields();
 | |
|         assert_eq!(3, *iter.next().unwrap().downcast_ref::<u32>().unwrap());
 | |
|         assert_eq!(4, *iter.next().unwrap().downcast_ref::<u64>().unwrap());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     #[should_panic(expected = "the given key does not support hashing")]
 | |
|     fn reflect_map_no_hash() {
 | |
|         #[derive(Reflect)]
 | |
|         struct Foo {
 | |
|             a: u32,
 | |
|         }
 | |
| 
 | |
|         let foo = Foo { a: 1 };
 | |
| 
 | |
|         let mut map = DynamicMap::default();
 | |
|         map.insert(foo, 10u32);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_ignore() {
 | |
|         #[derive(Reflect)]
 | |
|         struct Foo {
 | |
|             a: u32,
 | |
|             #[reflect(ignore)]
 | |
|             _b: u32,
 | |
|         }
 | |
| 
 | |
|         let foo = Foo { a: 1, _b: 2 };
 | |
| 
 | |
|         let values: Vec<u32> = foo
 | |
|             .iter_fields()
 | |
|             .map(|value| *value.downcast_ref::<u32>().unwrap())
 | |
|             .collect();
 | |
|         assert_eq!(values, vec![1]);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn from_reflect_should_use_default_field_attributes() {
 | |
|         #[derive(Reflect, FromReflect, Eq, PartialEq, Debug)]
 | |
|         struct MyStruct {
 | |
|             // Use `Default::default()`
 | |
|             // Note that this isn't an ignored field
 | |
|             #[reflect(default)]
 | |
|             foo: String,
 | |
| 
 | |
|             // Use `get_bar_default()`
 | |
|             #[reflect(default = "get_bar_default")]
 | |
|             #[reflect(ignore)]
 | |
|             bar: usize,
 | |
|         }
 | |
| 
 | |
|         fn get_bar_default() -> usize {
 | |
|             123
 | |
|         }
 | |
| 
 | |
|         let expected = MyStruct {
 | |
|             foo: String::default(),
 | |
|             bar: 123,
 | |
|         };
 | |
| 
 | |
|         let dyn_struct = DynamicStruct::default();
 | |
|         let my_struct = <MyStruct as FromReflect>::from_reflect(&dyn_struct);
 | |
| 
 | |
|         assert_eq!(Some(expected), my_struct);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn from_reflect_should_use_default_container_attribute() {
 | |
|         #[derive(Reflect, FromReflect, Eq, PartialEq, Debug)]
 | |
|         #[reflect(Default)]
 | |
|         struct MyStruct {
 | |
|             foo: String,
 | |
|             #[reflect(ignore)]
 | |
|             bar: usize,
 | |
|         }
 | |
| 
 | |
|         impl Default for MyStruct {
 | |
|             fn default() -> Self {
 | |
|                 Self {
 | |
|                     foo: String::from("Hello"),
 | |
|                     bar: 123,
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         let expected = MyStruct {
 | |
|             foo: String::from("Hello"),
 | |
|             bar: 123,
 | |
|         };
 | |
| 
 | |
|         let dyn_struct = DynamicStruct::default();
 | |
|         let my_struct = <MyStruct as FromReflect>::from_reflect(&dyn_struct);
 | |
| 
 | |
|         assert_eq!(Some(expected), my_struct);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_complex_patch() {
 | |
|         #[derive(Reflect, Eq, PartialEq, Debug, FromReflect)]
 | |
|         #[reflect(PartialEq)]
 | |
|         struct Foo {
 | |
|             a: u32,
 | |
|             #[reflect(ignore)]
 | |
|             _b: u32,
 | |
|             c: Vec<isize>,
 | |
|             d: HashMap<usize, i8>,
 | |
|             e: Bar,
 | |
|             f: (i32, Vec<isize>, Bar),
 | |
|             g: Vec<(Baz, HashMap<usize, Bar>)>,
 | |
|             h: [u32; 2],
 | |
|         }
 | |
| 
 | |
|         #[derive(Reflect, Eq, PartialEq, Clone, Debug, FromReflect)]
 | |
|         #[reflect(PartialEq)]
 | |
|         struct Bar {
 | |
|             x: u32,
 | |
|         }
 | |
| 
 | |
|         #[derive(Reflect, Eq, PartialEq, Debug, FromReflect)]
 | |
|         struct Baz(String);
 | |
| 
 | |
|         let mut hash_map = HashMap::default();
 | |
|         hash_map.insert(1, 1);
 | |
|         hash_map.insert(2, 2);
 | |
| 
 | |
|         let mut hash_map_baz = HashMap::default();
 | |
|         hash_map_baz.insert(1, Bar { x: 0 });
 | |
| 
 | |
|         let mut foo = Foo {
 | |
|             a: 1,
 | |
|             _b: 1,
 | |
|             c: vec![1, 2],
 | |
|             d: hash_map,
 | |
|             e: Bar { x: 1 },
 | |
|             f: (1, vec![1, 2], Bar { x: 1 }),
 | |
|             g: vec![(Baz("string".to_string()), hash_map_baz)],
 | |
|             h: [2; 2],
 | |
|         };
 | |
| 
 | |
|         let mut foo_patch = DynamicStruct::default();
 | |
|         foo_patch.insert("a", 2u32);
 | |
|         foo_patch.insert("b", 2u32); // this should be ignored
 | |
| 
 | |
|         let mut list = DynamicList::default();
 | |
|         list.push(3isize);
 | |
|         list.push(4isize);
 | |
|         list.push(5isize);
 | |
|         foo_patch.insert("c", List::clone_dynamic(&list));
 | |
| 
 | |
|         let mut map = DynamicMap::default();
 | |
|         map.insert(2usize, 3i8);
 | |
|         map.insert(3usize, 4i8);
 | |
|         foo_patch.insert("d", map);
 | |
| 
 | |
|         let mut bar_patch = DynamicStruct::default();
 | |
|         bar_patch.insert("x", 2u32);
 | |
|         foo_patch.insert("e", bar_patch.clone_dynamic());
 | |
| 
 | |
|         let mut tuple = DynamicTuple::default();
 | |
|         tuple.insert(2i32);
 | |
|         tuple.insert(list);
 | |
|         tuple.insert(bar_patch);
 | |
|         foo_patch.insert("f", tuple);
 | |
| 
 | |
|         let mut composite = DynamicList::default();
 | |
|         composite.push({
 | |
|             let mut tuple = DynamicTuple::default();
 | |
|             tuple.insert({
 | |
|                 let mut tuple_struct = DynamicTupleStruct::default();
 | |
|                 tuple_struct.insert("new_string".to_string());
 | |
|                 tuple_struct
 | |
|             });
 | |
|             tuple.insert({
 | |
|                 let mut map = DynamicMap::default();
 | |
|                 map.insert(1usize, {
 | |
|                     let mut struct_ = DynamicStruct::default();
 | |
|                     struct_.insert("x", 7u32);
 | |
|                     struct_
 | |
|                 });
 | |
|                 map
 | |
|             });
 | |
|             tuple
 | |
|         });
 | |
|         foo_patch.insert("g", composite);
 | |
| 
 | |
|         let array = DynamicArray::from_vec(vec![2u32, 2u32]);
 | |
|         foo_patch.insert("h", array);
 | |
| 
 | |
|         foo.apply(&foo_patch);
 | |
| 
 | |
|         let mut hash_map = HashMap::default();
 | |
|         hash_map.insert(1, 1);
 | |
|         hash_map.insert(2, 3);
 | |
|         hash_map.insert(3, 4);
 | |
| 
 | |
|         let mut hash_map_baz = HashMap::default();
 | |
|         hash_map_baz.insert(1, Bar { x: 7 });
 | |
| 
 | |
|         let expected_foo = Foo {
 | |
|             a: 2,
 | |
|             _b: 1,
 | |
|             c: vec![3, 4, 5],
 | |
|             d: hash_map,
 | |
|             e: Bar { x: 2 },
 | |
|             f: (2, vec![3, 4, 5], Bar { x: 2 }),
 | |
|             g: vec![(Baz("new_string".to_string()), hash_map_baz.clone())],
 | |
|             h: [2; 2],
 | |
|         };
 | |
| 
 | |
|         assert_eq!(foo, expected_foo);
 | |
| 
 | |
|         let new_foo = Foo::from_reflect(&foo_patch)
 | |
|             .expect("error while creating a concrete type from a dynamic type");
 | |
| 
 | |
|         let mut hash_map = HashMap::default();
 | |
|         hash_map.insert(2, 3);
 | |
|         hash_map.insert(3, 4);
 | |
| 
 | |
|         let expected_new_foo = Foo {
 | |
|             a: 2,
 | |
|             _b: 0,
 | |
|             c: vec![3, 4, 5],
 | |
|             d: hash_map,
 | |
|             e: Bar { x: 2 },
 | |
|             f: (2, vec![3, 4, 5], Bar { x: 2 }),
 | |
|             g: vec![(Baz("new_string".to_string()), hash_map_baz)],
 | |
|             h: [2; 2],
 | |
|         };
 | |
| 
 | |
|         assert_eq!(new_foo, expected_new_foo);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_serialize() {
 | |
|         #[derive(Reflect)]
 | |
|         struct Foo {
 | |
|             a: u32,
 | |
|             #[reflect(ignore)]
 | |
|             _b: u32,
 | |
|             c: Vec<isize>,
 | |
|             d: HashMap<usize, i8>,
 | |
|             e: Bar,
 | |
|             f: String,
 | |
|             g: (i32, Vec<isize>, Bar),
 | |
|             h: [u32; 2],
 | |
|         }
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         struct Bar {
 | |
|             x: u32,
 | |
|         }
 | |
| 
 | |
|         let mut hash_map = HashMap::default();
 | |
|         hash_map.insert(1, 1);
 | |
|         hash_map.insert(2, 2);
 | |
|         let foo = Foo {
 | |
|             a: 1,
 | |
|             _b: 1,
 | |
|             c: vec![1, 2],
 | |
|             d: hash_map,
 | |
|             e: Bar { x: 1 },
 | |
|             f: "hi".to_string(),
 | |
|             g: (1, vec![1, 2], Bar { x: 1 }),
 | |
|             h: [2; 2],
 | |
|         };
 | |
| 
 | |
|         let mut registry = TypeRegistry::default();
 | |
|         registry.register::<u32>();
 | |
|         registry.register::<isize>();
 | |
|         registry.register::<usize>();
 | |
|         registry.register::<Bar>();
 | |
|         registry.register::<String>();
 | |
|         registry.register::<i8>();
 | |
|         registry.register::<i32>();
 | |
| 
 | |
|         let serializer = ReflectSerializer::new(&foo, ®istry);
 | |
|         let serialized = to_string_pretty(&serializer, PrettyConfig::default()).unwrap();
 | |
| 
 | |
|         let mut deserializer = Deserializer::from_str(&serialized).unwrap();
 | |
|         let reflect_deserializer = ReflectDeserializer::new(®istry);
 | |
|         let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
 | |
|         let dynamic_struct = value.take::<DynamicStruct>().unwrap();
 | |
| 
 | |
|         assert!(foo.reflect_partial_eq(&dynamic_struct).unwrap());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_downcast() {
 | |
|         #[derive(Reflect, Clone, Debug, PartialEq)]
 | |
|         struct Bar {
 | |
|             y: u8,
 | |
|         }
 | |
| 
 | |
|         #[derive(Reflect, Clone, Debug, PartialEq)]
 | |
|         struct Foo {
 | |
|             x: i32,
 | |
|             s: String,
 | |
|             b: Bar,
 | |
|             u: usize,
 | |
|             t: ([f32; 3], String),
 | |
|         }
 | |
| 
 | |
|         let foo = Foo {
 | |
|             x: 123,
 | |
|             s: "String".to_string(),
 | |
|             b: Bar { y: 255 },
 | |
|             u: 1111111111111,
 | |
|             t: ([3.0, 2.0, 1.0], "Tuple String".to_string()),
 | |
|         };
 | |
| 
 | |
|         let foo2: Box<dyn Reflect> = Box::new(foo.clone());
 | |
| 
 | |
|         assert_eq!(foo, *foo2.downcast::<Foo>().unwrap());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_take() {
 | |
|         #[derive(Reflect, Debug, PartialEq)]
 | |
|         #[reflect(PartialEq)]
 | |
|         struct Bar {
 | |
|             x: u32,
 | |
|         }
 | |
| 
 | |
|         let x: Box<dyn Reflect> = Box::new(Bar { x: 2 });
 | |
|         let y = x.take::<Bar>().unwrap();
 | |
|         assert_eq!(y, Bar { x: 2 });
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn dynamic_names() {
 | |
|         let list = Vec::<usize>::new();
 | |
|         let dyn_list = List::clone_dynamic(&list);
 | |
|         assert_eq!(dyn_list.type_name(), std::any::type_name::<Vec<usize>>());
 | |
| 
 | |
|         let array = [b'0'; 4];
 | |
|         let dyn_array = Array::clone_dynamic(&array);
 | |
|         assert_eq!(dyn_array.type_name(), std::any::type_name::<[u8; 4]>());
 | |
| 
 | |
|         let map = HashMap::<usize, String>::default();
 | |
|         let dyn_map = map.clone_dynamic();
 | |
|         assert_eq!(
 | |
|             dyn_map.type_name(),
 | |
|             std::any::type_name::<HashMap<usize, String>>()
 | |
|         );
 | |
| 
 | |
|         let tuple = (0usize, "1".to_string(), 2.0f32);
 | |
|         let mut dyn_tuple = tuple.clone_dynamic();
 | |
|         dyn_tuple.insert::<usize>(3);
 | |
|         assert_eq!(
 | |
|             dyn_tuple.type_name(),
 | |
|             std::any::type_name::<(usize, String, f32, usize)>()
 | |
|         );
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         struct TestStruct {
 | |
|             a: usize,
 | |
|         }
 | |
|         let struct_ = TestStruct { a: 0 };
 | |
|         let dyn_struct = struct_.clone_dynamic();
 | |
|         assert_eq!(dyn_struct.type_name(), std::any::type_name::<TestStruct>());
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         struct TestTupleStruct(usize);
 | |
|         let tuple_struct = TestTupleStruct(0);
 | |
|         let dyn_tuple_struct = tuple_struct.clone_dynamic();
 | |
|         assert_eq!(
 | |
|             dyn_tuple_struct.type_name(),
 | |
|             std::any::type_name::<TestTupleStruct>()
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn reflect_type_info() {
 | |
|         // TypeInfo
 | |
|         let info = i32::type_info();
 | |
|         assert_eq!(std::any::type_name::<i32>(), info.type_name());
 | |
|         assert_eq!(std::any::TypeId::of::<i32>(), info.type_id());
 | |
| 
 | |
|         // TypeInfo (unsized)
 | |
|         assert_eq!(
 | |
|             std::any::TypeId::of::<dyn Reflect>(),
 | |
|             <dyn Reflect as Typed>::type_info().type_id()
 | |
|         );
 | |
| 
 | |
|         // TypeInfo (instance)
 | |
|         let value: &dyn Reflect = &123_i32;
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<i32>());
 | |
| 
 | |
|         // Struct
 | |
|         #[derive(Reflect)]
 | |
|         struct MyStruct {
 | |
|             foo: i32,
 | |
|             bar: usize,
 | |
|         }
 | |
| 
 | |
|         let info = MyStruct::type_info();
 | |
|         if let TypeInfo::Struct(info) = info {
 | |
|             assert!(info.is::<MyStruct>());
 | |
|             assert_eq!(std::any::type_name::<MyStruct>(), info.type_name());
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<i32>(),
 | |
|                 info.field("foo").unwrap().type_name()
 | |
|             );
 | |
|             assert_eq!(
 | |
|                 std::any::TypeId::of::<i32>(),
 | |
|                 info.field("foo").unwrap().type_id()
 | |
|             );
 | |
|             assert!(info.field("foo").unwrap().is::<i32>());
 | |
|             assert_eq!("foo", info.field("foo").unwrap().name());
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<usize>(),
 | |
|                 info.field_at(1).unwrap().type_name()
 | |
|             );
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Struct`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &MyStruct { foo: 123, bar: 321 };
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyStruct>());
 | |
| 
 | |
|         // Struct (generic)
 | |
|         #[derive(Reflect)]
 | |
|         struct MyGenericStruct<T: Reflect> {
 | |
|             foo: T,
 | |
|             bar: usize,
 | |
|         }
 | |
| 
 | |
|         let info = <MyGenericStruct<i32>>::type_info();
 | |
|         if let TypeInfo::Struct(info) = info {
 | |
|             assert!(info.is::<MyGenericStruct<i32>>());
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<MyGenericStruct<i32>>(),
 | |
|                 info.type_name()
 | |
|             );
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<i32>(),
 | |
|                 info.field("foo").unwrap().type_name()
 | |
|             );
 | |
|             assert_eq!("foo", info.field("foo").unwrap().name());
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<usize>(),
 | |
|                 info.field_at(1).unwrap().type_name()
 | |
|             );
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Struct`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &MyGenericStruct {
 | |
|             foo: String::from("Hello!"),
 | |
|             bar: 321,
 | |
|         };
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyGenericStruct<String>>());
 | |
| 
 | |
|         // Tuple Struct
 | |
|         #[derive(Reflect)]
 | |
|         struct MyTupleStruct(usize, i32, MyStruct);
 | |
| 
 | |
|         let info = MyTupleStruct::type_info();
 | |
|         if let TypeInfo::TupleStruct(info) = info {
 | |
|             assert!(info.is::<MyTupleStruct>());
 | |
|             assert_eq!(std::any::type_name::<MyTupleStruct>(), info.type_name());
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<i32>(),
 | |
|                 info.field_at(1).unwrap().type_name()
 | |
|             );
 | |
|             assert!(info.field_at(1).unwrap().is::<i32>());
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::TupleStruct`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &MyTupleStruct(123, 321, MyStruct { foo: 123, bar: 321 });
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyTupleStruct>());
 | |
| 
 | |
|         // Tuple
 | |
|         type MyTuple = (u32, f32, String);
 | |
| 
 | |
|         let info = MyTuple::type_info();
 | |
|         if let TypeInfo::Tuple(info) = info {
 | |
|             assert!(info.is::<MyTuple>());
 | |
|             assert_eq!(std::any::type_name::<MyTuple>(), info.type_name());
 | |
|             assert_eq!(
 | |
|                 std::any::type_name::<f32>(),
 | |
|                 info.field_at(1).unwrap().type_name()
 | |
|             );
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Tuple`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &(123_u32, 1.23_f32, String::from("Hello!"));
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyTuple>());
 | |
| 
 | |
|         // List
 | |
|         type MyList = Vec<usize>;
 | |
| 
 | |
|         let info = MyList::type_info();
 | |
|         if let TypeInfo::List(info) = info {
 | |
|             assert!(info.is::<MyList>());
 | |
|             assert!(info.item_is::<usize>());
 | |
|             assert_eq!(std::any::type_name::<MyList>(), info.type_name());
 | |
|             assert_eq!(std::any::type_name::<usize>(), info.item_type_name());
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::List`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &vec![123_usize];
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyList>());
 | |
| 
 | |
|         // List (SmallVec)
 | |
|         #[cfg(feature = "smallvec")]
 | |
|         {
 | |
|             type MySmallVec = smallvec::SmallVec<[String; 2]>;
 | |
| 
 | |
|             let info = MySmallVec::type_info();
 | |
|             if let TypeInfo::List(info) = info {
 | |
|                 assert!(info.is::<MySmallVec>());
 | |
|                 assert!(info.item_is::<String>());
 | |
|                 assert_eq!(std::any::type_name::<MySmallVec>(), info.type_name());
 | |
|                 assert_eq!(std::any::type_name::<String>(), info.item_type_name());
 | |
|             } else {
 | |
|                 panic!("Expected `TypeInfo::List`");
 | |
|             }
 | |
| 
 | |
|             let value: MySmallVec = smallvec::smallvec![String::default(); 2];
 | |
|             let value: &dyn Reflect = &value;
 | |
|             let info = value.get_type_info();
 | |
|             assert!(info.is::<MySmallVec>());
 | |
|         }
 | |
| 
 | |
|         // Array
 | |
|         type MyArray = [usize; 3];
 | |
| 
 | |
|         let info = MyArray::type_info();
 | |
|         if let TypeInfo::Array(info) = info {
 | |
|             assert!(info.is::<MyArray>());
 | |
|             assert!(info.item_is::<usize>());
 | |
|             assert_eq!(std::any::type_name::<MyArray>(), info.type_name());
 | |
|             assert_eq!(std::any::type_name::<usize>(), info.item_type_name());
 | |
|             assert_eq!(3, info.capacity());
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Array`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &[1usize, 2usize, 3usize];
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyArray>());
 | |
| 
 | |
|         // Map
 | |
|         type MyMap = HashMap<usize, f32>;
 | |
| 
 | |
|         let info = MyMap::type_info();
 | |
|         if let TypeInfo::Map(info) = info {
 | |
|             assert!(info.is::<MyMap>());
 | |
|             assert!(info.key_is::<usize>());
 | |
|             assert!(info.value_is::<f32>());
 | |
|             assert_eq!(std::any::type_name::<MyMap>(), info.type_name());
 | |
|             assert_eq!(std::any::type_name::<usize>(), info.key_type_name());
 | |
|             assert_eq!(std::any::type_name::<f32>(), info.value_type_name());
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Map`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &MyMap::new();
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyMap>());
 | |
| 
 | |
|         // Value
 | |
|         type MyValue = String;
 | |
| 
 | |
|         let info = MyValue::type_info();
 | |
|         if let TypeInfo::Value(info) = info {
 | |
|             assert!(info.is::<MyValue>());
 | |
|             assert_eq!(std::any::type_name::<MyValue>(), info.type_name());
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Value`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &String::from("Hello!");
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyValue>());
 | |
| 
 | |
|         // Dynamic
 | |
|         type MyDynamic = DynamicList;
 | |
| 
 | |
|         let info = MyDynamic::type_info();
 | |
|         if let TypeInfo::Dynamic(info) = info {
 | |
|             assert!(info.is::<MyDynamic>());
 | |
|             assert_eq!(std::any::type_name::<MyDynamic>(), info.type_name());
 | |
|         } else {
 | |
|             panic!("Expected `TypeInfo::Dynamic`");
 | |
|         }
 | |
| 
 | |
|         let value: &dyn Reflect = &DynamicList::default();
 | |
|         let info = value.get_type_info();
 | |
|         assert!(info.is::<MyDynamic>());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn as_reflect() {
 | |
|         trait TestTrait: Reflect {}
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         struct TestStruct;
 | |
| 
 | |
|         impl TestTrait for TestStruct {}
 | |
| 
 | |
|         let trait_object: Box<dyn TestTrait> = Box::new(TestStruct);
 | |
| 
 | |
|         // Should compile:
 | |
|         let _ = trait_object.as_reflect();
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn should_reflect_debug() {
 | |
|         #[derive(Reflect)]
 | |
|         struct Test {
 | |
|             value: usize,
 | |
|             list: Vec<String>,
 | |
|             array: [f32; 3],
 | |
|             map: HashMap<i32, f32>,
 | |
|             a_struct: SomeStruct,
 | |
|             a_tuple_struct: SomeTupleStruct,
 | |
|             custom: CustomDebug,
 | |
|             unknown: Option<String>,
 | |
|             #[reflect(ignore)]
 | |
|             #[allow(dead_code)]
 | |
|             ignored: isize,
 | |
|         }
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         struct SomeStruct {
 | |
|             foo: String,
 | |
|         }
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         struct SomeTupleStruct(String);
 | |
| 
 | |
|         #[derive(Reflect)]
 | |
|         #[reflect(Debug)]
 | |
|         struct CustomDebug;
 | |
|         impl Debug for CustomDebug {
 | |
|             fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 | |
|                 f.write_str("Cool debug!")
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         let mut map = HashMap::new();
 | |
|         map.insert(123, 1.23);
 | |
| 
 | |
|         let test = Test {
 | |
|             value: 123,
 | |
|             list: vec![String::from("A"), String::from("B"), String::from("C")],
 | |
|             array: [1.0, 2.0, 3.0],
 | |
|             map,
 | |
|             a_struct: SomeStruct {
 | |
|                 foo: String::from("A Struct!"),
 | |
|             },
 | |
|             a_tuple_struct: SomeTupleStruct(String::from("A Tuple Struct!")),
 | |
|             custom: CustomDebug,
 | |
|             unknown: Some(String::from("Enums aren't supported yet :(")),
 | |
|             ignored: 321,
 | |
|         };
 | |
| 
 | |
|         let reflected: &dyn Reflect = &test;
 | |
|         let expected = r#"
 | |
| bevy_reflect::tests::should_reflect_debug::Test {
 | |
|     value: 123,
 | |
|     list: [
 | |
|         "A",
 | |
|         "B",
 | |
|         "C",
 | |
|     ],
 | |
|     array: [
 | |
|         1.0,
 | |
|         2.0,
 | |
|         3.0,
 | |
|     ],
 | |
|     map: {
 | |
|         123: 1.23,
 | |
|     },
 | |
|     a_struct: bevy_reflect::tests::should_reflect_debug::SomeStruct {
 | |
|         foo: "A Struct!",
 | |
|     },
 | |
|     a_tuple_struct: bevy_reflect::tests::should_reflect_debug::SomeTupleStruct(
 | |
|         "A Tuple Struct!",
 | |
|     ),
 | |
|     custom: Cool debug!,
 | |
|     unknown: Reflect(core::option::Option<alloc::string::String>),
 | |
| }"#;
 | |
| 
 | |
|         assert_eq!(expected, format!("\n{:#?}", reflected));
 | |
|     }
 | |
| 
 | |
|     #[cfg(feature = "glam")]
 | |
|     mod glam {
 | |
|         use super::*;
 | |
| 
 | |
|         #[test]
 | |
|         fn vec3_serialization() {
 | |
|             let v = vec3(12.0, 3.0, -6.9);
 | |
| 
 | |
|             let mut registry = TypeRegistry::default();
 | |
|             registry.register::<f32>();
 | |
|             registry.register::<Vec3>();
 | |
| 
 | |
|             let ser = ReflectSerializer::new(&v, ®istry);
 | |
| 
 | |
|             let result = ron::to_string(&ser).expect("Failed to serialize to string");
 | |
| 
 | |
|             assert_eq!(
 | |
|                 result,
 | |
|                 r#"{"type":"glam::f32::vec3::Vec3","struct":{"x":{"type":"f32","value":12.0},"y":{"type":"f32","value":3.0},"z":{"type":"f32","value":-6.9}}}"#
 | |
|             );
 | |
|         }
 | |
| 
 | |
|         #[test]
 | |
|         fn vec3_deserialization() {
 | |
|             let data = r#"{"type":"glam::vec3::Vec3","struct":{"x":{"type":"f32","value":12},"y":{"type":"f32","value":3},"z":{"type":"f32","value":-6.9}}}"#;
 | |
| 
 | |
|             let mut registry = TypeRegistry::default();
 | |
|             registry.add_registration(Vec3::get_type_registration());
 | |
|             registry.add_registration(f32::get_type_registration());
 | |
| 
 | |
|             let de = ReflectDeserializer::new(®istry);
 | |
| 
 | |
|             let mut deserializer =
 | |
|                 ron::de::Deserializer::from_str(data).expect("Failed to acquire deserializer");
 | |
| 
 | |
|             let dynamic_struct = de
 | |
|                 .deserialize(&mut deserializer)
 | |
|                 .expect("Failed to deserialize");
 | |
| 
 | |
|             let mut result = Vec3::default();
 | |
| 
 | |
|             result.apply(&*dynamic_struct);
 | |
| 
 | |
|             assert_eq!(result, vec3(12.0, 3.0, -6.9));
 | |
|         }
 | |
| 
 | |
|         #[test]
 | |
|         fn vec3_field_access() {
 | |
|             let mut v = vec3(1.0, 2.0, 3.0);
 | |
| 
 | |
|             assert_eq!(*v.get_field::<f32>("x").unwrap(), 1.0);
 | |
| 
 | |
|             *v.get_field_mut::<f32>("y").unwrap() = 6.0;
 | |
| 
 | |
|             assert_eq!(v.y, 6.0);
 | |
|         }
 | |
| 
 | |
|         #[test]
 | |
|         fn vec3_path_access() {
 | |
|             let mut v = vec3(1.0, 2.0, 3.0);
 | |
| 
 | |
|             assert_eq!(*v.path("x").unwrap().downcast_ref::<f32>().unwrap(), 1.0);
 | |
| 
 | |
|             *v.path_mut("y").unwrap().downcast_mut::<f32>().unwrap() = 6.0;
 | |
| 
 | |
|             assert_eq!(v.y, 6.0);
 | |
|         }
 | |
| 
 | |
|         #[test]
 | |
|         fn vec3_apply_dynamic() {
 | |
|             let mut v = vec3(3.0, 3.0, 3.0);
 | |
| 
 | |
|             let mut d = DynamicStruct::default();
 | |
|             d.insert("x", 4.0f32);
 | |
|             d.insert("y", 2.0f32);
 | |
|             d.insert("z", 1.0f32);
 | |
| 
 | |
|             v.apply(&d);
 | |
| 
 | |
|             assert_eq!(v, vec3(4.0, 2.0, 1.0));
 | |
|         }
 | |
|     }
 | |
| }
 |