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)
}
}
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::{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 {
@ -151,7 +155,6 @@ impl<'de> Deserialize<'de> for Box<dyn Property> {
struct AnyPropVisiter;
impl<'de> Visitor<'de> for AnyPropVisiter {
type Value = Box<dyn Property>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
@ -159,63 +162,87 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v))
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error {
Ok(Box::new(v.to_string()))
where
E: de::Error,
{
Ok(Box::new(v.to_string()))
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
@ -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::<Box<dyn Property>>()?;
if key == "type" {
dynamic_properties.type_name = prop
.val::<String>()
.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 properties::*;
pub use dynamic_properties::*;
pub use serde;

View file

@ -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() {

View file

@ -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<dyn Property>;
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<T: 'static>(&self) -> Option<&T>;
fn set_val<T: 'static>(&mut self, value: T);
}
impl PropertyVal for dyn Property {
// #[inline]
#[inline]
default fn val<T: 'static>(&self) -> Option<&T> {
self.any().downcast_ref::<T>()
}
// #[inline]
#[inline]
default fn set_val<T: 'static>(&mut self, value: T) {
if let Some(prop) = self.any_mut().downcast_mut::<T>() {
*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
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<dyn Property> {
Box::new(self.clone())
}
#[inline]
default fn set(&mut self, value: &dyn Property) {
if let Some(prop) = value.any().downcast_ref::<T>() {
@ -55,6 +75,11 @@ where
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 {
@ -347,7 +372,6 @@ impl Property for i8 {
}
}
impl Property for f32 {
fn set(&mut self, value: &dyn Property) {
let value = value.any();

View file

@ -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::<usize>("a", 2);