Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit 5b30914

Browse files
Merge #5
5: Address nits, prepare for 0.1 r=adamgreig a=jonas-schievink :shipit: Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
2 parents 28e7c19 + 1c5cdfb commit 5b30914

File tree

1 file changed

+106
-69
lines changed

1 file changed

+106
-69
lines changed

src/lib.rs

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
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(
@@ -42,52 +42,54 @@
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+
/// ```
4591
pub 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.
158153
pub 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)]
188216
mod 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

Comments
 (0)