Skip to main content

todc_mem/register/
mutex.rs

1use crate::sync::Mutex;
2
3use super::Register;
4
5/// An shared-memory register, backed by a [`Mutex`].
6///
7/// This object uses a mutex to protect against concurrent memory
8/// access. It is **not** lock-free.
9///
10/// # Examples
11///
12/// A simple spinlock.
13///
14/// ```
15/// use std::sync::Arc;
16/// use std::{hint, thread};
17/// use todc_mem::register::{MutexRegister, Register};
18///
19///
20/// let register: Arc<MutexRegister<bool>> = Arc::new(MutexRegister::new());
21///
22/// let register_clone = register.clone();
23/// let thread = thread::spawn(move || {
24///     register_clone.write(true)
25/// });
26///
27/// while !register.read() {
28///     hint::spin_loop();
29/// }
30///
31/// thread.join().unwrap();
32/// ```
33///
34/// It is also possible to store larger, more complicated objects.
35///
36/// ```
37/// use todc_mem::register::{MutexRegister, Register};
38///
39/// #[derive(Clone, Copy, Debug, Default, PartialEq)]
40/// enum MyType {
41///     #[default]
42///     Nothing,
43///     Booleans([bool; 100]),
44///     Numbers([u64; 100]),
45/// }
46///
47/// let register: MutexRegister<MyType> = MutexRegister::new();
48///
49/// assert_eq!(register.read(), MyType::Nothing);
50///
51/// let numbers = MyType::Numbers([42; 100]);
52/// register.write(numbers);
53/// assert_eq!(register.read(), numbers);
54/// ```
55///
56#[derive(Debug)]
57pub struct MutexRegister<T: Copy + Default> {
58    mutex: Mutex<T>,
59}
60
61impl<T: Copy + Default> Default for MutexRegister<T> {
62    fn default() -> Self {
63        MutexRegister::<T>::new()
64    }
65}
66
67impl<T: Copy + Default> Register for MutexRegister<T> {
68    type Value = T;
69
70    /// Creates a new register containing the default value of `T`.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use todc_mem::register::{MutexRegister, Register};
76    ///
77    /// let register: MutexRegister<bool> = MutexRegister::new();
78    /// assert_eq!(register.read(), bool::default());
79    /// ```
80    fn new() -> Self {
81        Self {
82            mutex: Mutex::new(T::default()),
83        }
84    }
85
86    /// Returns the value currently contained in the register.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// use todc_mem::register::{MutexRegister, Register};
92    ///
93    /// let register: MutexRegister<bool> = MutexRegister::new();
94    /// assert_eq!(register.read(), false);
95    /// ```
96    fn read(&self) -> Self::Value {
97        *self.mutex.lock().unwrap()
98    }
99
100    /// Sets contents of the register to the specified value.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// use todc_mem::register::{MutexRegister, Register};
106    ///
107    /// let register: MutexRegister<bool> = MutexRegister::new();
108    /// register.write(true);
109    /// assert_eq!(register.read(), true);
110    /// ```
111    fn write(&self, value: Self::Value) {
112        *self.mutex.lock().unwrap() = value;
113    }
114}
115
116impl<T: Copy + Default> Clone for MutexRegister<T> {
117    fn clone(&self) -> Self {
118        let clone = Self::new();
119        clone.write(self.read());
120        clone
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::{MutexRegister, Register};
127
128    mod boolean {
129        use super::{MutexRegister, Register};
130
131        #[test]
132        fn new() {
133            MutexRegister::<bool>::new();
134        }
135
136        #[test]
137        fn read() {
138            let register: MutexRegister<bool> = MutexRegister::new();
139            assert!(!register.read());
140        }
141
142        #[test]
143        fn write() {
144            let register = MutexRegister::new();
145            register.write(true);
146            assert!(register.read());
147        }
148    }
149
150    mod integer {
151        use super::{MutexRegister, Register};
152
153        #[test]
154        fn new() {
155            MutexRegister::<u32>::new();
156        }
157
158        #[test]
159        fn read() {
160            let register: MutexRegister<u32> = MutexRegister::new();
161            assert_eq!(0, register.read());
162        }
163
164        #[test]
165        fn write() {
166            let register = MutexRegister::new();
167            register.write(123);
168            assert_eq!(123, register.read());
169        }
170    }
171
172    mod custom_struct {
173        use super::{MutexRegister, Register};
174
175        #[derive(Clone, Copy, PartialEq, Debug, Default)]
176        enum Color {
177            #[default]
178            Red,
179            Blue,
180        }
181
182        #[derive(Clone, Copy, Default)]
183        struct Thing {
184            color: Color,
185            height_in_ft: f32,
186        }
187
188        #[test]
189        fn new() {
190            MutexRegister::<Thing>::new();
191        }
192
193        #[test]
194        fn read() {
195            let register: MutexRegister<Thing> = MutexRegister::new();
196            let thing = register.read();
197            let same_thing = Thing {
198                color: Color::Red,
199                height_in_ft: 0.0,
200            };
201            assert_eq!(thing.color, same_thing.color);
202            assert_eq!(thing.height_in_ft, same_thing.height_in_ft);
203        }
204
205        #[test]
206        fn write() {
207            let register = MutexRegister::new();
208            let new_thing = Thing {
209                color: Color::Blue,
210                height_in_ft: 10.0,
211            };
212            register.write(new_thing);
213            let contents = register.read();
214            assert_eq!(contents.color, new_thing.color);
215            assert_eq!(contents.height_in_ft, new_thing.height_in_ft);
216        }
217    }
218}