ferroui_base/
ferro_property_metadata.rs1use crate::data::BindingMode;
2use crate::{FerroObject, TypeInfo};
3use std::cell::RefCell;
4use std::rc::Rc;
5
6#[derive(Clone, Debug)]
8pub struct FerroPropertyMetadata {
9 default_binding_mode: BindingMode,
10 enable_data_validation: Option<bool>,
11 is_read_only: bool,
12}
13
14impl FerroPropertyMetadata {
15 pub fn new(default_binding_mode: BindingMode, enable_data_validation: Option<bool>) -> Self {
16 Self { default_binding_mode, enable_data_validation, is_read_only: false }
17 }
18
19 pub fn default_binding_mode(&self) -> BindingMode {
21 if self.default_binding_mode == BindingMode::Default {
22 BindingMode::OneWay
23 } else {
24 self.default_binding_mode
25 }
26 }
27
28 pub fn enable_data_validation(&self) -> Option<bool> {
34 self.enable_data_validation
35 }
36
37 pub fn is_read_only(&self) -> bool {
39 self.is_read_only
40 }
41
42 pub fn merge(&mut self, base: &FerroPropertyMetadata) {
44 assert!(!self.is_read_only, "The metadata is read-only.");
45 if self.default_binding_mode == BindingMode::Default {
46 self.default_binding_mode = base.default_binding_mode();
47 }
48 if self.enable_data_validation.is_none() {
49 self.enable_data_validation = base.enable_data_validation;
50 }
51 }
52
53 pub fn freeze(&mut self) {
55 self.is_read_only = true;
56 }
57}
58
59pub type CoerceValueCallback<T> = Rc<dyn Fn(&FerroObject, T) -> T>;
61
62pub struct StyledPropertyMetadata<T> {
64 base: FerroPropertyMetadata,
65 default_value: Option<T>,
66 coerce: Option<CoerceValueCallback<T>>,
67}
68
69impl<T: Clone> Clone for StyledPropertyMetadata<T> {
70 fn clone(&self) -> Self {
71 Self { base: self.base.clone(), default_value: self.default_value.clone(), coerce: self.coerce.clone() }
72 }
73}
74
75impl<T> std::ops::Deref for StyledPropertyMetadata<T> {
76 type Target = FerroPropertyMetadata;
77 fn deref(&self) -> &FerroPropertyMetadata {
78 &self.base
79 }
80}
81
82impl<T: Clone + 'static> StyledPropertyMetadata<T> {
83 pub fn new(default_value: Option<T>) -> Self {
86 Self {
87 base: FerroPropertyMetadata::new(BindingMode::Default, Some(false)),
88 default_value,
89 coerce: None,
90 }
91 }
92
93 pub fn with_default_binding_mode(mut self, mode: BindingMode) -> Self {
94 self.base.default_binding_mode = mode;
95 self
96 }
97
98 pub fn with_coerce(mut self, coerce: impl Fn(&FerroObject, T) -> T + 'static) -> Self {
99 self.coerce = Some(Rc::new(coerce));
100 self
101 }
102
103 pub fn with_enable_data_validation(mut self, enable: bool) -> Self {
104 self.base.enable_data_validation = Some(enable);
105 self
106 }
107
108 #[inline]
111 pub fn default_value(&self) -> &T {
112 self.default_value.as_ref().expect("metadata has no default value")
113 }
114
115 pub(crate) fn has_default_value(&self) -> bool {
116 self.default_value.is_some()
117 }
118
119 #[inline]
121 pub fn coerce_value(&self) -> Option<&CoerceValueCallback<T>> {
122 self.coerce.as_ref()
123 }
124}
125
126#[derive(Clone)]
128pub struct DirectPropertyMetadata<T> {
129 base: FerroPropertyMetadata,
130 unset_value: Option<T>,
131}
132
133impl<T> std::ops::Deref for DirectPropertyMetadata<T> {
134 type Target = FerroPropertyMetadata;
135 fn deref(&self) -> &FerroPropertyMetadata {
136 &self.base
137 }
138}
139
140impl<T: Clone + 'static> DirectPropertyMetadata<T> {
141 pub fn new(unset_value: Option<T>) -> Self {
142 Self { base: FerroPropertyMetadata::new(BindingMode::Default, None), unset_value }
143 }
144
145 pub fn with_default_binding_mode(mut self, mode: BindingMode) -> Self {
146 self.base.default_binding_mode = mode;
147 self
148 }
149
150 pub fn with_enable_data_validation(mut self, enable: bool) -> Self {
151 self.base.enable_data_validation = Some(enable);
152 self
153 }
154
155 #[inline]
157 pub fn unset_value(&self) -> &T {
158 self.unset_value.as_ref().expect("metadata has no unset value")
159 }
160}
161
162pub trait PropertyMetadata: Sized + 'static {
165 fn base(&self) -> &FerroPropertyMetadata;
166 fn merge(&mut self, base: &Self);
167 fn freeze(&mut self);
168 fn generate_type_safe_metadata(this: &Rc<Self>) -> Rc<Self>;
171}
172
173impl<T: Clone + 'static> PropertyMetadata for StyledPropertyMetadata<T> {
174 fn base(&self) -> &FerroPropertyMetadata {
175 &self.base
176 }
177
178 fn merge(&mut self, base: &Self) {
179 self.base.merge(&base.base);
180 if self.default_value.is_none() {
181 self.default_value = base.default_value.clone();
182 }
183 if self.coerce.is_none() {
184 self.coerce = base.coerce.clone();
185 }
186 }
187
188 fn freeze(&mut self) {
189 self.base.freeze();
190 }
191
192 fn generate_type_safe_metadata(this: &Rc<Self>) -> Rc<Self> {
193 if this.is_read_only() && this.coerce.is_none() {
194 return this.clone();
195 }
196 let mut copy = StyledPropertyMetadata::new(this.default_value.clone())
197 .with_default_binding_mode(this.default_binding_mode())
198 .with_enable_data_validation(this.enable_data_validation().unwrap_or(false));
199 copy.freeze();
200 Rc::new(copy)
201 }
202}
203
204impl<T: Clone + 'static> PropertyMetadata for DirectPropertyMetadata<T> {
205 fn base(&self) -> &FerroPropertyMetadata {
206 &self.base
207 }
208
209 fn merge(&mut self, base: &Self) {
210 self.base.merge(&base.base);
211 if self.unset_value.is_none() {
212 self.unset_value = base.unset_value.clone();
213 }
214 }
215
216 fn freeze(&mut self) {
217 self.base.freeze();
218 }
219
220 fn generate_type_safe_metadata(this: &Rc<Self>) -> Rc<Self> {
221 this.clone()
222 }
223}
224
225pub(crate) struct MetadataTable<M> {
229 default_metadata: Rc<M>,
230 inner: RefCell<TableInner<M>>,
231}
232
233struct TableInner<M> {
234 single: Option<(&'static TypeInfo, Rc<M>)>,
236 metadata: Vec<(&'static TypeInfo, Rc<M>)>,
237 cache: Vec<(&'static TypeInfo, Rc<M>)>,
238}
239
240impl<M: PropertyMetadata> MetadataTable<M> {
241 pub fn new(host_type: &'static TypeInfo, mut metadata: M) -> Self {
242 metadata.freeze();
243 let metadata = Rc::new(metadata);
244 let default_metadata = M::generate_type_safe_metadata(&metadata);
245 Self {
246 default_metadata,
247 inner: RefCell::new(TableInner {
248 single: Some((host_type, metadata.clone())),
249 metadata: vec![(host_type, metadata)],
250 cache: Vec::new(),
251 }),
252 }
253 }
254
255 pub fn for_added_owner(source: &Self, owner_type: &'static TypeInfo, metadata: Option<M>) -> Self {
258 let mut entries = Vec::new();
259 if let Some(m) = metadata {
260 entries.push((owner_type, Rc::new(m)));
261 }
262 Self {
263 default_metadata: source.default_metadata.clone(),
264 inner: RefCell::new(TableInner { single: None, metadata: entries, cache: Vec::new() }),
265 }
266 }
267
268 #[inline]
269 pub fn default_metadata(&self) -> &Rc<M> {
270 &self.default_metadata
271 }
272
273 pub fn get(&self, type_: &'static TypeInfo) -> Rc<M> {
274 let mut inner = self.inner.borrow_mut();
275 if let Some((host, single)) = &inner.single {
276 if Rc::ptr_eq(single, &self.default_metadata) {
277 return self.default_metadata.clone();
278 }
279 return if host.is_assignable_from(type_) { single.clone() } else { self.default_metadata.clone() };
280 }
281 if let Some((_, m)) = inner.cache.iter().find(|(t, _)| std::ptr::eq(*t, type_)) {
282 return m.clone();
283 }
284 let mut current = Some(type_);
285 let mut result = None;
286 while let Some(t) = current {
287 if let Some((_, m)) = inner.metadata.iter().find(|(mt, _)| std::ptr::eq(*mt, t)) {
288 result = Some(m.clone());
289 break;
290 }
291 current = t.base_type();
292 }
293 let result = result.unwrap_or_else(|| self.default_metadata.clone());
294 inner.cache.push((type_, result.clone()));
295 result
296 }
297
298 pub fn override_metadata(&self, property_name: &str, type_: &'static TypeInfo, mut metadata: M) {
299 let already_set = self.inner.borrow().metadata.iter().any(|(t, _)| std::ptr::eq(*t, type_));
300 if already_set {
301 panic!("Metadata is already set for {property_name} on {type_}.");
302 }
303 let base = self.get(type_);
304 metadata.merge(&base);
305 metadata.freeze();
306 let mut inner = self.inner.borrow_mut();
307 inner.metadata.push((type_, Rc::new(metadata)));
308 inner.cache.clear();
309 inner.single = None;
310 }
311
312 pub fn unregister(&self, type_: &'static TypeInfo) {
313 let mut inner = self.inner.borrow_mut();
314 inner.metadata.retain(|(t, _)| !std::ptr::eq(*t, type_));
315 inner.cache.retain(|(t, _)| !std::ptr::eq(*t, type_));
316 inner.single = None;
317 }
318}