mutex_trait/
lib.rs

1//! Low level definition of a Mutex.
2//!
3//! This crate provides:
4//!
5//! - A `Mutex` trait that is to be used as the foundation of exclusive access to the data
6//!   contained within it.
7//! - Helper traits and implementations which allows for multiple locks to be taken at once.
8//!
9//! RFC that added this trait: [RFC #377](https://github.com/rust-embedded/wg/blob/master/rfcs/0377-mutex-trait.md)
10//!
11//! # Example
12//!
13//! ```
14//! use mutex_trait::prelude::*;
15//!
16//! // A function taking 2 mutexes
17//! fn normal_lock(
18//!     a: &mut impl Mutex<Data = i32>,
19//!     b: &mut impl Mutex<Data = i32>,
20//! ) {
21//!     // Taking each lock separately
22//!     a.lock(|a| {
23//!         b.lock(|b| {
24//!             *a += 1;
25//!             *b += 1;
26//!         });
27//!     });
28//!
29//!     // Or both at once
30//!     (a, b).lock(|a, b| {
31//!         *a += 1;
32//!         *b += 1;
33//!     });
34//! }
35//! ```
36//!
37//! # Minimum Supported Rust Version (MSRV)
38//!
39//! This crate is guaranteed to compile on stable Rust 1.31 and up. It *might*
40//! compile with older versions but that may change in any new patch release.
41
42#![no_std]
43#![deny(missing_docs)]
44
45use core::cell::RefCell;
46use core::ops::{Deref, DerefMut};
47
48/// Makes locks work on N-tuples, locks the mutexes from left-to-right in the tuple. These are
49/// used to reduce rightward drift in code and to help make intentions clearer.
50///
51/// # Example
52///
53/// ```
54/// use mutex_trait::prelude::*;
55///
56/// fn normal_lock(
57///     a: &mut impl Mutex<Data = i32>,
58///     b: &mut impl Mutex<Data = i32>,
59///     c: &mut impl Mutex<Data = i32>
60/// ) {
61///     // A lot of rightward drift...
62///     a.lock(|a| {
63///         b.lock(|b| {
64///             c.lock(|c| {
65///                 *a += 1;
66///                 *b += 1;
67///                 *c += 1;
68///             });
69///         });
70///     });
71/// }
72/// ```
73///
74/// Has a shorthand as:
75///
76/// ```
77/// use mutex_trait::prelude::*;
78///
79/// fn tuple_lock(
80///     a: &mut impl Mutex<Data = i32>,
81///     b: &mut impl Mutex<Data = i32>,
82///     c: &mut impl Mutex<Data = i32>
83/// ) {
84///     // Look! Single indent and less to write
85///     (a, b, c).lock(|a, b, c| {
86///         *a += 1;
87///         *b += 1;
88///         *c += 1;
89///     });
90/// }
91/// ```
92pub mod prelude {
93    pub use crate::Mutex;
94
95    macro_rules! lock {
96        ($e:ident, $fun:block) => {
97            $e.lock(|$e| $fun )
98        };
99        ($e:ident, $($es:ident),+, $fun:block) => {
100            $e.lock(|$e| lock!($($es),*, $fun))
101        };
102    }
103
104    macro_rules! make_tuple_impl {
105        ($name:ident, $($es:ident),+) => {
106            /// Auto-generated tuple implementation, see [`Mutex`](../trait.Mutex.html) for details.
107            pub trait $name {
108                $(
109                    /// Data protected by the mutex.
110                    type $es;
111                )*
112
113                /// Creates a critical section and grants temporary access to the protected data.
114                fn lock<R>(&mut self, f: impl FnOnce($(&mut Self::$es),*) -> R) -> R;
115            }
116
117            impl<$($es),+> $name for ($($es,)+)
118            where
119                $($es: crate::Mutex),*
120            {
121                $(
122                    type $es = $es::Data;
123                )*
124
125                #[allow(non_snake_case)]
126                fn lock<R>(&mut self, f: impl FnOnce($(&mut Self::$es),*) -> R) -> R {
127                    let ($(
128                        $es,
129                    )*) = self;
130
131                    lock!($($es),*, { f($($es),*) })
132                }
133            }
134        };
135    }
136
137    // Generate tuple lock impls
138    make_tuple_impl!(TupleExt01, T1);
139    make_tuple_impl!(TupleExt02, T1, T2);
140    make_tuple_impl!(TupleExt03, T1, T2, T3);
141    make_tuple_impl!(TupleExt04, T1, T2, T3, T4);
142    make_tuple_impl!(TupleExt05, T1, T2, T3, T4, T5);
143    make_tuple_impl!(TupleExt06, T1, T2, T3, T4, T5, T6);
144    make_tuple_impl!(TupleExt07, T1, T2, T3, T4, T5, T6, T7);
145    make_tuple_impl!(TupleExt08, T1, T2, T3, T4, T5, T6, T7, T8);
146    make_tuple_impl!(TupleExt09, T1, T2, T3, T4, T5, T6, T7, T8, T9);
147    make_tuple_impl!(TupleExt10, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
148    make_tuple_impl!(TupleExt11, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
149    make_tuple_impl!(TupleExt12, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
150}
151
152/// Any object implementing this trait guarantees exclusive access to the data contained
153/// within the mutex for the duration of the lock.
154pub trait Mutex {
155    /// Data protected by the mutex.
156    type Data;
157
158    /// Creates a critical section and grants temporary access to the protected data.
159    fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
160}
161
162// `lock` will now work on any mutable reference to a lock
163impl<L> Mutex for &'_ mut L
164where
165    L: Mutex,
166{
167    type Data = L::Data;
168
169    fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R {
170        L::lock(self, f)
171    }
172}
173
174// A RefCell is a lock in single threaded applications
175impl<T> Mutex for &'_ RefCell<T> {
176    type Data = T;
177
178    fn lock<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
179        f(&mut self.borrow_mut())
180    }
181}
182
183/// Wraps a `T` and provides exclusive access via a `Mutex` impl.
184///
185/// This provides an no-op `Mutex` implementation for data that does not need a real mutex.
186#[derive(Debug)]
187pub struct Exclusive<'a, T>(&'a mut T);
188
189impl<'a, T> Exclusive<'a, T> {
190    /// Creates a new `Exclusive` object wrapping `data`.
191    pub fn new(data: &'a mut T) -> Self {
192        Exclusive(data)
193    }
194
195    /// Consumes this `Exclusive` instance and returns the wrapped value.
196    pub fn into_inner(self) -> &'a mut T {
197        self.0
198    }
199}
200
201impl<'a, T> From<&'a mut T> for Exclusive<'a, T> {
202    fn from(data: &'a mut T) -> Self {
203        Exclusive(data)
204    }
205}
206
207impl<'a, T> Deref for Exclusive<'a, T> {
208    type Target = T;
209
210    fn deref(&self) -> &T {
211        self.0
212    }
213}
214
215impl<'a, T> DerefMut for Exclusive<'a, T> {
216    fn deref_mut(&mut self) -> &mut T {
217        self.0
218    }
219}
220
221impl<'a, T> Mutex for Exclusive<'a, T> {
222    type Data = T;
223
224    fn lock<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
225        f(self.0)
226    }
227}
228
229#[cfg(test)]
230#[allow(dead_code)]
231mod tests {
232    use crate::prelude::*;
233    use crate::Exclusive;
234
235    fn compile_test_single_move(mut a: impl Mutex<Data = i32>) {
236        a.lock(|a| {
237            *a += 1;
238        });
239    }
240
241    fn compile_test_single_reference(a: &mut impl Mutex<Data = i32>) {
242        a.lock(|a| {
243            *a += 1;
244        });
245    }
246
247    fn compile_test_double_move(mut a: impl Mutex<Data = i32>, mut b: impl Mutex<Data = i32>) {
248        a.lock(|a| {
249            *a += 1;
250        });
251
252        b.lock(|b| {
253            *b += 1;
254        });
255
256        (a, b).lock(|a, b| {
257            *a += 1;
258            *b += 1;
259        });
260    }
261
262    fn compile_test_double_reference(
263        a: &mut impl Mutex<Data = i32>,
264        b: &mut impl Mutex<Data = i32>,
265    ) {
266        a.lock(|a| {
267            *a += 1;
268        });
269
270        b.lock(|b| {
271            *b += 1;
272        });
273
274        (a, b).lock(|a, b| {
275            *a += 1;
276            *b += 1;
277        });
278    }
279
280    fn compile_test_move_and_reference(
281        mut a: impl Mutex<Data = i32>,
282        b: &mut impl Mutex<Data = i32>,
283    ) {
284        a.lock(|a| {
285            *a += 1;
286        });
287
288        b.lock(|b| {
289            *b += 1;
290        });
291
292        (a, b).lock(|a, b| {
293            *a += 1;
294            *b += 1;
295        });
296    }
297
298    #[test]
299    fn refcell_lock() {
300        let a = core::cell::RefCell::new(0);
301        let b = core::cell::RefCell::new(0);
302
303        (&a).lock(|a| {
304            *a += 1;
305        });
306
307        (&b).lock(|b| {
308            *b += 1;
309        });
310
311        (&a, &b).lock(|a, b| {
312            *a += 1;
313            *b += 1;
314        });
315    }
316
317    #[test]
318    fn exclusive() {
319        let mut var = 0;
320        let mut excl = Exclusive(&mut var);
321
322        excl.lock(|val| *val += 1);
323
324        assert_eq!(*excl.into_inner(), 1);
325    }
326}