/*! 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 std::convert::{TryFrom, TryInto}; 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]; pub enum PropertyInfoOption<'a, Item, Value> { SimpleProperty(&'a dyn PropertyInfo), AnimatedProperty(&'a dyn AnimatedPropertyInfo), } impl<'a, Item, Value> PropertyInfoOption<'a, Item, Value> { pub fn get(&self, item: &Item, context: &crate::EvaluationContext) -> Result { match self { PropertyInfoOption::SimpleProperty(pi) => pi.get(item, context), PropertyInfoOption::AnimatedProperty(pi) => pi.get(item, context), } } pub fn set(&self, item: &Item, value: Value) -> Result<(), ()> { match self { PropertyInfoOption::SimpleProperty(pi) => pi.set(item, value), PropertyInfoOption::AnimatedProperty(pi) => pi.set(item, value), } } pub fn set_binding( &self, item: &Item, binding: Box Value>, ) { match self { PropertyInfoOption::SimpleProperty(pi) => pi.set_binding(item, binding), PropertyInfoOption::AnimatedProperty(pi) => pi.set_binding(item, binding), } } pub fn set_animated_value( &self, item: &Item, value: Value, animation: &crate::abi::primitives::PropertyAnimation, ) -> Result<(), ()> { match self { PropertyInfoOption::SimpleProperty(_) => Err(()), PropertyInfoOption::AnimatedProperty(pi) => { pi.set_animated_value(item, value, animation) } } } pub fn set_animated_binding( &self, item: &Item, binding: Box Value>, animation: &crate::abi::primitives::PropertyAnimation, ) -> bool { match self { PropertyInfoOption::SimpleProperty(_) => false, PropertyInfoOption::AnimatedProperty(pi) => { pi.set_animated_binding(item, binding, animation); true } } } /// The offset of the property in the item. /// The use of this is unsafe pub fn offset(&self) -> usize { match self { PropertyInfoOption::SimpleProperty(pi) => pi.offset(), PropertyInfoOption::AnimatedProperty(pi) => pi.offset(), } } } pub trait PropertyInfo { fn get(&self, item: &Item, context: &crate::EvaluationContext) -> Result; fn set(&self, item: &Item, value: Value) -> Result<(), ()>; fn set_binding(&self, item: &Item, binding: Box Value>); /// The offset of the property in the item. /// The use of this is unsafe fn offset(&self) -> usize; } pub trait AnimatedPropertyInfo: PropertyInfo { fn set_animated_value( &self, item: &Item, value: Value, animation: &crate::abi::primitives::PropertyAnimation, ) -> Result<(), ()>; fn set_animated_binding( &self, item: &Item, binding: Box Value>, animation: &crate::abi::primitives::PropertyAnimation, ); } impl PropertyInfo for FieldOffset> where Value: TryInto, T: TryInto, { fn get(&self, item: &Item, context: &crate::EvaluationContext) -> Result { self.apply(item).get(context).try_into().map_err(|_| ()) } fn set(&self, item: &Item, value: Value) -> Result<(), ()> { self.apply(item).set(value.try_into().map_err(|_| ())?); Ok(()) } fn set_binding(&self, item: &Item, binding: Box Value>) { self.apply(item).set_binding(move |context| { binding(context).try_into().map_err(|_| ()).expect("binding was of the wrong type") }); } fn offset(&self) -> usize { self.get_byte_offset() } } impl AnimatedPropertyInfo for FieldOffset> where Value: TryInto, T: TryInto, T: crate::abi::properties::InterpolatedPropertyValue, { fn set_animated_value( &self, item: &Item, value: Value, animation: &crate::abi::primitives::PropertyAnimation, ) -> Result<(), ()> { self.apply(item).set_animated_value(value.try_into().map_err(|_| ())?, animation); Ok(()) } fn set_animated_binding( &self, item: &Item, binding: Box Value>, animation: &crate::abi::primitives::PropertyAnimation, ) { self.apply(item).set_animated_binding( move |context| { binding(context).try_into().map_err(|_| ()).expect("binding was of the wrong type") }, animation, ); } } pub trait BuiltinItem: Sized { fn name() -> &'static str; fn properties( ) -> Vec<(&'static str, PropertyInfoOption<'static, Self, Value>)>; fn signals() -> Vec<(&'static str, FieldOffset>)>; }