diff --git a/src/lib.rs b/src/lib.rs index 8b8efeb..9d60436 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ )] #![no_std] -use core::cell::UnsafeCell; +use core::cell::{RefCell, UnsafeCell}; /// A peripheral #[derive(Debug)] @@ -123,3 +123,57 @@ pub unsafe trait Nr { // to prevent sending non-Sendable stuff (e.g. access tokens) across different // execution contexts (e.g. interrupts) unsafe impl Sync for Mutex where T: Send {} + +/// A shared value wrapper +/// +/// Uses `Mutex` internally, so the same caveats about multi-core systems apply +pub struct Shared { + inner: Mutex>>, +} + +impl Shared { + /// Creates a new empty shared value + #[cfg(feature = "const-fn")] + pub const fn new() -> Self { + Shared { + inner: Mutex::new(RefCell::new(None)), + } + } + + /// Creates a new empty shared value + #[cfg(not(feature = "const-fn"))] + pub fn new() -> Self { + Shared { + inner: Mutex::new(RefCell::new(None)), + } + } + + /// Loads new contents into a shared value, if the value already contained + /// data the old value is returned + pub fn put(&self, cs: &CriticalSection, value: T) -> Option { + self.inner.borrow(cs).replace(Some(value)) + } + + /// Attempts to get a reference to the data in the shared value, may fail + /// if there are current mutable references, or if the value is empty + pub fn get<'a>(&'a self, cs: &'a CriticalSection) -> Option> { + self.inner + .borrow(cs) + .try_borrow() + .ok() + .filter(|inner| inner.is_some()) + .map(|inner| core::cell::Ref::map(inner, |v| v.as_ref().unwrap())) + } + + /// Attempts to get a reference to the data in the shared value, may fail + /// if there are current mutable or immutable references, or if the value + /// is empty + pub fn get_mut<'a>(&'a self, cs: &'a CriticalSection) -> Option> { + self.inner + .borrow(cs) + .try_borrow_mut() + .ok() + .filter(|inner| inner.is_some()) + .map(|inner| core::cell::RefMut::map(inner, |v| v.as_mut().unwrap())) + } +}