flo_binding/
binding.rs

1use super::traits::*;
2use super::releasable::*;
3use super::binding_context::*;
4
5use std::sync::*;
6
7///
8/// An internal representation of a bound value
9///
10struct BoundValue<Value> {
11    /// The current value of this binding
12    value: Value,
13
14    /// What to call when the value changes
15    when_changed: Vec<ReleasableNotifiable>
16}
17
18impl<Value: Clone+PartialEq> BoundValue<Value> {
19    ///
20    /// Creates a new binding with the specified value
21    ///
22    pub fn new(val: Value) -> BoundValue<Value> {
23        BoundValue {
24            value:          val,
25            when_changed:   vec![]
26        }
27    }
28
29    ///
30    /// Updates the value in this structure without calling the notifications, returns whether or not anything actually changed
31    ///
32    pub fn set_without_notifying(&mut self, new_value: Value) -> bool {
33        let changed = self.value != new_value;
34
35        self.value = new_value;
36
37        changed
38    }
39
40    ///
41    /// Retrieves a copy of the list of notifiable items for this value
42    ///
43    pub fn get_notifiable_items(&self) -> Vec<ReleasableNotifiable> {
44        self.when_changed
45            .iter()
46            .map(|item| item.clone_for_inspection())
47            .collect()
48    }
49
50    ///
51    /// If there are any notifiables in this object that aren't in use, remove them
52    ///
53    pub fn filter_unused_notifications(&mut self) {
54        self.when_changed.retain(|releasable| releasable.is_in_use());
55    }
56
57    ///
58    /// Retrieves the value of this item
59    ///
60    fn get(&self) -> Value {
61        self.value.clone()
62    }
63
64    ///
65    /// Retrieves a mutable reference to the value of this item
66    ///
67    fn get_mut(&mut self) -> &mut Value {
68        &mut self.value
69    }
70
71    ///
72    /// Adds something that will be notified when this item changes
73    ///
74    fn when_changed(&mut self, what: Arc<dyn Notifiable>) -> Box<dyn Releasable> {
75        let releasable = ReleasableNotifiable::new(what);
76        self.when_changed.push(releasable.clone_as_owned());
77
78        self.filter_unused_notifications();
79
80        Box::new(releasable)
81    }
82}
83
84impl<Value: Default + Clone + PartialEq> Default for BoundValue<Value> {
85    fn default() -> Self {
86        BoundValue::new(Value::default())
87    }
88}
89
90impl<Value: std::fmt::Debug> std::fmt::Debug for BoundValue<Value> {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        self.value.fmt(f)
93    }
94}
95
96impl<Value: PartialEq> PartialEq for BoundValue<Value> {
97    fn eq(&self, other: &Self) -> bool {
98        self.value.eq(&other.value)
99    }
100}
101///
102/// Represents a thread-safe, sharable binding
103///
104#[derive(Clone)]
105pub struct Binding<Value> {
106    /// The value stored in this binding
107    value: Arc<Mutex<BoundValue<Value>>>
108}
109
110impl<Value: Default + Clone + PartialEq> Default for Binding<Value> {
111    fn default() -> Self {
112        Binding::new(Value::default())
113    }
114}
115
116impl<Value: std::fmt::Debug> std::fmt::Debug for Binding<Value> {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        self.value.fmt(f)
119    }
120}
121
122impl<Value: PartialEq> PartialEq for Binding<Value> {
123    fn eq(&self, other: &Self) -> bool {
124        self.value.lock().unwrap().eq(&other.value.lock().unwrap())
125    }
126}
127
128impl<Value: Clone+PartialEq> Binding<Value> {
129    pub fn new(value: Value) -> Binding<Value> {
130        Binding {
131            value: Arc::new(Mutex::new(BoundValue::new(value)))
132        }
133    }
134}
135
136impl<Value: 'static+Clone+PartialEq+Send> Changeable for Binding<Value> {
137    fn when_changed(&self, what: Arc<dyn Notifiable>) -> Box<dyn Releasable> {
138        self.value.lock().unwrap().when_changed(what)
139    }
140}
141
142impl<Value: 'static+Clone+PartialEq+Send> Bound<Value> for Binding<Value> {
143    fn get(&self) -> Value {
144        BindingContext::add_dependency(self.clone());
145
146        self.value.lock().unwrap().get()
147    }
148}
149
150impl<Value: 'static+Clone+PartialEq+Send> MutableBound<Value> for Binding<Value> {
151    fn set(&self, new_value: Value) {
152        // Update the value with the lock held
153        let notifications = {
154            let mut cell    = self.value.lock().unwrap();
155            let changed     = cell.set_without_notifying(new_value);
156        
157            if changed {
158                cell.get_notifiable_items()
159            } else {
160                vec![]
161            }
162        };
163
164        // Call the notifications outside of the lock
165        let mut needs_filtering = false;
166
167        for to_notify in notifications {
168            needs_filtering = !to_notify.mark_as_changed() || needs_filtering;
169        }
170
171        if needs_filtering {
172            let mut cell = self.value.lock().unwrap();
173            cell.filter_unused_notifications();
174        }
175    }
176}
177
178impl<Value: 'static + Clone + PartialEq + Send> WithBound<Value> for Binding<Value> {
179    fn with_ref<F, T>(&self, f: F) -> T
180    where
181        F: FnOnce(&Value) -> T,
182    {
183        f(&self.value.lock().unwrap().value)
184    }
185    fn with_mut<F>(&self, f: F)
186    where
187        F: FnOnce(&mut Value) -> bool,
188    {
189        let notifications = {
190            let mut v = self.value.lock().unwrap();
191            let changed = f(v.get_mut());
192
193            if changed {
194                v.get_notifiable_items()
195            } else {
196                vec![]
197            }
198        };
199
200        // Call the notifications outside of the lock
201        let mut needs_filtering = false;
202
203        for to_notify in notifications {
204            needs_filtering = !to_notify.mark_as_changed() || needs_filtering;
205        }
206
207        if needs_filtering {
208            let mut cell = self.value.lock().unwrap();
209            cell.filter_unused_notifications();
210        }
211    }
212
213}
214
215impl<Value: 'static+Clone+PartialEq+Send> From<Value> for Binding<Value> {
216    #[inline]
217    fn from(val: Value) -> Binding<Value> {
218        Binding::new(val)
219    }
220}
221
222impl<'a, Value: 'static+Clone+PartialEq+Send> From<&'a Binding<Value>> for Binding<Value> {
223    #[inline]
224    fn from(val: &'a Binding<Value>) -> Binding<Value> {
225        Binding::clone(val)
226    }
227}
228
229impl<'a, Value: 'static+Clone+PartialEq+Send> From<&'a Value> for Binding<Value> {
230    #[inline]
231    fn from(val: &'a Value) -> Binding<Value> {
232        Binding::new(val.clone())
233    }
234}