1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! Core abstractions of the Real-Time Interrupt-driven Concurrency (RTIC) framework
//!
//! You can write generic *libraries* using the `Mutex` trait in this crate. If you want to write
//! application code then you'll need an *implementation* of the RTIC framework for a particular
//! architecture. Currently, there are implementations for these architectures and OSes:
//!
//! - [ARM Cortex-M](https://crates.io/crates/cortex-m-rtic)
// - [Linux]
// - [MSP430]
// - [RISC-V]

#![deny(missing_docs)]
#![deny(rust_2018_compatibility)]
#![deny(rust_2018_idioms)]
#![deny(warnings)]
#![no_std]

use core::ops;

/// Memory safe access to shared resources
///
/// In RTIC, locks are implemented as critical sections that prevent other tasks from *starting*.
/// These critical sections are implemented by temporarily increasing the dynamic priority of the
/// current context. Entering and leaving these critical sections is always done in bounded constant
/// time (a few instructions in bare metal contexts).
pub trait Mutex {
    /// Data protected by the mutex
    type T;

    /// Creates a critical section and grants temporary access to the protected data
    fn lock<R>(&mut self, f: impl FnOnce(&mut Self::T) -> R) -> R;
}

impl<'a, M> Mutex for &'a mut M
where
    M: Mutex,
{
    type T = M::T;

    fn lock<R>(&mut self, f: impl FnOnce(&mut M::T) -> R) -> R {
        M::lock(self, f)
    }
}

/// Newtype over `&'a mut T` that implements the `Mutex` trait
///
/// The `Mutex` implementation for this type is a no-op: no critical section is created
pub struct Exclusive<'a, T>(pub &'a mut T);

impl<'a, T> Mutex for Exclusive<'a, T> {
    type T = T;

    fn lock<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
        f(self.0)
    }
}

impl<'a, T> ops::Deref for Exclusive<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.0
    }
}

impl<'a, T> ops::DerefMut for Exclusive<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        self.0
    }
}

/// Makes locks work on N-tuples, locks the mutexes from left-to-right in the tuple. These are
/// used to reduce rightward drift in code and to help make intentions clearer.
///
/// # Example
///
/// ```
/// use mutex_trait::prelude::*;
///
/// fn normal_lock(
///     a: &mut impl Mutex<T = i32>,
///     b: &mut impl Mutex<T = i32>,
///     c: &mut impl Mutex<T = i32>
/// ) {
///     // A lot of rightward drift...
///     a.lock(|a| {
///         b.lock(|b| {
///             c.lock(|c| {
///                 *a += 1;
///                 *b += 1;
///                 *c += 1;
///             });
///         });
///     });
/// }
/// ```
///
/// Has a shorthand as:
///
/// ```
/// use mutex_trait::prelude::*;
///
/// fn tuple_lock(
///     a: &mut impl Mutex<T = i32>,
///     b: &mut impl Mutex<T = i32>,
///     c: &mut impl Mutex<T = i32>
/// ) {
///     // Look! Single indent and less to write
///     (a, b, c).lock(|a, b, c| {
///         *a += 1;
///         *b += 1;
///         *c += 1;
///     });
/// }
/// ```
pub mod prelude {
    pub use crate::Mutex;

    macro_rules! lock {
        ($e:ident, $fun:block) => {
            $e.lock(|$e| $fun )
        };
        ($e:ident, $($es:ident),+, $fun:block) => {
            $e.lock(|$e| lock!($($es),*, $fun))
        };
    }

    macro_rules! make_tuple_impl {
        ($name:ident, $($es:ident),+) => {
            /// Auto-generated tuple implementation, see [`Mutex`](../trait.Mutex.html) for details.
            pub trait $name {
                $(
                    /// Data protected by the mutex.
                    type $es;
                )*

                /// Creates a critical section and grants temporary access to the protected data.
                fn lock<R>(&mut self, f: impl FnOnce($(&mut Self::$es),*) -> R) -> R;
            }

            impl<$($es),+> $name for ($($es,)+)
            where
                $($es: crate::Mutex),*
            {
                $(
                    type $es = $es::T;
                )*

                #[allow(non_snake_case)]
                fn lock<R>(&mut self, f: impl FnOnce($(&mut Self::$es),*) -> R) -> R {
                    let ($(
                        $es,
                    )*) = self;

                    lock!($($es),*, { f($($es),*) })
                }
            }
        };
    }

    // Generate tuple lock impls
    make_tuple_impl!(TupleExt01, T1);
    make_tuple_impl!(TupleExt02, T1, T2);
    make_tuple_impl!(TupleExt03, T1, T2, T3);
    make_tuple_impl!(TupleExt04, T1, T2, T3, T4);
    make_tuple_impl!(TupleExt05, T1, T2, T3, T4, T5);
    make_tuple_impl!(TupleExt06, T1, T2, T3, T4, T5, T6);
    make_tuple_impl!(TupleExt07, T1, T2, T3, T4, T5, T6, T7);
    make_tuple_impl!(TupleExt08, T1, T2, T3, T4, T5, T6, T7, T8);
    make_tuple_impl!(TupleExt09, T1, T2, T3, T4, T5, T6, T7, T8, T9);
    make_tuple_impl!(TupleExt10, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
    make_tuple_impl!(TupleExt11, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
    make_tuple_impl!(TupleExt12, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
}