Skip to main content

ferroui_base/data/core/plugins/
exception_validation_plugin.rs

1use super::{AccessorListener, DataValidationBase, IDataValidationPlugin, IPropertyAccessor};
2use crate::data::core::{ValueType, WeakValue};
3use crate::data::{BindingError, BindingErrorType, BindingNotification, BindingPriority};
4use crate::reactive::IDisposable;
5use crate::BoxedValue;
6use std::rc::{Rc, Weak};
7
8/// Validates properties that report errors by failing in their setter.
9pub struct ExceptionValidationPlugin;
10
11impl IDataValidationPlugin for ExceptionValidationPlugin {
12    fn match_(&self, _reference: &WeakValue, _member_name: &str) -> bool {
13        true
14    }
15
16    fn start(
17        &self,
18        _reference: &WeakValue,
19        _property_name: &str,
20        inner: Rc<dyn IPropertyAccessor>,
21    ) -> Rc<dyn IPropertyAccessor> {
22        Rc::new_cyclic(|this| Validator { this: this.clone(), validation: DataValidationBase::new(inner) })
23    }
24}
25
26struct Validator {
27    this: Weak<Validator>,
28    validation: DataValidationBase,
29}
30
31impl IDisposable for Validator {
32    fn dispose(&self) {
33        if self.validation.base.is_subscribed() {
34            self.unsubscribe();
35        }
36    }
37}
38
39impl IPropertyAccessor for Validator {
40    fn property_type(&self) -> Option<ValueType> {
41        self.validation.inner.property_type()
42    }
43
44    fn value(&self) -> Option<BoxedValue> {
45        self.validation.inner.value()
46    }
47
48    fn set_value(&self, value: Option<&BoxedValue>, priority: BindingPriority) -> Result<bool, BindingError> {
49        match self.validation.inner.set_value(value, priority) {
50            Ok(result) => Ok(result),
51            Err(error) => {
52                self.validation.base.publish_value(Some(Rc::new(BindingNotification::with_error(
53                    error,
54                    BindingErrorType::DataValidationError,
55                ))));
56                Ok(false)
57            }
58        }
59    }
60
61    fn subscribe(&self, listener: AccessorListener) {
62        self.validation.base.set_listener(listener);
63        let weak = self.this.clone();
64        self.validation.subscribe_core(Rc::new(move |value| {
65            if let Some(this) = weak.upgrade() {
66                this.validation.inner_value_changed(value);
67            }
68        }));
69    }
70
71    fn unsubscribe(&self) {
72        self.validation.unsubscribe_core();
73        self.validation.base.clear_listener();
74    }
75}