use crate::Properties; use std::any::Any; pub trait Property: erased_serde::Serialize + Send + Sync + Any + 'static { fn type_name(&self) -> &str; 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); fn as_properties(&self) -> Option<&dyn Properties> { None } fn is_sequence(&self) -> bool { false } } erased_serde::serialize_trait_object!(Property); pub trait PropertyVal { fn val(&self) -> Option<&T>; fn set_val(&mut self, value: T); } impl PropertyVal for dyn Property { #[inline] fn val(&self) -> Option<&T> { self.any().downcast_ref::() } #[inline] fn set_val(&mut self, value: T) { if let Some(prop) = self.any_mut().downcast_mut::() { *prop = value; } else { panic!("prop value is not {}", std::any::type_name::()); } } } // used by impl_property #[allow(unused_macros)] macro_rules! as_item { ($i:item) => { $i }; } #[macro_export] macro_rules! impl_property { ($ty:ident) => { impl Property for $ty { #[inline] fn type_name(&self) -> &str { std::any::type_name::() } #[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.clone()) } #[inline] fn apply(&mut self, value: &dyn Property) { self.set(value); } fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { *self = prop.clone(); } else { panic!("prop value is not {}", std::any::type_name::()); } } } }; (SEQUENCE, @$trait_:ident [$($args:ident,)*] where [$($preds:tt)+]) => { impl_property! { @as_item impl<$($args),*> Property for $trait_<$($args),*> where $($args: ::std::any::Any + 'static,)* $($preds)* { #[inline] fn type_name(&self) -> &str { std::any::type_name::() } #[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.clone()) } #[inline] fn apply(&mut self, value: &dyn Property) { self.set(value); } fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { *self = prop.clone(); } else { panic!("prop value is not {}", std::any::type_name::()); } } fn is_sequence(&self) -> bool { true } } } }; (@$trait_:ident [$($args:ident,)*] where [$($preds:tt)+]) => { impl_property! { @as_item impl<$($args),*> Property for $trait_<$($args),*> where $($args: ::std::any::Any + 'static,)* $($preds)* { #[inline] fn type_name(&self) -> &str { std::any::type_name::() } #[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.clone()) } #[inline] fn apply(&mut self, value: &dyn Property) { self.set(value); } fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { *self = prop.clone(); } else { panic!("prop value is not {}", std::any::type_name::()); } } } } }; (@as_item $i:item) => { $i }; ( SEQUENCE, $trait_:ident < $($args:ident),* $(,)* > where $($preds:tt)+ ) => { impl_property! {SEQUENCE, @$trait_ [$($args,)*] where [$($preds)*] } }; ( $trait_:ident < $($args:ident),* $(,)* > where $($preds:tt)+ ) => { impl_property! { @$trait_ [$($args,)*] where [$($preds)*] } }; }