ferroui_base/data/core/
i_property_info.rs1use super::plugins::{get_property_value, property_value_type, set_property_value};
2use super::{ValueType, ValueTypes};
3use crate::data::{BindingError, BindingPriority};
4use crate::{AnyValue, BoxedValue, FerroObject, FerroProperty, FerroPropertyRegistry, Ref};
5
6pub trait IPropertyInfo {
9 fn name(&self) -> &str;
11
12 fn get(&self, target: &dyn AnyValue) -> Option<BoxedValue>;
14
15 fn try_get(&self, target: &dyn AnyValue) -> Result<Option<BoxedValue>, BindingError> {
19 Ok(self.get(target))
20 }
21
22 fn set(&self, target: &dyn AnyValue, value: Option<&BoxedValue>) -> Result<(), BindingError>;
25
26 fn can_set(&self) -> bool;
27
28 fn can_get(&self) -> bool;
29
30 fn property_type(&self) -> ValueType;
32
33 fn as_any(&self) -> Option<&dyn std::any::Any> {
37 None
38 }
39
40 fn get_boxed(&self, target: &BoxedValue) -> Option<BoxedValue> {
46 self.get(&**target)
47 }
48
49 fn try_get_boxed(&self, target: &BoxedValue) -> Result<Option<BoxedValue>, BindingError> {
51 self.try_get(&**target)
52 }
53
54 fn set_boxed(&self, target: &BoxedValue, value: Option<&BoxedValue>) -> Result<(), BindingError> {
56 self.set(&**target, value)
57 }
58
59 fn as_ferro_property(&self) -> Option<&'static FerroProperty> {
62 None
63 }
64}
65
66impl IPropertyInfo for FerroProperty {
69 fn as_any(&self) -> Option<&dyn std::any::Any> {
70 Some(self)
71 }
72
73 fn name(&self) -> &str {
74 FerroProperty::name(self)
75 }
76
77 fn get(&self, target: &dyn AnyValue) -> Option<BoxedValue> {
79 match self.try_get(target) {
80 Ok(value) => value,
81 Err(error) => panic!("{error}"),
82 }
83 }
84
85 fn try_get(&self, target: &dyn AnyValue) -> Result<Option<BoxedValue>, BindingError> {
86 let object = target_object(self, target)?;
87 Ok(get_property_value(&object, registered(self)))
88 }
89
90 fn set(&self, target: &dyn AnyValue, value: Option<&BoxedValue>) -> Result<(), BindingError> {
91 let object = target_object(self, target)?;
92 set_property_value(&object, registered(self), value, BindingPriority::LocalValue)
93 }
94
95 fn can_set(&self) -> bool {
96 !self.is_read_only()
97 }
98
99 fn can_get(&self) -> bool {
100 true
101 }
102
103 fn property_type(&self) -> ValueType {
104 property_value_type(self)
105 }
106
107 fn as_ferro_property(&self) -> Option<&'static FerroProperty> {
108 Some(registered(self))
109 }
110}
111
112struct RegisteredPropertyInfo(&'static FerroProperty);
115
116impl IPropertyInfo for RegisteredPropertyInfo {
117 fn name(&self) -> &str {
118 FerroProperty::name(self.0)
119 }
120
121 fn get(&self, target: &dyn AnyValue) -> Option<BoxedValue> {
122 IPropertyInfo::get(self.0, target)
123 }
124
125 fn try_get(&self, target: &dyn AnyValue) -> Result<Option<BoxedValue>, BindingError> {
126 IPropertyInfo::try_get(self.0, target)
127 }
128
129 fn set(&self, target: &dyn AnyValue, value: Option<&BoxedValue>) -> Result<(), BindingError> {
130 IPropertyInfo::set(self.0, target, value)
131 }
132
133 fn can_set(&self) -> bool {
134 IPropertyInfo::can_set(self.0)
135 }
136
137 fn can_get(&self) -> bool {
138 IPropertyInfo::can_get(self.0)
139 }
140
141 fn property_type(&self) -> ValueType {
142 IPropertyInfo::property_type(self.0)
143 }
144
145 fn as_ferro_property(&self) -> Option<&'static FerroProperty> {
146 Some(self.0)
147 }
148}
149
150impl FerroProperty {
151 pub fn as_property_info(&'static self) -> std::rc::Rc<dyn IPropertyInfo> {
156 std::rc::Rc::new(RegisteredPropertyInfo(self))
157 }
158}
159
160fn registered(property: &FerroProperty) -> &'static FerroProperty {
162 FerroPropertyRegistry::instance()
163 .find_registered_by_id(property.id())
164 .expect("a property definition is registered when it is created")
165}
166
167fn target_object(property: &FerroProperty, target: &dyn AnyValue) -> Result<Ref<FerroObject>, BindingError> {
168 ValueTypes::as_object(target).ok_or_else(|| {
169 BindingError::message(format!(
170 "Unable to access Property '{}': the target ({}) is not an object.",
171 property.name(),
172 target.type_name()
173 ))
174 })
175}
176
177impl PartialEq for dyn IPropertyInfo {
180 #[inline]
181 fn eq(&self, other: &Self) -> bool {
182 std::ptr::addr_eq(self as *const Self, other as *const Self)
183 }
184}