critical_section_lock_mut/
lib.rs

1#![doc(html_root_url = "https://docs.rs/critical-section-lock-mut/0.1.2")]
2#![no_std]
3//! Lock data with mutable access on a single-core
4//! processor.  The locking is provided by a
5//! `critical-section::Mutex`.
6//!
7//! # Example
8//!
9//! ```text
10//! use critical_section_lock_mut::LockMut;
11//!
12//! static SHARED: LockMut<u8> = LockMut::new();
13//!
14//! fn main() {
15//!     SHARED.init(3);
16//!     SHARED.with_lock(|u| *u += 1);
17//! ```
18
19use core::cell::RefCell;
20
21pub use critical_section;
22use critical_section::Mutex;
23
24/// This datatype provides a lock with interior mutability
25/// for the data inside.
26#[derive(Debug)]
27pub struct LockMut<T>(Mutex<RefCell<Option<T>>>);
28
29impl<T> LockMut<T> {
30    /// Create a new empty `LockMut`.
31    ///
32    /// # Examples
33    ///
34    /// ```no_run
35    /// # use critical_section_lock_mut::LockMut;
36    /// static LOCKED_DATA: LockMut<u8> = LockMut::new();
37    /// ```
38    pub const fn new() -> Self {
39        LockMut(Mutex::new(RefCell::new(None)))
40    }
41
42    /// Initialize a previously-uninitialized `LockMut`.
43    ///
44    /// # Examples
45    ///
46    /// ```no_run
47    /// # use critical_section_lock_mut::LockMut;
48    /// static LOCKED_DATA: LockMut<u8> = LockMut::new();
49    /// LOCKED_DATA.init(5);
50    /// ```
51    ///
52    /// # Panics
53    ///
54    /// Panics if this `LockMut` is to be initialized a second time.
55    pub fn init(&self, val: T) {
56        critical_section::with(|cs| {
57            let mut cell = self.0.borrow(cs).borrow_mut();
58            assert!(cell.is_none(), "lock reinitialized");
59            *cell = Some(val);
60        });
61    }
62
63    /// Locks, then runs the closure `f` with a mutable
64    /// reference to the locked data.
65    ///
66    /// # Examples
67    ///
68    /// ```no_run
69    /// # use critical_section_lock_mut::LockMut;
70    /// static LOCKED_DATA: LockMut<u8> = LockMut::new();
71    /// LOCKED_DATA.init(5);
72    /// LOCKED_DATA.with_lock(|u| *u += 1);
73    /// ```
74    ///
75    /// # Panics
76    ///
77    /// Panics if this `LockMut` is uninitialized.
78    pub fn with_lock<F: FnOnce(&mut T)>(&self, f: F) {
79        critical_section::with(|cs| {
80            // &LockMut<T> → &Mutex<RefCell<Option<T>>> →
81            // &RefCell<Option<T>> → &mut Option<T>
82            let mut cell = self.0.borrow(cs).borrow_mut();
83            // &mut Option<T> → Option<&mut T> → &mut T
84            let val_mut = cell.as_mut().expect("empty lock");
85            f(val_mut);
86        });
87    }
88
89    /// Locks if this `LockMut` is initialized, then runs
90    /// the closure `f` with a mutable reference to the
91    /// locked data. If the `LockMut` is uninitialized,
92    /// this method does nothing.
93    ///
94    /// # Examples
95    ///
96    /// ```no_run
97    /// # use critical_section_lock_mut::LockMut;
98    /// static LOCKED_DATA: LockMut<u8> = LockMut::new();
99    /// LOCKED_DATA.try_with_lock(|_| panic!());
100    /// ```
101    pub fn try_with_lock<F: FnOnce(&mut T)>(&self, f: F) {
102        critical_section::with(|cs| {
103            // &LockMut<T> → &Mutex<RefCell<Option<T>>> →
104            // &RefCell<Option<T>> → &mut Option<T>
105            let mut cell = self.0.borrow(cs).borrow_mut();
106            // &mut Option<T> → Option<&mut T> → &mut T
107            if let Some(val_mut) = cell.as_mut() {
108                f(val_mut);
109            }
110        });
111    }
112}