mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
props: support nesting
This commit is contained in:
parent
284afd4f94
commit
f36a67ee96
6 changed files with 202 additions and 58 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String> = None;
|
||||
while let Some(key) = map.next_key::<String>()? {
|
||||
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<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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,6 @@ mod dynamic_properties;
|
|||
|
||||
pub use property::*;
|
||||
pub use properties::*;
|
||||
pub use dynamic_properties::*;
|
||||
pub use dynamic_properties::*;
|
||||
|
||||
pub use serde;
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
@ -372,4 +396,4 @@ impl Property for f64 {
|
|||
panic!("prop value is not {}", std::any::type_name::<Self>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue