1use super::{CollectionChange, Event, INotifyCollectionChanged, INotifyPropertyChanged, ModelTypes};
2use crate::collections::{FerroDictionary, NotifyCollectionChangedEventArgs};
3use crate::data::core::{PropertyKind, Value, ValueType};
4use crate::data::BindingError;
5use crate::{BoxedValue, PropertyValue};
6use std::any::TypeId;
7use std::cell::{OnceCell, RefCell};
8use std::fmt::Display;
9use std::hash::Hash;
10use std::rc::Rc;
11
12pub trait IBindableIndexer {
24 fn index_parameter_types(&self) -> Vec<ValueType>;
26
27 fn value_type(&self) -> ValueType;
29
30 fn can_set(&self) -> bool {
32 true
33 }
34
35 fn get(&self, arguments: &[BoxedValue]) -> Result<Option<BoxedValue>, BindingError>;
39
40 fn set(&self, arguments: &[BoxedValue], value: Option<&BoxedValue>) -> Result<bool, BindingError>;
43}
44
45pub trait IBindableArray {
48 fn rank(&self) -> usize;
50
51 fn element_type(&self) -> ValueType;
53
54 fn get_value(&self, indexes: &[i32]) -> Result<Option<BoxedValue>, BindingError>;
56
57 fn set_value(&self, indexes: &[i32], value: Option<&BoxedValue>) -> Result<(), BindingError>;
59}
60
61fn invalid_value(value: Option<&BoxedValue>, target: ValueType) -> BindingError {
62 BindingError::message(format!(
63 "Object of type '{}' cannot be converted to type '{}'.",
64 value.map_or("null", |v| (**v).type_name()),
65 target
66 ))
67}
68
69fn argument<'a, T: 'static>(arguments: &'a [BoxedValue], index: usize) -> Result<&'a T, BindingError> {
70 arguments.get(index).and_then(|a| a.downcast_ref::<T>()).ok_or_else(|| {
71 BindingError::message(format!(
72 "Object of type '{}' cannot be converted to type '{}'.",
73 arguments.get(index).map_or("null", |v| (**v).type_name()),
74 std::any::type_name::<T>()
75 ))
76 })
77}
78
79pub struct BindableArray<T: PropertyValue> {
84 items: RefCell<Vec<T>>,
85 lengths: Vec<usize>,
86}
87
88impl<T: PropertyValue> BindableArray<T> {
89 pub fn new(items: impl IntoIterator<Item = T>) -> Rc<Self> {
91 let items: Vec<T> = items.into_iter().collect();
92 let lengths = vec![items.len()];
93 Self::create(items, lengths)
94 }
95
96 pub fn with_lengths(lengths: &[usize], items: impl IntoIterator<Item = T>) -> Rc<Self> {
100 let items: Vec<T> = items.into_iter().collect();
101 if lengths.is_empty() || lengths.iter().product::<usize>() != items.len() {
102 panic!("The number of elements does not match the lengths of the array.");
103 }
104 Self::create(items, lengths.to_vec())
105 }
106
107 fn create(items: Vec<T>, lengths: Vec<usize>) -> Rc<Self> {
108 if !ModelTypes::is_registered(TypeId::of::<Self>()) {
109 ModelTypes::register::<Self>(|b| b.array().indexer());
110 }
111 Rc::new(Self { items: RefCell::new(items), lengths })
112 }
113
114 pub fn lengths(&self) -> &[usize] {
116 &self.lengths
117 }
118
119 pub fn len(&self) -> usize {
121 self.items.borrow().len()
122 }
123
124 pub fn is_empty(&self) -> bool {
125 self.len() == 0
126 }
127
128 pub fn get(&self, indexes: &[usize]) -> T {
130 let offset = self.offset(indexes).expect("Index was outside the bounds of the array.");
131 self.items.borrow()[offset].clone()
132 }
133
134 pub fn set(&self, indexes: &[usize], value: T) {
136 let offset = self.offset(indexes).expect("Index was outside the bounds of the array.");
137 self.items.borrow_mut()[offset] = value;
138 }
139
140 pub fn to_vec(&self) -> Vec<T> {
142 self.items.borrow().clone()
143 }
144
145 fn offset(&self, indexes: &[usize]) -> Option<usize> {
146 if indexes.len() != self.lengths.len() {
147 return None;
148 }
149 let mut offset = 0;
150 for (index, length) in indexes.iter().zip(&self.lengths) {
151 if index >= length {
152 return None;
153 }
154 offset = offset * length + index;
155 }
156 Some(offset)
157 }
158
159 fn checked_offset(&self, indexes: &[i32]) -> Result<usize, BindingError> {
160 if indexes.len() != self.lengths.len() {
161 return Err(BindingError::message("Indices length does not match the array rank."));
162 }
163 let indexes: Option<Vec<usize>> = indexes.iter().map(|i| usize::try_from(*i).ok()).collect();
164 indexes
165 .and_then(|i| self.offset(&i))
166 .ok_or_else(|| BindingError::message("Index was outside the bounds of the array."))
167 }
168}
169
170impl<T: PropertyValue> PartialEq for BindableArray<T> {
171 fn eq(&self, other: &Self) -> bool {
172 std::ptr::eq(self, other)
173 }
174}
175
176impl<T: PropertyValue> IBindableArray for BindableArray<T> {
177 fn rank(&self) -> usize {
178 self.lengths.len()
179 }
180
181 fn element_type(&self) -> ValueType {
182 ValueType::of::<T>()
183 }
184
185 fn get_value(&self, indexes: &[i32]) -> Result<Option<BoxedValue>, BindingError> {
186 let offset = self.checked_offset(indexes)?;
187 Ok(Some(Rc::new(self.items.borrow()[offset].clone())))
188 }
189
190 fn set_value(&self, indexes: &[i32], value: Option<&BoxedValue>) -> Result<(), BindingError> {
191 let offset = self.checked_offset(indexes)?;
192 let value = Value::<T>::from_untyped(value).ok_or_else(|| invalid_value(value, ValueType::of::<T>()))?;
193 self.items.borrow_mut()[offset] = value;
194 Ok(())
195 }
196}
197
198impl<T: PropertyValue> IBindableIndexer for BindableArray<T> {
199 fn index_parameter_types(&self) -> Vec<ValueType> {
200 vec![ValueType::of::<i32>(); self.lengths.len()]
201 }
202
203 fn value_type(&self) -> ValueType {
204 ValueType::of::<T>()
205 }
206
207 fn get(&self, arguments: &[BoxedValue]) -> Result<Option<BoxedValue>, BindingError> {
208 let indexes: Result<Vec<i32>, BindingError> =
209 (0..arguments.len()).map(|i| argument::<i32>(arguments, i).copied()).collect();
210 self.get_value(&indexes?)
211 }
212
213 fn set(&self, arguments: &[BoxedValue], value: Option<&BoxedValue>) -> Result<bool, BindingError> {
214 let indexes: Result<Vec<i32>, BindingError> =
215 (0..arguments.len()).map(|i| argument::<i32>(arguments, i).copied()).collect();
216 self.set_value(&indexes?, value).map(|()| true)
217 }
218}
219
220pub struct BindableDictionary<K: Eq + Hash + Clone + Display + 'static, V: PropertyValue> {
226 items: FerroDictionary<K, V>,
227 changed: Event<CollectionChange>,
228 forwarder: OnceCell<u64>,
229}
230
231impl<K: Eq + Hash + Clone + Display + 'static, V: PropertyValue> BindableDictionary<K, V> {
232 pub fn new(entries: impl IntoIterator<Item = (K, V)>) -> Rc<Self> {
234 let this = Rc::new(Self {
235 items: FerroDictionary::from_dictionary(entries),
236 changed: Event::new(),
237 forwarder: OnceCell::new(),
238 });
239 let weak = Rc::downgrade(&this);
240 let token =
241 this.items.add_collection_changed(Rc::new(move |e: &NotifyCollectionChangedEventArgs<'_, (K, V)>| {
242 if let Some(this) = weak.upgrade() {
243 this.changed.raise(&CollectionChange {
244 action: e.action,
245 new_starting_index: e.new_starting_index,
246 new_count: e.new_items.len(),
247 old_starting_index: e.old_starting_index,
248 old_count: e.old_items.len(),
249 });
250 }
251 }));
252 let _ = this.forwarder.set(token);
253 if !ModelTypes::is_registered(TypeId::of::<Self>()) {
254 ModelTypes::register::<Self>(|b| b.indexer().notify_collection_changed().notify_property_changed());
255 }
256 this
257 }
258
259 pub fn items(&self) -> &FerroDictionary<K, V> {
261 &self.items
262 }
263}
264
265impl<K: Eq + Hash + Clone + Display + 'static, V: PropertyValue> PartialEq for BindableDictionary<K, V> {
266 fn eq(&self, other: &Self) -> bool {
267 std::ptr::eq(self, other)
268 }
269}
270
271impl<K: Eq + Hash + Clone + Display + 'static, V: PropertyValue> INotifyCollectionChanged
272 for BindableDictionary<K, V>
273{
274 fn collection_changed(&self) -> &Event<CollectionChange> {
275 &self.changed
276 }
277}
278
279impl<K: Eq + Hash + Clone + Display + 'static, V: PropertyValue> INotifyPropertyChanged for BindableDictionary<K, V> {
280 fn property_changed(&self) -> &Event<str> {
281 self.items.property_changed()
282 }
283}
284
285impl<K: Eq + Hash + Clone + Display + 'static, V: PropertyValue> IBindableIndexer for BindableDictionary<K, V> {
286 fn index_parameter_types(&self) -> Vec<ValueType> {
287 vec![ValueType::of::<K>()]
288 }
289
290 fn value_type(&self) -> ValueType {
291 ValueType::of::<V>()
292 }
293
294 fn get(&self, arguments: &[BoxedValue]) -> Result<Option<BoxedValue>, BindingError> {
295 let key = argument::<K>(arguments, 0)?;
296 match self.items.try_get_value(key) {
297 Some(value) => Ok(Some(Rc::new(value))),
298 None => Err(BindingError::message(format!("The given key '{key}' was not present in the dictionary."))),
299 }
300 }
301
302 fn set(&self, arguments: &[BoxedValue], value: Option<&BoxedValue>) -> Result<bool, BindingError> {
303 let key = argument::<K>(arguments, 0)?;
304 let value = Value::<V>::from_untyped(value).ok_or_else(|| invalid_value(value, ValueType::of::<V>()))?;
305 self.items.set(key.clone(), value);
306 Ok(true)
307 }
308}