flo_animation/traits/
editable.rs

1use super::edit::*;
2
3use std::ops::{Deref, DerefMut};
4
5///
6/// Represents an item that can be edited
7///
8pub trait Editable<T: ?Sized> {
9    ///
10    /// Opens this item for editing, if an editor is available
11    ///
12    fn edit(&self) -> Option<Editor<T>>;
13
14    ///
15    /// Opens this item for reading, if a reader is available
16    ///
17    fn read(&self) -> Option<Reader<T>>;
18}
19
20///
21/// Represents a reader for type T
22/// 
23pub struct Reader<'a, T: ?Sized+'a> {
24    target: Box<'a+Deref<Target=T>>
25}
26
27///
28/// Represents an editor for type T
29///
30pub struct Editor<'a, T: ?Sized+'a> {
31    /// The target that is being edited
32    target: Box<'a+DerefMut<Target=T>>,
33}
34
35impl<'a, T: ?Sized+'a> Reader<'a, T> {
36    ///
37    /// Creates a new reader from something that can be dereferenced as the specified type
38    ///
39    pub fn new<Owner: 'a+Deref<Target=T>>(target: Owner) -> Reader<'a, T> {
40        Reader { target: Box::new(target) }
41    }
42}
43
44impl<'a, T: ?Sized+'a> Editor<'a, T> {
45    ///
46    /// Creates a new editor from something that can be dereferenced as the specified type
47    ///
48    pub fn new<Owner: 'a+DerefMut<Target=T>>(target: Owner) -> Editor<'a, T> {
49        Editor { target: Box::new(target) }
50    }
51}
52
53impl<'a, T: ?Sized+'a> Deref for Reader<'a, T> {
54    type Target = T;
55
56    fn deref(&self) -> &T {
57        self.target.deref()
58    }
59}
60
61impl<'a, T: ?Sized+'a> Deref for Editor<'a, T> {
62    type Target = T;
63
64    fn deref(&self) -> &T {
65        self.target.deref()
66    }
67}
68
69impl<'a, T: ?Sized+'a> DerefMut for Editor<'a, T> {
70    fn deref_mut(&mut self) -> &mut T {
71        self.target.deref_mut()
72    }
73}
74
75impl<T: ?Sized> Editable<T> for () {
76    fn edit(&self) -> Option<Editor<T>> { None }
77    fn read(&self) -> Option<Reader<T>> { None }
78}
79
80///
81/// Opens an editable object for reading if possible
82/// 
83pub fn open_read<'a, EditorType: ?Sized>(editable: &'a Editable<EditorType>) -> Option<Reader<'a, EditorType>> {
84    editable.read()
85}
86
87///
88/// Opens an editable object for editing if possible
89/// 
90pub fn open_edit<'a, EditorType: ?Sized>(editable: &'a Editable<EditorType>) -> Option<Editor<'a, EditorType>> {
91    editable.edit()
92}
93
94///
95/// Convenience trait that makes it easier to edit an object that uses an EditLog
96/// 
97pub trait PerformEdits<Edit> {
98    fn perform_edits<Iter: IntoIterator<Item=Edit>>(&self, edits: Iter);
99    fn set_pending(&self, pending: &[Edit]);
100    fn commit_pending(&self);
101}
102
103impl<Edit, T: Editable<PendingEditLog<Edit>>> PerformEdits<Edit> for T {
104    #[inline]
105    fn perform_edits<Iter: IntoIterator<Item=Edit>>(&self, edits: Iter) {
106        let mut editor = open_edit::<PendingEditLog<Edit>>(self).unwrap();
107
108        let edits: Vec<_> = edits.into_iter().collect();
109
110        editor.set_pending(&edits);
111        editor.commit_pending();
112    }
113
114    #[inline]
115    fn set_pending(&self, edits: &[Edit]) {
116        let mut editor = open_edit::<PendingEditLog<Edit>>(self).unwrap();
117
118        editor.set_pending(edits);
119    }
120
121    #[inline]
122    fn commit_pending(&self) {
123        let mut editor = open_edit::<PendingEditLog<Edit>>(self).unwrap();
124
125        editor.commit_pending();
126    }
127}
128
129#[cfg(test)]
130mod test {
131    use super::*;
132    use std::sync::*;
133
134    #[test]
135    fn can_create_reader_for_mutex() {
136        let mutex = Mutex::new(1);
137
138        {
139            // Lock the mutex and turn the lock into a reader
140            let reader = {
141                let locked = mutex.lock().unwrap();
142                Reader::new(locked)
143            };
144
145            // Can use the reader like it was the lock
146            assert!(*reader == 1);
147        }
148    }
149
150    #[test]
151    fn can_create_editor_for_mutex() {
152        let mutex = Mutex::new(1);
153
154        {
155            // Lock the mutex and turn the lock into an editor
156            let mut editor = {
157                let locked = mutex.lock().unwrap();
158                Editor::new(locked)
159            };
160
161            // Can use the editor like it was the lock
162            assert!(*editor == 1);
163            *editor = 2;
164        }
165
166        // Updates stay afterwards
167        assert!(*mutex.lock().unwrap() == 2);
168    }
169
170    struct TestEditable;
171
172    impl Editable<i32> for TestEditable {
173        fn edit(&self) -> Option<Editor<i32>> { None }
174        fn read(&self) -> Option<Reader<i32>> { None }
175    }
176
177    impl Editable<bool> for TestEditable {
178        fn edit(&self) -> Option<Editor<bool>> { None }
179        fn read(&self) -> Option<Reader<bool>> { None }
180    }
181
182    #[test]
183    fn can_have_multiple_editable_items() {
184        let test = TestEditable;
185        let edit_i32:Option<Editor<i32>>    = test.edit();
186        let edit_bool                       = open_edit::<bool>(&test);
187
188        assert!(edit_i32.is_none());
189        assert!(edit_bool.is_none());
190    }
191}