From f36a67ee9612b42a26118bb17f4ce845831f9551 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 23 May 2020 12:26:13 -0700 Subject: [PATCH] props: support nesting --- crates/bevy_derive/src/lib.rs | 52 +++++++ .../bevy_property/src/dynamic_properties.rs | 145 +++++++++++++----- crates/bevy_property/src/lib.rs | 4 +- crates/bevy_property/src/properties.rs | 7 - crates/bevy_property/src/property.rs | 36 ++++- examples/scene/properties.rs | 16 +- 6 files changed, 202 insertions(+), 58 deletions(-) diff --git a/crates/bevy_derive/src/lib.rs b/crates/bevy_derive/src/lib.rs index 08b8458452..2ab2fbf1ef 100644 --- a/crates/bevy_derive/src/lib.rs +++ b/crates/bevy_derive/src/lib.rs @@ -126,6 +126,58 @@ pub fn derive_props(input: TokenStream) -> TokenStream { #bevy_property_path::PropertyIter::new(self) } } + + impl #impl_generics #bevy_property_path::serde::ser::Serialize for #struct_name#ty_generics { + fn serialize(&self, serializer: S) -> Result + where + S: #bevy_property_path::serde::ser::Serializer, + { + use #bevy_property_path::serde::ser::SerializeMap; + let mut state = serializer.serialize_map(Some(self.prop_len()))?; + state.serialize_entry("type", self.type_name())?; + for (name, prop) in self.iter_props() { + state.serialize_entry(name, prop)?; + } + state.end() + } + } + + impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics { + #[inline] + fn any(&self) -> &dyn std::any::Any { + self + } + #[inline] + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.to_dynamic()) + } + #[inline] + fn set(&mut self, value: &dyn #bevy_property_path::Property) { + // TODO: type check + self.apply(value); + } + + #[inline] + fn apply(&mut self, value: &dyn #bevy_property_path::Property) { + if let Some(properties) = value.as_properties() { + for (name, prop) in properties.iter_props() { + self.prop_mut(name).map(|p| p.apply(prop)); + } + } else { + panic!("attempted to apply non-Properties type to Properties type"); + } + } + } + + impl #impl_generics #bevy_property_path::AsProperties for #struct_name#ty_generics { + fn as_properties(&self) -> Option<&dyn #bevy_property_path::Properties> { + Some(self) + } + } }) } diff --git a/crates/bevy_property/src/dynamic_properties.rs b/crates/bevy_property/src/dynamic_properties.rs index bc1e4e7e6c..7d93fa07b2 100644 --- a/crates/bevy_property/src/dynamic_properties.rs +++ b/crates/bevy_property/src/dynamic_properties.rs @@ -1,6 +1,10 @@ -use std::{collections::HashMap, borrow::Cow}; -use crate::{Properties, Property, PropertyIter}; -use serde::{Deserialize, Serialize, ser::SerializeMap, de::{self, MapAccess, Visitor}}; +use crate::{AsProperties, Properties, Property, PropertyIter, PropertyVal}; +use serde::{ + de::{self, MapAccess, Visitor}, + ser::SerializeMap, + Deserialize, Serialize, +}; +use std::{any::Any, borrow::Cow, collections::HashMap}; #[derive(Default)] pub struct DynamicProperties { @@ -127,7 +131,7 @@ impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> { let mut type_name: Option = None; while let Some(key) = map.next_key::()? { if &key == "type" { - type_name = Some(map.next_value()?); + type_name = Some(map.next_value()?); } else { let prop = map.next_value()?; self.dynamic_properties.set_box(&key, prop); @@ -151,7 +155,6 @@ impl<'de> Deserialize<'de> for Box { struct AnyPropVisiter; - impl<'de> Visitor<'de> for AnyPropVisiter { type Value = Box; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -159,63 +162,87 @@ impl<'de> Visitor<'de> for AnyPropVisiter { } fn visit_u8(self, v: u8) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_u16(self, v: u16) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_u32(self, v: u32) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_u64(self, v: u64) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_i8(self, v: i8) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_i16(self, v: i16) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_i32(self, v: i32) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_i64(self, v: i64) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_f32(self, v: f32) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_f64(self, v: f64) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_string(self, v: String) -> Result - where E: de::Error { - Ok(Box::new(v)) + where + E: de::Error, + { + Ok(Box::new(v)) } fn visit_str(self, v: &str) -> Result - where E: de::Error { - Ok(Box::new(v.to_string())) + where + E: de::Error, + { + Ok(Box::new(v.to_string())) } fn visit_map(self, mut map: V) -> Result @@ -223,11 +250,57 @@ impl<'de> Visitor<'de> for AnyPropVisiter { V: MapAccess<'de>, { let mut dynamic_properties = DynamicProperties::default(); - // while let Some(key) = map.next_key()? { - // let prop = map.next_value()?; - // self.dynamic_properties.set_box(key, prop); - // } - panic!("aaah"); - // Ok(Box::new(dynamic_properties)) + while let Some(key) = map.next_key()? { + let prop = map.next_value::>()?; + if key == "type" { + dynamic_properties.type_name = prop + .val::() + .map(|s| s.clone()) + .ok_or_else(|| de::Error::custom("type must be a string"))?; + } else { + dynamic_properties.set_box(key, prop); + } + } + Ok(Box::new(dynamic_properties)) } -} \ No newline at end of file +} + +impl Property for DynamicProperties { + #[inline] + fn any(&self) -> &dyn Any { + self + } + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.to_dynamic()) + } + #[inline] + fn set(&mut self, value: &dyn Property) { + if let Some(properties) = value.as_properties() { + *self = properties.to_dynamic(); + } else { + panic!("attempted to apply non-Properties type to Properties type"); + } + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + if let Some(properties) = value.as_properties() { + for (name, prop) in properties.iter_props() { + self.prop_mut(name).map(|p| p.apply(prop)); + } + } else { + panic!("attempted to apply non-Properties type to Properties type"); + } + } +} + +impl AsProperties for DynamicProperties { + fn as_properties(&self) -> Option<&dyn Properties> { + Some(self) + } +} diff --git a/crates/bevy_property/src/lib.rs b/crates/bevy_property/src/lib.rs index 6b0a719095..fa0164fbf3 100644 --- a/crates/bevy_property/src/lib.rs +++ b/crates/bevy_property/src/lib.rs @@ -6,4 +6,6 @@ mod dynamic_properties; pub use property::*; pub use properties::*; -pub use dynamic_properties::*; \ No newline at end of file +pub use dynamic_properties::*; + +pub use serde; \ No newline at end of file diff --git a/crates/bevy_property/src/properties.rs b/crates/bevy_property/src/properties.rs index 97dd3439d0..97ff5221b8 100644 --- a/crates/bevy_property/src/properties.rs +++ b/crates/bevy_property/src/properties.rs @@ -17,14 +17,7 @@ pub trait Properties { panic!("prop does not exist: {}", name); } } - fn apply(&mut self, props: &dyn Properties) { - for (name, prop) in props.iter_props() { - self.set_prop(name, prop); - } - } fn to_dynamic(&self) -> DynamicProperties - where - Self: 'static, { let mut dynamic_props = DynamicProperties::default(); for (name, prop) in self.iter_props() { diff --git a/crates/bevy_property/src/property.rs b/crates/bevy_property/src/property.rs index b2f5f91f74..ed0a608413 100644 --- a/crates/bevy_property/src/property.rs +++ b/crates/bevy_property/src/property.rs @@ -1,27 +1,33 @@ +use crate::Properties; use serde::Serialize; use std::any::Any; -pub trait Property: erased_serde::Serialize + Send + Sync + Any + 'static { +pub trait Property: erased_serde::Serialize + Send + Sync + Any + AsProperties + 'static { fn any(&self) -> &dyn Any; fn any_mut(&mut self) -> &mut dyn Any; fn clone_prop(&self) -> Box; fn set(&mut self, value: &dyn Property); + fn apply(&mut self, value: &dyn Property); } erased_serde::serialize_trait_object!(Property); +pub trait AsProperties { + fn as_properties(&self) -> Option<&dyn Properties>; +} + pub trait PropertyVal { fn val(&self) -> Option<&T>; fn set_val(&mut self, value: T); } impl PropertyVal for dyn Property { - // #[inline] + #[inline] default fn val(&self) -> Option<&T> { self.any().downcast_ref::() } - - // #[inline] + + #[inline] default fn set_val(&mut self, value: T) { if let Some(prop) = self.any_mut().downcast_mut::() { *prop = value; @@ -31,6 +37,17 @@ impl PropertyVal for dyn Property { } } +// TODO: remove specialization +impl AsProperties for T +where + T: Clone + Serialize + Send + Sync + Any + 'static, +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + + impl Property for T where T: Clone + Serialize + Send + Sync + Any + 'static, @@ -39,14 +56,17 @@ where default fn any(&self) -> &dyn Any { self } + #[inline] default fn any_mut(&mut self) -> &mut dyn Any { self } + #[inline] default fn clone_prop(&self) -> Box { Box::new(self.clone()) } + #[inline] default fn set(&mut self, value: &dyn Property) { if let Some(prop) = value.any().downcast_ref::() { @@ -55,6 +75,11 @@ where panic!("prop value is not {}", std::any::type_name::()); } } + + #[inline] + default fn apply(&mut self, value: &dyn Property) { + self.set(value); + } } impl Property for usize { @@ -347,7 +372,6 @@ impl Property for i8 { } } - impl Property for f32 { fn set(&mut self, value: &dyn Property) { let value = value.any(); @@ -372,4 +396,4 @@ impl Property for f64 { panic!("prop value is not {}", std::any::type_name::()); } } -} \ No newline at end of file +} diff --git a/examples/scene/properties.rs b/examples/scene/properties.rs index 9157826df1..4cfd30f3bc 100644 --- a/examples/scene/properties.rs +++ b/examples/scene/properties.rs @@ -17,22 +17,22 @@ pub struct Test { a: usize, b: String, c: f32, - // nest: Nested, + nest: Nested, } -// #[derive(Properties, Default, Clone)] -// pub struct Nested { -// d: usize, -// } +#[derive(Properties, Default)] +pub struct Nested { + d: usize, +} fn setup() { let mut test = Test { a: 1, b: "hi".to_string(), c: 1.0, - // nest: Nested { - // d: 8, - // } + nest: Nested { + d: 8, + } }; test.set_prop_val::("a", 2);