props: support nesting

This commit is contained in:
Carter Anderson 2020-05-23 12:26:13 -07:00
parent 284afd4f94
commit f36a67ee96
6 changed files with 202 additions and 58 deletions

View File

@ -126,6 +126,58 @@ pub fn derive_props(input: TokenStream) -> TokenStream {
#bevy_property_path::PropertyIter::new(self) #bevy_property_path::PropertyIter::new(self)
} }
} }
impl #impl_generics #bevy_property_path::serde::ser::Serialize for #struct_name#ty_generics {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<dyn #bevy_property_path::Property> {
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)
}
}
}) })
} }

View File

@ -1,6 +1,10 @@
use std::{collections::HashMap, borrow::Cow}; use crate::{AsProperties, Properties, Property, PropertyIter, PropertyVal};
use crate::{Properties, Property, PropertyIter}; use serde::{
use serde::{Deserialize, Serialize, ser::SerializeMap, de::{self, MapAccess, Visitor}}; de::{self, MapAccess, Visitor},
ser::SerializeMap,
Deserialize, Serialize,
};
use std::{any::Any, borrow::Cow, collections::HashMap};
#[derive(Default)] #[derive(Default)]
pub struct DynamicProperties { pub struct DynamicProperties {
@ -151,7 +155,6 @@ impl<'de> Deserialize<'de> for Box<dyn Property> {
struct AnyPropVisiter; struct AnyPropVisiter;
impl<'de> Visitor<'de> for AnyPropVisiter { impl<'de> Visitor<'de> for AnyPropVisiter {
type Value = Box<dyn Property>; type Value = Box<dyn Property>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
@ -159,62 +162,86 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
} }
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E> fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E> fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E> fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E> fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E> fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E> fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_string<E>(self, v: String) -> Result<Self::Value, E> fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v)) Ok(Box::new(v))
} }
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error { where
E: de::Error,
{
Ok(Box::new(v.to_string())) Ok(Box::new(v.to_string()))
} }
@ -223,11 +250,57 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
V: MapAccess<'de>, V: MapAccess<'de>,
{ {
let mut dynamic_properties = DynamicProperties::default(); let mut dynamic_properties = DynamicProperties::default();
// while let Some(key) = map.next_key()? { while let Some(key) = map.next_key()? {
// let prop = map.next_value()?; let prop = map.next_value::<Box<dyn Property>>()?;
// self.dynamic_properties.set_box(key, prop); if key == "type" {
// } dynamic_properties.type_name = prop
panic!("aaah"); .val::<String>()
// Ok(Box::new(dynamic_properties)) .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))
}
}
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<dyn Property> {
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)
} }
} }

View File

@ -7,3 +7,5 @@ mod dynamic_properties;
pub use property::*; pub use property::*;
pub use properties::*; pub use properties::*;
pub use dynamic_properties::*; pub use dynamic_properties::*;
pub use serde;

View File

@ -17,14 +17,7 @@ pub trait Properties {
panic!("prop does not exist: {}", name); 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 fn to_dynamic(&self) -> DynamicProperties
where
Self: 'static,
{ {
let mut dynamic_props = DynamicProperties::default(); let mut dynamic_props = DynamicProperties::default();
for (name, prop) in self.iter_props() { for (name, prop) in self.iter_props() {

View File

@ -1,27 +1,33 @@
use crate::Properties;
use serde::Serialize; use serde::Serialize;
use std::any::Any; 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(&self) -> &dyn Any;
fn any_mut(&mut self) -> &mut dyn Any; fn any_mut(&mut self) -> &mut dyn Any;
fn clone_prop(&self) -> Box<dyn Property>; fn clone_prop(&self) -> Box<dyn Property>;
fn set(&mut self, value: &dyn Property); fn set(&mut self, value: &dyn Property);
fn apply(&mut self, value: &dyn Property);
} }
erased_serde::serialize_trait_object!(Property); erased_serde::serialize_trait_object!(Property);
pub trait AsProperties {
fn as_properties(&self) -> Option<&dyn Properties>;
}
pub trait PropertyVal { pub trait PropertyVal {
fn val<T: 'static>(&self) -> Option<&T>; fn val<T: 'static>(&self) -> Option<&T>;
fn set_val<T: 'static>(&mut self, value: T); fn set_val<T: 'static>(&mut self, value: T);
} }
impl PropertyVal for dyn Property { impl PropertyVal for dyn Property {
// #[inline] #[inline]
default fn val<T: 'static>(&self) -> Option<&T> { default fn val<T: 'static>(&self) -> Option<&T> {
self.any().downcast_ref::<T>() self.any().downcast_ref::<T>()
} }
// #[inline] #[inline]
default fn set_val<T: 'static>(&mut self, value: T) { default fn set_val<T: 'static>(&mut self, value: T) {
if let Some(prop) = self.any_mut().downcast_mut::<T>() { if let Some(prop) = self.any_mut().downcast_mut::<T>() {
*prop = value; *prop = value;
@ -31,6 +37,17 @@ impl PropertyVal for dyn Property {
} }
} }
// TODO: remove specialization
impl<T> AsProperties for T
where
T: Clone + Serialize + Send + Sync + Any + 'static,
{
fn as_properties(&self) -> Option<&dyn Properties> {
None
}
}
impl<T> Property for T impl<T> Property for T
where where
T: Clone + Serialize + Send + Sync + Any + 'static, T: Clone + Serialize + Send + Sync + Any + 'static,
@ -39,14 +56,17 @@ where
default fn any(&self) -> &dyn Any { default fn any(&self) -> &dyn Any {
self self
} }
#[inline] #[inline]
default fn any_mut(&mut self) -> &mut dyn Any { default fn any_mut(&mut self) -> &mut dyn Any {
self self
} }
#[inline] #[inline]
default fn clone_prop(&self) -> Box<dyn Property> { default fn clone_prop(&self) -> Box<dyn Property> {
Box::new(self.clone()) Box::new(self.clone())
} }
#[inline] #[inline]
default fn set(&mut self, value: &dyn Property) { default fn set(&mut self, value: &dyn Property) {
if let Some(prop) = value.any().downcast_ref::<T>() { if let Some(prop) = value.any().downcast_ref::<T>() {
@ -55,6 +75,11 @@ where
panic!("prop value is not {}", std::any::type_name::<T>()); panic!("prop value is not {}", std::any::type_name::<T>());
} }
} }
#[inline]
default fn apply(&mut self, value: &dyn Property) {
self.set(value);
}
} }
impl Property for usize { impl Property for usize {
@ -347,7 +372,6 @@ impl Property for i8 {
} }
} }
impl Property for f32 { impl Property for f32 {
fn set(&mut self, value: &dyn Property) { fn set(&mut self, value: &dyn Property) {
let value = value.any(); let value = value.any();

View File

@ -17,22 +17,22 @@ pub struct Test {
a: usize, a: usize,
b: String, b: String,
c: f32, c: f32,
// nest: Nested, nest: Nested,
} }
// #[derive(Properties, Default, Clone)] #[derive(Properties, Default)]
// pub struct Nested { pub struct Nested {
// d: usize, d: usize,
// } }
fn setup() { fn setup() {
let mut test = Test { let mut test = Test {
a: 1, a: 1,
b: "hi".to_string(), b: "hi".to_string(),
c: 1.0, c: 1.0,
// nest: Nested { nest: Nested {
// d: 8, d: 8,
// } }
}; };
test.set_prop_val::<usize>("a", 2); test.set_prop_val::<usize>("a", 2);