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}