#![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> and B> 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::("a").unwrap(); assert_eq!(a, 42); *foo.get_field_mut::("a").unwrap() += 1; assert_eq!(foo.a, 43); let bar = foo.get_field::("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::("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::().unwrap()); assert!(map.get(&key_c).is_none()); *map.get_mut(&key_b).unwrap().downcast_mut::().unwrap() = 20; assert_eq!(20, *map.get(&key_b).unwrap().downcast_ref::().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::(0).unwrap()); assert_eq!(2, *foo.get_field::(1).unwrap()); let mut patch = DynamicTupleStruct::default(); patch.insert(3u32); patch.insert(4u64); assert_eq!(3, *patch.field(0).unwrap().downcast_ref::().unwrap()); assert_eq!(4, *patch.field(1).unwrap().downcast_ref::().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::().unwrap()); assert_eq!(4, *iter.next().unwrap().downcast_ref::().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 = foo .iter_fields() .map(|value| *value.downcast_ref::().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 = ::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 = ::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, d: HashMap, e: Bar, f: (i32, Vec, Bar), g: Vec<(Baz, HashMap)>, 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); 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); 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); 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, d: HashMap, e: Bar, f: String, g: (i32, Vec, 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::(); registry.register::(); registry.register::(); registry.register::(); registry.register::(); registry.register::(); registry.register::(); 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::().unwrap(); assert!(foo.reflect_partial_eq(&dynamic_struct).unwrap()); } #[test] fn reflect_downcast() { #[derive(Reflect, Clone, Debug, PartialEq)] struct Bar { y: u8, z: ::glam::Mat4, } #[derive(Reflect, Clone, Debug, PartialEq)] struct Foo { x: i32, s: String, b: Bar, u: usize, t: (Vec3, String), } let foo = Foo { x: 123, s: "String".to_string(), b: Bar { y: 255, z: ::glam::Mat4::from_cols_array(&[ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, ]), }, u: 1111111111111, t: (Vec3::new(3.0, 2.0, 1.0), "Tuple String".to_string()), }; let foo2: Box = Box::new(foo.clone()); assert_eq!(foo, *foo2.downcast::().unwrap()); } #[test] fn reflect_take() { #[derive(Reflect, Debug, PartialEq)] #[reflect(PartialEq)] struct Bar { x: u32, } let x: Box = Box::new(Bar { x: 2 }); let y = x.take::().unwrap(); assert_eq!(y, Bar { x: 2 }); } #[test] fn dynamic_names() { let list = Vec::::new(); let dyn_list = List::clone_dynamic(&list); assert_eq!(dyn_list.type_name(), std::any::type_name::>()); 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::::default(); let dyn_map = map.clone_dynamic(); assert_eq!( dyn_map.type_name(), std::any::type_name::>() ); let tuple = (0usize, "1".to_string(), 2.0f32); let mut dyn_tuple = tuple.clone_dynamic(); dyn_tuple.insert::(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::()); #[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::() ); } #[test] fn reflect_type_info() { // TypeInfo let info = i32::type_info(); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::TypeId::of::(), info.type_id()); // TypeInfo (unsized) assert_eq!( std::any::TypeId::of::(), ::type_info().type_id() ); // TypeInfo (instance) let value: &dyn Reflect = &123_i32; let info = value.get_type_info(); assert!(info.is::()); // Struct #[derive(Reflect)] struct MyStruct { foo: i32, bar: usize, } let info = MyStruct::type_info(); if let TypeInfo::Struct(info) = info { assert!(info.is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), info.field("foo").unwrap().type_name() ); assert_eq!( std::any::TypeId::of::(), info.field("foo").unwrap().type_id() ); assert!(info.field("foo").unwrap().is::()); assert_eq!("foo", info.field("foo").unwrap().name()); assert_eq!( std::any::type_name::(), 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::()); // Struct (generic) #[derive(Reflect)] struct MyGenericStruct { foo: T, bar: usize, } let info = >::type_info(); if let TypeInfo::Struct(info) = info { assert!(info.is::>()); assert_eq!( std::any::type_name::>(), info.type_name() ); assert_eq!( std::any::type_name::(), info.field("foo").unwrap().type_name() ); assert_eq!("foo", info.field("foo").unwrap().name()); assert_eq!( std::any::type_name::(), 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::>()); // Tuple Struct #[derive(Reflect)] struct MyTupleStruct(usize, i32, MyStruct); let info = MyTupleStruct::type_info(); if let TypeInfo::TupleStruct(info) = info { assert!(info.is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), info.field_at(1).unwrap().type_name() ); assert!(info.field_at(1).unwrap().is::()); } 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::()); // Tuple type MyTuple = (u32, f32, String); let info = MyTuple::type_info(); if let TypeInfo::Tuple(info) = info { assert!(info.is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), 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::()); // List type MyList = Vec; let info = MyList::type_info(); if let TypeInfo::List(info) = info { assert!(info.is::()); assert!(info.item_is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::type_name::(), 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::()); // 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::()); assert!(info.item_is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::type_name::(), 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::()); } // Array type MyArray = [usize; 3]; let info = MyArray::type_info(); if let TypeInfo::Array(info) = info { assert!(info.is::()); assert!(info.item_is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::type_name::(), 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::()); // Map type MyMap = HashMap; let info = MyMap::type_info(); if let TypeInfo::Map(info) = info { assert!(info.is::()); assert!(info.key_is::()); assert!(info.value_is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::type_name::(), info.key_type_name()); assert_eq!(std::any::type_name::(), info.value_type_name()); } else { panic!("Expected `TypeInfo::Map`"); } let value: &dyn Reflect = &MyMap::new(); let info = value.get_type_info(); assert!(info.is::()); // Value type MyValue = String; let info = MyValue::type_info(); if let TypeInfo::Value(info) = info { assert!(info.is::()); assert_eq!(std::any::type_name::(), info.type_name()); } else { panic!("Expected `TypeInfo::Value`"); } let value: &dyn Reflect = &String::from("Hello!"); let info = value.get_type_info(); assert!(info.is::()); // Dynamic type MyDynamic = DynamicList; let info = MyDynamic::type_info(); if let TypeInfo::Dynamic(info) = info { assert!(info.is::()); assert_eq!(std::any::type_name::(), info.type_name()); } else { panic!("Expected `TypeInfo::Dynamic`"); } let value: &dyn Reflect = &DynamicList::default(); let info = value.get_type_info(); assert!(info.is::()); } #[test] fn as_reflect() { trait TestTrait: Reflect {} #[derive(Reflect)] struct TestStruct; impl TestTrait for TestStruct {} let trait_object: Box = Box::new(TestStruct); // Should compile: let _ = trait_object.as_reflect(); } #[test] fn should_reflect_debug() { #[derive(Reflect)] struct Test { value: usize, list: Vec, array: [f32; 3], map: HashMap, a_struct: SomeStruct, a_tuple_struct: SomeTupleStruct, custom: CustomDebug, unknown: Option, #[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), }"#; 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::(); registry.register::(); 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::("x").unwrap(), 1.0); *v.get_field_mut::("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::().unwrap(), 1.0); *v.path_mut("y").unwrap().downcast_mut::().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)); } } }