1- //! Low level definition of a Mutex
1+ //! Low level definition of a Mutex.
22//!
33//! This crate provides:
44//!
55//! - 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
6+ //! contained within it.
7+ //! - Helper traits and implementations which allows for multiple locks to be taken at once.
88//!
99//! RFC that added this trait: [RFC #377](https://github.com/rust-embedded/wg/blob/master/rfcs/0377-mutex-trait.md)
1010//!
1111//! # Example
1212//!
1313//! ```
14- //! use mutex_trait::*;
14+ //! use mutex_trait::prelude:: *;
1515//!
1616//! // A function taking 2 mutexes
1717//! fn normal_lock(
4242#![ no_std]
4343#![ deny( missing_docs) ]
4444
45+ use core:: cell:: RefCell ;
46+
47+ /// Makes locks work on N-tuples, locks the mutexes from left-to-right in the tuple. These are
48+ /// used to reduce rightward drift in code and to help make intentions clearer.
49+ ///
50+ /// # Example
51+ ///
52+ /// ```
53+ /// use mutex_trait::prelude::*;
54+ ///
55+ /// fn normal_lock(
56+ /// a: &mut impl Mutex<Data = i32>,
57+ /// b: &mut impl Mutex<Data = i32>,
58+ /// c: &mut impl Mutex<Data = i32>
59+ /// ) {
60+ /// // A lot of rightward drift...
61+ /// a.lock(|a| {
62+ /// b.lock(|b| {
63+ /// c.lock(|c| {
64+ /// *a += 1;
65+ /// *b += 1;
66+ /// *c += 1;
67+ /// });
68+ /// });
69+ /// });
70+ /// }
71+ /// ```
72+ ///
73+ /// Has a shorthand as:
74+ ///
75+ /// ```
76+ /// use mutex_trait::prelude::*;
77+ ///
78+ /// fn tuple_lock(
79+ /// a: &mut impl Mutex<Data = i32>,
80+ /// b: &mut impl Mutex<Data = i32>,
81+ /// c: &mut impl Mutex<Data = i32>
82+ /// ) {
83+ /// // Look! Single indent and less to write
84+ /// (a, b, c).lock(|a, b, c| {
85+ /// *a += 1;
86+ /// *b += 1;
87+ /// *c += 1;
88+ /// });
89+ /// }
90+ /// ```
4591pub mod prelude {
46- #![ allow( non_snake_case) ]
47- //! Makes locks work on N-tuples, locks the mutexes from left-to-right in the tuple. These are
48- //! used to reduce rightward drift in code and to help make intentions clearer.
49- //!
50- //! # Example
51- //!
52- //! ```
53- //! use mutex_trait::*;
54- //!
55- //! fn normal_lock(
56- //! a: &mut impl Mutex<Data = i32>,
57- //! b: &mut impl Mutex<Data = i32>,
58- //! c: &mut impl Mutex<Data = i32>
59- //! ) {
60- //! // A lot of rightward drift...
61- //! a.lock(|a| {
62- //! b.lock(|b| {
63- //! c.lock(|c| {
64- //! *a += 1;
65- //! *b += 1;
66- //! *c += 1;
67- //! });
68- //! });
69- //! });
70- //! }
71- //! ```
72- //!
73- //! Has a shorthand as:
74- //!
75- //! ```
76- //! use mutex_trait::*;
77- //!
78- //! fn tuple_lock(
79- //! a: &mut impl Mutex<Data = i32>,
80- //! b: &mut impl Mutex<Data = i32>,
81- //! c: &mut impl Mutex<Data = i32>
82- //! ) {
83- //! // Look! Single indent and less to write
84- //! (a, b, c).lock(|a, b, c| {
85- //! *a += 1;
86- //! *b += 1;
87- //! *c += 1;
88- //! });
89- //! }
90- //! ```
92+ pub use crate :: Mutex ;
9193
9294 macro_rules! lock {
9395 ( $e: ident, $fun: block) => {
@@ -100,29 +102,30 @@ pub mod prelude {
100102
101103 macro_rules! make_tuple_impl {
102104 ( $name: ident, $( $es: ident) ,+) => {
103- /// Auto-generated tuple implementation, see [Mutex](../trait.Mutex.html) for details
105+ /// Auto-generated tuple implementation, see [` Mutex` ](../trait.Mutex.html) for details.
104106 pub trait $name {
105107 $(
106- /// Data protected by the mutex
108+ /// Data protected by the mutex.
107109 type $es;
108110 ) *
109111
110- /// Creates a critical section and grants temporary access to the protected data
112+ /// Creates a critical section and grants temporary access to the protected data.
111113 fn lock<R >( & mut self , f: impl FnOnce ( $( & mut Self :: $es) ,* ) -> R ) -> R ;
112114 }
113115
114- impl <$( $es) ,* > $name for ( $( $es) , * )
116+ impl <$( $es) ,+ > $name for ( $( $es, ) + )
115117 where
116118 $( $es: crate :: Mutex ) ,*
117119 {
118120 $(
119121 type $es = $es:: Data ;
120122 ) *
121123
124+ #[ allow( non_snake_case) ]
122125 fn lock<R >( & mut self , f: impl FnOnce ( $( & mut Self :: $es) ,* ) -> R ) -> R {
123126 let ( $(
124- $es
125- ) , * ) = self ;
127+ $es,
128+ ) * ) = self ;
126129
127130 lock!( $( $es) ,* , { f( $( $es) ,* ) } )
128131 }
@@ -131,6 +134,7 @@ pub mod prelude {
131134 }
132135
133136 // Generate tuple lock impls
137+ make_tuple_impl ! ( TupleExt01 , T1 ) ;
134138 make_tuple_impl ! ( TupleExt02 , T1 , T2 ) ;
135139 make_tuple_impl ! ( TupleExt03 , T1 , T2 , T3 ) ;
136140 make_tuple_impl ! ( TupleExt04 , T1 , T2 , T3 , T4 ) ;
@@ -142,24 +146,15 @@ pub mod prelude {
142146 make_tuple_impl ! ( TupleExt10 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 ) ;
143147 make_tuple_impl ! ( TupleExt11 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 ) ;
144148 make_tuple_impl ! ( TupleExt12 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 ) ;
145- make_tuple_impl ! ( TupleExt13 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 ) ;
146- make_tuple_impl ! ( TupleExt14 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 , T14 ) ;
147- make_tuple_impl ! ( TupleExt15 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 , T14 , T15 ) ;
148- make_tuple_impl ! (
149- TupleExt16 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 , T14 , T15 , T16
150- ) ;
151149}
152150
153- use core:: cell:: RefCell ;
154- pub use crate :: prelude:: * ;
155-
156151/// Any object implementing this trait guarantees exclusive access to the data contained
157152/// within the mutex for the duration of the lock.
158153pub trait Mutex {
159- /// Data protected by the mutex
154+ /// Data protected by the mutex.
160155 type Data ;
161156
162- /// Creates a critical section and grants temporary access to the protected data
157+ /// Creates a critical section and grants temporary access to the protected data.
163158 fn lock < R > ( & mut self , f : impl FnOnce ( & mut Self :: Data ) -> R ) -> R ;
164159}
165160
@@ -184,10 +179,43 @@ impl<T> Mutex for &'_ RefCell<T> {
184179 }
185180}
186181
182+ /// Wraps a `T` and provides exclusive access via a `Mutex` impl.
183+ ///
184+ /// This provides an no-op `Mutex` implementation for data that does not need a real mutex.
185+ #[ derive( Copy , Clone , Debug ) ]
186+ pub struct Exclusive < T > ( T ) ;
187+
188+ impl < T > Exclusive < T > {
189+ /// Creates a new `Exclusive` object wrapping `data`.
190+ pub const fn new ( data : T ) -> Self {
191+ Exclusive ( data)
192+ }
193+
194+ /// Consumes this `Exclusive` instance and returns the wrapped value.
195+ pub fn into_inner ( self ) -> T {
196+ self . 0
197+ }
198+ }
199+
200+ impl < T > From < T > for Exclusive < T > {
201+ fn from ( data : T ) -> Self {
202+ Exclusive ( data)
203+ }
204+ }
205+
206+ impl < T > Mutex for Exclusive < T > {
207+ type Data = T ;
208+
209+ fn lock < R > ( & mut self , f : impl FnOnce ( & mut T ) -> R ) -> R {
210+ f ( & mut self . 0 )
211+ }
212+ }
213+
187214#[ cfg( test) ]
215+ #[ allow( dead_code) ]
188216mod tests {
189- #! [ allow ( dead_code ) ]
190- use crate :: * ;
217+ use crate :: prelude :: * ;
218+ use crate :: Exclusive ;
191219
192220 fn compile_test_single_move ( mut a : impl Mutex < Data = i32 > ) {
193221 a. lock ( |a| {
@@ -265,9 +293,18 @@ mod tests {
265293 * b += 1 ;
266294 } ) ;
267295
268- ( & a, & b) . lock ( |a, b| {
296+ ( & a, & b) . lock ( |a, b| {
269297 * a += 1 ;
270298 * b += 1 ;
271299 } ) ;
272300 }
301+
302+ #[ test]
303+ fn exclusive ( ) {
304+ let mut excl = Exclusive ( 0 ) ;
305+
306+ excl. lock ( |val| * val += 1 ) ;
307+
308+ assert_eq ! ( excl. into_inner( ) , 1 ) ;
309+ }
273310}
0 commit comments