ferroui_base/controls/
i_name_scope.rs1use crate::utilities::{SynchronousCompletionAsyncResult, SynchronousCompletionAsyncResultSource};
2use crate::data::core::ValueTypes;
3use crate::{BoxedValue, FerroObject, Ref};
4use std::ops::Deref;
5use std::rc::Rc;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
9pub enum NameScopeError {
10 Completed,
12 DuplicateName(String),
14}
15
16impl std::fmt::Display for NameScopeError {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 match self {
19 Self::Completed => f.write_str("NameScope is completed, no further registrations are allowed"),
20 Self::DuplicateName(name) => write!(f, "Control with the name '{name}' already registered."),
21 }
22 }
23}
24
25impl std::error::Error for NameScopeError {}
26
27#[derive(Clone, Debug, PartialEq, Eq)]
31pub enum NameScopeValueError {
32 Completed,
34 DuplicateName(String),
36 UnsupportedValue,
39 NullValue,
41}
42
43impl std::fmt::Display for NameScopeValueError {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 match self {
46 Self::Completed => NameScopeError::Completed.fmt(f),
47 Self::DuplicateName(name) => NameScopeError::DuplicateName(name.clone()).fmt(f),
48 Self::NullValue => f.write_str("Value cannot be null. (Parameter 'element')"),
49 Self::UnsupportedValue => f.write_str("This custom name scope only supports native objects."),
50 }
51 }
52}
53
54impl std::error::Error for NameScopeValueError {}
55
56impl From<NameScopeError> for NameScopeValueError {
57 fn from(error: NameScopeError) -> Self {
58 match error {
59 NameScopeError::Completed => Self::Completed,
60 NameScopeError::DuplicateName(name) => Self::DuplicateName(name),
61 }
62 }
63}
64
65pub trait INameScope {
67 fn try_register_value(&self, name: &str, value: BoxedValue) -> Result<(), NameScopeValueError> {
71 if self.is_completed() {
72 return Err(NameScopeValueError::Completed);
73 }
74 let value = ValueTypes::normalize(value).ok_or(NameScopeValueError::NullValue)?;
75 let element = ValueTypes::as_object(&*value).ok_or(NameScopeValueError::UnsupportedValue)?;
76 Ok(self.try_register(name, element)?)
77 }
78
79 fn register_value(&self, name: &str, value: BoxedValue) {
81 if let Err(error) = self.try_register_value(name, value) {
82 panic!("{error}");
83 }
84 }
85
86 fn find_value(&self, name: &str) -> Option<BoxedValue> {
88 self.find(name).map(|element| Rc::new(element) as BoxedValue)
89 }
90
91 fn find_value_async(&self, name: &str) -> SynchronousCompletionAsyncResult<Option<BoxedValue>> {
93 map_result(self.find_async(name), |element| element.map(|element| Rc::new(element) as BoxedValue))
94 }
95
96 fn register(&self, name: &str, element: Ref<FerroObject>) {
101 if let Err(error) = self.try_register(name, element) {
102 panic!("{error}");
103 }
104 }
105
106 fn try_register(&self, name: &str, element: Ref<FerroObject>) -> Result<(), NameScopeError>;
110
111 fn find_async(&self, name: &str) -> SynchronousCompletionAsyncResult<Option<Ref<FerroObject>>>;
115
116 fn find(&self, name: &str) -> Option<Ref<FerroObject>>;
119
120 fn complete(&self);
123
124 fn is_completed(&self) -> bool;
127
128 fn attached_to(&self, _owner: &Ref<FerroObject>) {}
135
136 fn detached_from(&self, _owner: &Ref<FerroObject>) {}
139}
140
141pub(crate) fn map_result<T: Clone + 'static, U: Clone + 'static>(
143 result: SynchronousCompletionAsyncResult<T>,
144 map: impl FnOnce(T) -> U + 'static,
145) -> SynchronousCompletionAsyncResult<U> {
146 if result.is_completed() {
147 return SynchronousCompletionAsyncResult::new(map(result.get_result()));
148 }
149 let source = SynchronousCompletionAsyncResultSource::new();
150 let output = source.async_result();
151 let pending = result.clone();
152 result.on_completed(move || source.set_result(map(pending.get_result())));
153 output
154}
155
156#[derive(Clone)]
159pub struct NameScopeRef(pub Rc<dyn INameScope>);
160
161impl NameScopeRef {
162 pub fn new(scope: impl INameScope + 'static) -> Self {
163 NameScopeRef(Rc::new(scope))
164 }
165}
166
167impl Deref for NameScopeRef {
168 type Target = dyn INameScope;
169
170 fn deref(&self) -> &(dyn INameScope + 'static) {
171 &*self.0
172 }
173}
174
175impl PartialEq for NameScopeRef {
176 fn eq(&self, other: &Self) -> bool {
177 std::ptr::addr_eq(Rc::as_ptr(&self.0), Rc::as_ptr(&other.0))
178 }
179}
180
181impl From<Rc<dyn INameScope>> for NameScopeRef {
182 fn from(value: Rc<dyn INameScope>) -> Self {
183 NameScopeRef(value)
184 }
185}
186
187impl PartialEq for dyn INameScope {
190 #[inline]
191 fn eq(&self, other: &Self) -> bool {
192 std::ptr::addr_eq(self as *const Self, other as *const Self)
193 }
194}