ferroui_base/data/
indexer_descriptor.rs1use crate::data::{BindingMode, BindingPriority};
2use crate::reactive::{IDisposable, IObservable, IObserver};
3use crate::{BoxedValue, FerroObject, FerroObjectExtensions, FerroProperty, Ref};
4use std::rc::Rc;
5
6#[derive(Clone, Default)]
10pub struct IndexerDescriptor {
11 pub mode: BindingMode,
13 pub priority: BindingPriority,
15 pub property: Option<&'static FerroProperty>,
17 pub source: Option<Ref<FerroObject>>,
19 pub source_observable: Option<Rc<dyn IObservable<BoxedValue>>>,
21}
22
23impl IndexerDescriptor {
24 pub fn new() -> Self {
26 Self::default()
27 }
28
29 pub fn description(&self) -> String {
31 format!(
32 "{}.{}",
33 self.source.as_ref().map_or("", |s| s.get_type().name()),
34 self.property.map_or("", |p| p.name())
35 )
36 }
37
38 pub fn with_mode(mut self, mode: BindingMode) -> Self {
40 self.mode = mode;
41 self
42 }
43
44 pub fn with_priority(mut self, priority: BindingPriority) -> Self {
46 self.priority = priority;
47 self
48 }
49}
50
51impl std::ops::Not for IndexerDescriptor {
53 type Output = IndexerDescriptor;
54
55 fn not(self) -> IndexerDescriptor {
56 self.with_mode(BindingMode::TwoWay)
57 }
58}
59
60impl IObservable<BoxedValue> for IndexerDescriptor {
61 fn subscribe(&self, observer: Rc<dyn IObserver<BoxedValue>>) -> Rc<dyn IDisposable> {
64 if self.source_observable.is_none() && self.source.is_none() {
65 panic!("Cannot subscribe to IndexerDescriptor.");
66 }
67 let Some(property) = self.property else {
68 panic!("Cannot subscribe to IndexerDescriptor.");
69 };
70 match (&self.source_observable, &self.source) {
71 (Some(observable), _) => observable.subscribe(observer),
72 (None, Some(source)) => source.get_observable_untyped(property).subscribe(observer),
73 (None, None) => unreachable!("checked above"),
74 }
75 }
76}
77
78impl FerroProperty {
79 pub fn bind(&'static self) -> IndexerDescriptor {
85 IndexerDescriptor { priority: BindingPriority::LocalValue, property: Some(self), ..IndexerDescriptor::default() }
86 }
87}