1use std::collections::HashMap;
77use std::hash::Hash;
78use std::cmp::Eq;
79
80#[cfg(not(feature = "no_send"))]
82pub trait OnChanged<T>: Send {
83    fn on_changed(&self, old_value: &T, new_value: &T) -> ();
84}
85
86#[cfg(feature = "no_send")]
87pub trait OnChanged<T> {
88    fn on_changed(&self, old_value: &T, new_value: &T) -> ();
89}
90
91#[cfg(not(feature = "no_send"))]
92impl<F, T> OnChanged<T> for F
93    where F: Fn(&T, &T) -> () + Send
94{
95    fn on_changed(&self, old_value: &T, new_value: &T) -> () {
96        self(old_value, new_value)
97    }
98}
99
100#[cfg(feature = "no_send")]
101impl<F, T> OnChanged<T> for F
102    where F: Fn(&T, &T) -> ()
103{
104    fn on_changed(&self, old_value: &T, new_value: &T) -> () {
105        self(old_value, new_value)
106    }
107}
108
109struct Inner<T, K>
110    where T: Clone + PartialEq,
111          K: Hash + Eq
112{
113    value: T,
114    fn_map: HashMap<K, Box<OnChanged<T>>>,
115}
116
117impl<T, K> Inner<T, K>
118    where T: Clone + PartialEq,
119          K: Hash + Eq
120{
121    fn add_listener(&mut self, key: K, f: Box<OnChanged<T>>) -> Option<Box<OnChanged<T>>> {
122        self.fn_map.insert(key, f)
123    }
124    fn remove_listener(&mut self, key: &K) -> Option<Box<OnChanged<T>>> {
125        self.fn_map.remove(key)
126    }
127    fn notify_listeners(&self, modifier: &Modifier<T, K>) {
128        let orig_value = &modifier.orig_copy;
129        let new_value: &T = modifier;
130        for on_changed_obj in self.fn_map.values() {
131            on_changed_obj.on_changed(orig_value, new_value);
132        }
133    }
134}
135
136pub struct Modifier<'a, T, K>
141    where T: 'a + Clone + PartialEq,
142          K: 'a + Hash + Eq
143{
144    orig_copy: T,
145    inner_ref: &'a mut Inner<T, K>,
146}
147
148impl<'a, T, K> Modifier<'a, T, K>
149    where T: 'a + Clone + PartialEq,
150          K: 'a + Hash + Eq
151{
152    fn new(inner: &'a mut Inner<T, K>) -> Modifier<'a, T, K> {
153        let orig_copy: T = inner.value.clone();
154        Modifier {
155            orig_copy: orig_copy,
156            inner_ref: inner,
157        }
158    }
159}
160
161impl<'a, T, K> std::ops::Deref for Modifier<'a, T, K>
162    where T: 'a + Clone + PartialEq,
163          K: 'a + Hash + Eq
164{
165    type Target = T;
166
167    fn deref(&self) -> &T {
168        &self.inner_ref.value
169    }
170}
171
172impl<'a, T, K> std::ops::DerefMut for Modifier<'a, T, K>
173    where T: 'a + Clone + PartialEq,
174          K: 'a + Hash + Eq
175{
176    fn deref_mut(&mut self) -> &mut T {
177        &mut self.inner_ref.value
178    }
179}
180
181impl<'a, T, K> Drop for Modifier<'a, T, K>
182    where T: 'a + Clone + PartialEq,
183          K: 'a + Hash + Eq
184{
185    fn drop(&mut self) {
186        if self.orig_copy != self.inner_ref.value {
187            self.inner_ref.notify_listeners(self);
188        }
189    }
190}
191
192pub struct DataTracker<T, K>
200    where T: Clone + PartialEq,
201          K: Hash + Eq
202{
203    inner: Inner<T, K>,
204}
205
206impl<T, K> DataTracker<T, K>
207    where T: Clone + PartialEq,
208          K: Hash + Eq
209{
210    pub fn new(value: T) -> DataTracker<T, K> {
215        DataTracker {
216            inner: Inner {
217                value: value,
218                fn_map: HashMap::new(),
219            },
220        }
221    }
222
223    pub fn add_listener(&mut self,
228                        key: K,
229                        callback: Box<OnChanged<T>>)
230                        -> Option<Box<OnChanged<T>>> {
231        self.inner.add_listener(key, callback)
232    }
233
234    pub fn remove_listener(&mut self, key: &K) -> Option<Box<OnChanged<T>>> {
239        self.inner.remove_listener(key)
240    }
241
242    pub fn as_tracked_mut(&mut self) -> Modifier<T, K> {
244        Modifier::new(&mut self.inner)
245    }
246}
247
248impl<T, K> AsRef<T> for DataTracker<T, K>
249    where T: Clone + PartialEq,
250          K: Hash + Eq
251{
252    fn as_ref(&self) -> &T {
253        &self.inner.value
254    }
255}
256
257#[cfg(test)]
258mod tests {
259    use std::sync::{Arc, Mutex};
260    use super::DataTracker;
261
262    #[test]
263    fn track_struct() {
264        #[derive(Clone, PartialEq)]
265        struct MyData {
266            a: u8,
267        }
268
269        let change_count = Arc::new(Mutex::new(0));
270        let mut tracked_data = DataTracker::new(MyData { a: 1 });
271
272        let cc2 = change_count.clone();
273        let key = 0;
274        tracked_data.add_listener(key,
275                                  Box::new(move |_: &MyData, _: &MyData| {
276                                      let ref mut data = *cc2.lock().unwrap();
277                                      *data = *data + 1;
278                                  }));
279
280        assert!(*change_count.lock().unwrap() == 0);
281
282        {
283            let _x = tracked_data.as_ref();
284        }
285        assert!(*change_count.lock().unwrap() == 0);
286
287        {
288            let mut x = tracked_data.as_tracked_mut();
289            x.a = 10;
290        }
291        assert!(*change_count.lock().unwrap() == 1);
292
293        {
294            let mut x = tracked_data.as_tracked_mut();
295            x.a += 10;
296        }
297        assert!(*change_count.lock().unwrap() == 2);
298
299        assert!(tracked_data.as_ref().a == 20);
300        assert!(*change_count.lock().unwrap() == 2);
301
302        tracked_data.remove_listener(&key);
303    }
304
305    #[test]
306    fn track_enum() {
307
308        #[derive(Clone, PartialEq)]
309        enum MyEnum {
310            FirstValue,
311            SecondValue,
312        }
313
314        let change_count = Arc::new(Mutex::new(0));
315        let mut tracked_data = DataTracker::new(MyEnum::FirstValue);
316
317        let cc2 = change_count.clone();
318        let key = 0;
319        tracked_data.add_listener(key,
320                                  Box::new(move |_: &MyEnum, _: &MyEnum| {
321                                      let ref mut data = *cc2.lock().unwrap();
322                                      *data = *data + 1;
323                                  }));
324
325        assert!(*change_count.lock().unwrap() == 0);
326
327        {
328            let _x = tracked_data.as_ref();
329        }
330        assert!(*change_count.lock().unwrap() == 0);
331
332        {
333            let mut x = tracked_data.as_tracked_mut();
334            *x = MyEnum::SecondValue;
335        }
336        assert!(*change_count.lock().unwrap() == 1);
337
338        assert!(tracked_data.as_ref() == &MyEnum::SecondValue);
339        assert!(*change_count.lock().unwrap() == 1);
340
341        tracked_data.remove_listener(&key);
342    }
343
344    #[test]
345    fn callback_arg_order() {
346
347        #[derive(Clone, PartialEq)]
348        enum MyEnum {
349            FirstValue,
350            SecondValue,
351        }
352
353        let mut tracked_data = DataTracker::new(MyEnum::FirstValue);
354
355        let did_run = Arc::new(Mutex::new(false));
356        let did_run_clone = did_run.clone();
357
358        tracked_data.add_listener(0,
359                                  Box::new(move |old_value: &MyEnum, new_value: &MyEnum| {
360                                      assert!(old_value == &MyEnum::FirstValue);
361                                      assert!(new_value == &MyEnum::SecondValue);
362                                      let ref mut data = *did_run_clone.lock().unwrap();
363                                      *data = true;
364                                  }));
365        {
366            let mut x = tracked_data.as_tracked_mut();
367            *x = MyEnum::SecondValue;
368        }
369
370        assert!(*did_run.lock().unwrap() == true);
371    }
372
373    #[cfg(not(feature = "no_send"))]
376    #[test]
377    fn track_send_impl() {
378
379        #[derive(Clone, PartialEq)]
380        struct MyStruct {
381            a: i32,
382        }
383
384        let mut tracked_data = DataTracker::new(MyStruct { a: 42 });
385        tracked_data.add_listener(0,
386                                  Box::new(move |_old_value: &MyStruct, _new_value: &MyStruct| {
387                                  }));
388
389        ::std::thread::spawn(move || {
390            let mut x = tracked_data.as_tracked_mut();
391            (*x).a = 123;
392        });
393    }
394
395}