/*! This module enable runtime type information for the builtin items and property so that the viewer can handle them */ pub type FieldOffset = const_field_offset::FieldOffset; use core::convert::{TryFrom, TryInto}; use core::pin::Pin; macro_rules! declare_ValueType { ($($ty:ty),*) => { pub trait ValueType: 'static $(+ TryInto<$ty> + TryFrom<$ty>)* {} }; } declare_ValueType![ bool, u32, u64, i32, i64, f32, f64, crate::SharedString, crate::Resource, crate::Color, crate::PathData ]; pub trait PropertyInfo { fn get(&self, item: Pin<&Item>) -> Result; fn set( &self, item: Pin<&Item>, value: Value, animation: Option, ) -> Result<(), ()>; fn set_binding( &self, item: Pin<&Item>, binding: Box Value>, animation: Option, ) -> Result<(), ()>; /// The offset of the property in the item. /// The use of this is unsafe fn offset(&self) -> usize; /// Returns self. This is just a trick to get auto-deref specialization of /// MaybeAnimatedPropertyInfoWrapper working. fn as_property_info(&'static self) -> &'static dyn PropertyInfo where Self: Sized, { self } } impl PropertyInfo for FieldOffset> where Value: TryInto, T: TryInto, { fn get(&self, item: Pin<&Item>) -> Result { self.apply_pin(item).get().try_into().map_err(|_| ()) } fn set( &self, item: Pin<&Item>, value: Value, animation: Option, ) -> Result<(), ()> { if animation.is_some() { Err(()) } else { self.apply_pin(item).set(value.try_into().map_err(|_| ())?); Ok(()) } } fn set_binding( &self, item: Pin<&Item>, binding: Box Value>, animation: Option, ) -> Result<(), ()> { if animation.is_some() { Err(()) } else { self.apply_pin(item).set_binding(move || { binding().try_into().map_err(|_| ()).expect("binding was of the wrong type") }); Ok(()) } } fn offset(&self) -> usize { self.get_byte_offset() } } /// Wraper for a field offset that optonally implement PropertyInfo and uses /// the auto deref specialization trick #[derive(derive_more::Deref)] pub struct MaybeAnimatedPropertyInfoWrapper(pub FieldOffset); impl PropertyInfo for MaybeAnimatedPropertyInfoWrapper> where Value: TryInto, T: TryInto, T: crate::abi::properties::InterpolatedPropertyValue, { fn get(&self, item: Pin<&Item>) -> Result { self.0.get(item) } fn set( &self, item: Pin<&Item>, value: Value, animation: Option, ) -> Result<(), ()> { if let Some(animation) = &animation { self.apply_pin(item).set_animated_value(value.try_into().map_err(|_| ())?, animation); Ok(()) } else { self.0.set(item, value, None) } } fn set_binding( &self, item: Pin<&Item>, binding: Box Value>, animation: Option, ) -> Result<(), ()> { if let Some(animation) = &animation { self.apply_pin(item).set_animated_binding( move || { binding().try_into().map_err(|_| ()).expect("binding was of the wrong type") }, animation, ); Ok(()) } else { self.0.set_binding(item, binding, None) } } fn offset(&self) -> usize { self.get_byte_offset() } } pub trait FieldInfo { fn set_field(&self, item: &mut Item, value: Value) -> Result<(), ()>; } impl FieldInfo for FieldOffset where Value: TryInto, T: TryInto, { fn set_field(&self, item: &mut Item, value: Value) -> Result<(), ()> { *self.apply_mut(item) = value.try_into().map_err(|_| ())?; Ok(()) } } pub trait BuiltinItem: Sized { fn name() -> &'static str; fn properties() -> Vec<(&'static str, &'static dyn PropertyInfo)>; fn fields() -> Vec<(&'static str, &'static dyn FieldInfo)>; fn signals() -> Vec<(&'static str, FieldOffset>)>; }