#![cfg_attr(target_os = "none", no_std)]
mod interrupt_dropper;
#[cfg(not(target_os = "none"))]
mod local_key;
use core::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut};
use core::cmp::Ordering;
use core::ops::{Deref, DerefMut};
use core::{fmt, mem};
use self::interrupt_dropper::InterruptDropper;
#[cfg(not(target_os = "none"))]
pub use self::local_key::LocalKeyExt;
pub struct InterruptRefCell<T: ?Sized> {
inner: RefCell<T>,
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for InterruptRefCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("InterruptRefCell");
match self.try_borrow() {
Ok(borrow) => d.field("value", &borrow),
Err(_) => d.field("value", &format_args!("<borrowed>")),
};
d.finish()
}
}
impl<T> InterruptRefCell<T> {
#[inline]
pub const fn new(value: T) -> Self {
Self {
inner: RefCell::new(value),
}
}
#[inline]
pub fn into_inner(self) -> T {
self.inner.into_inner()
}
#[inline]
#[track_caller]
pub fn replace(&self, t: T) -> T {
mem::replace(&mut *self.borrow_mut(), t)
}
#[inline]
#[track_caller]
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
let mut_borrow = &mut *self.borrow_mut();
let replacement = f(mut_borrow);
mem::replace(mut_borrow, replacement)
}
#[inline]
pub fn swap(&self, other: &Self) {
mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
}
}
impl<T: ?Sized> InterruptRefCell<T> {
#[inline]
#[track_caller]
pub fn borrow(&self) -> InterruptRef<'_, T> {
self.try_borrow().expect("already mutably borrowed")
}
#[inline]
#[cfg_attr(feature = "debug_interruptrefcell", track_caller)]
pub fn try_borrow(&self) -> Result<InterruptRef<'_, T>, BorrowError> {
let guard = interrupts::disable();
self.inner.try_borrow().map(|inner| {
let inner = InterruptDropper::from(inner);
InterruptRef { inner, guard }
})
}
#[inline]
#[track_caller]
pub fn borrow_mut(&self) -> InterruptRefMut<'_, T> {
self.try_borrow_mut().expect("already borrowed")
}
#[inline]
#[cfg_attr(feature = "debug_interruptrefcell", track_caller)]
pub fn try_borrow_mut(&self) -> Result<InterruptRefMut<'_, T>, BorrowMutError> {
let guard = interrupts::disable();
self.inner.try_borrow_mut().map(|inner| {
let inner = InterruptDropper::from(inner);
InterruptRefMut { inner, guard }
})
}
#[inline]
pub fn as_ptr(&self) -> *mut T {
self.inner.as_ptr()
}
#[inline]
pub fn get_mut(&mut self) -> &mut T {
self.inner.get_mut()
}
#[inline]
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
let guard = interrupts::disable();
let ret = self.inner.try_borrow_unguarded();
drop(guard);
ret
}
}
impl<T: Default> InterruptRefCell<T> {
pub fn take(&self) -> T {
self.replace(Default::default())
}
}
impl<T: Clone> Clone for InterruptRefCell<T> {
#[inline]
#[track_caller]
fn clone(&self) -> InterruptRefCell<T> {
InterruptRefCell::new(self.borrow().clone())
}
#[inline]
#[track_caller]
fn clone_from(&mut self, other: &Self) {
self.get_mut().clone_from(&other.borrow())
}
}
impl<T: Default> Default for InterruptRefCell<T> {
#[inline]
fn default() -> InterruptRefCell<T> {
InterruptRefCell::new(Default::default())
}
}
impl<T: ?Sized + PartialEq> PartialEq for InterruptRefCell<T> {
#[inline]
fn eq(&self, other: &InterruptRefCell<T>) -> bool {
*self.borrow() == *other.borrow()
}
}
impl<T: ?Sized + Eq> Eq for InterruptRefCell<T> {}
impl<T: ?Sized + PartialOrd> PartialOrd for InterruptRefCell<T> {
#[inline]
fn partial_cmp(&self, other: &InterruptRefCell<T>) -> Option<Ordering> {
self.borrow().partial_cmp(&*other.borrow())
}
#[inline]
fn lt(&self, other: &InterruptRefCell<T>) -> bool {
*self.borrow() < *other.borrow()
}
#[inline]
fn le(&self, other: &InterruptRefCell<T>) -> bool {
*self.borrow() <= *other.borrow()
}
#[inline]
fn gt(&self, other: &InterruptRefCell<T>) -> bool {
*self.borrow() > *other.borrow()
}
#[inline]
fn ge(&self, other: &InterruptRefCell<T>) -> bool {
*self.borrow() >= *other.borrow()
}
}
impl<T: ?Sized + Ord> Ord for InterruptRefCell<T> {
#[inline]
fn cmp(&self, other: &InterruptRefCell<T>) -> Ordering {
self.borrow().cmp(&*other.borrow())
}
}
impl<T> From<T> for InterruptRefCell<T> {
fn from(t: T) -> InterruptRefCell<T> {
InterruptRefCell::new(t)
}
}
pub struct InterruptRef<'b, T: ?Sized + 'b> {
inner: InterruptDropper<Ref<'b, T>>,
guard: interrupts::Guard,
}
impl<T: ?Sized> Deref for InterruptRef<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.inner.deref()
}
}
impl<'b, T: ?Sized> InterruptRef<'b, T> {
#[allow(clippy::should_implement_trait)]
#[must_use]
#[inline]
pub fn clone(orig: &InterruptRef<'b, T>) -> InterruptRef<'b, T> {
let guard = interrupts::disable();
let inner = InterruptDropper::from(Ref::clone(&orig.inner));
InterruptRef { inner, guard }
}
#[inline]
pub fn map<U: ?Sized, F>(orig: InterruptRef<'b, T>, f: F) -> InterruptRef<'b, U>
where
F: FnOnce(&T) -> &U,
{
let InterruptRef { inner, guard } = orig;
let inner = InterruptDropper::from(Ref::map(InterruptDropper::into_inner(inner), f));
InterruptRef { inner, guard }
}
#[allow(clippy::result_large_err)]
#[inline]
pub fn filter_map<U: ?Sized, F>(
orig: InterruptRef<'b, T>,
f: F,
) -> Result<InterruptRef<'b, U>, Self>
where
F: FnOnce(&T) -> Option<&U>,
{
let guard = interrupts::disable();
let filter_map = Ref::filter_map(InterruptDropper::into_inner(orig.inner), f);
drop(guard);
match filter_map {
Ok(inner) => {
let inner = InterruptDropper::from(inner);
Ok(InterruptRef {
inner,
guard: orig.guard,
})
}
Err(inner) => {
let inner = InterruptDropper::from(inner);
Err(InterruptRef {
inner,
guard: orig.guard,
})
}
}
}
#[inline]
pub fn map_split<U: ?Sized, V: ?Sized, F>(
orig: InterruptRef<'b, T>,
f: F,
) -> (InterruptRef<'b, U>, InterruptRef<'b, V>)
where
F: FnOnce(&T) -> (&U, &V),
{
let guard = interrupts::disable();
let (a, b) = Ref::map_split(InterruptDropper::into_inner(orig.inner), f);
(
InterruptRef {
inner: InterruptDropper::from(a),
guard,
},
InterruptRef {
inner: InterruptDropper::from(b),
guard: orig.guard,
},
)
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for InterruptRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for InterruptRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<'b, T: ?Sized> InterruptRefMut<'b, T> {
#[inline]
pub fn map<U: ?Sized, F>(orig: InterruptRefMut<'b, T>, f: F) -> InterruptRefMut<'b, U>
where
F: FnOnce(&mut T) -> &mut U,
{
let InterruptRefMut { inner, guard } = orig;
let inner = InterruptDropper::from(RefMut::map(InterruptDropper::into_inner(inner), f));
InterruptRefMut { inner, guard }
}
#[allow(clippy::result_large_err)]
#[inline]
pub fn filter_map<U: ?Sized, F>(
orig: InterruptRefMut<'b, T>,
f: F,
) -> Result<InterruptRefMut<'b, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
{
let guard = interrupts::disable();
let filter_map = RefMut::filter_map(InterruptDropper::into_inner(orig.inner), f);
drop(guard);
match filter_map {
Ok(inner) => {
let inner = InterruptDropper::from(inner);
Ok(InterruptRefMut {
inner,
guard: orig.guard,
})
}
Err(inner) => {
let inner = InterruptDropper::from(inner);
Err(InterruptRefMut {
inner,
guard: orig.guard,
})
}
}
}
#[inline]
pub fn map_split<U: ?Sized, V: ?Sized, F>(
orig: InterruptRefMut<'b, T>,
f: F,
) -> (InterruptRefMut<'b, U>, InterruptRefMut<'b, V>)
where
F: FnOnce(&mut T) -> (&mut U, &mut V),
{
let guard = interrupts::disable();
let (a, b) = RefMut::map_split(InterruptDropper::into_inner(orig.inner), f);
(
InterruptRefMut {
inner: InterruptDropper::from(a),
guard,
},
InterruptRefMut {
inner: InterruptDropper::from(b),
guard: orig.guard,
},
)
}
}
pub struct InterruptRefMut<'b, T: ?Sized + 'b> {
inner: InterruptDropper<RefMut<'b, T>>,
guard: interrupts::Guard,
}
impl<T: ?Sized> Deref for InterruptRefMut<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.inner.deref()
}
}
impl<T: ?Sized> DerefMut for InterruptRefMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.deref_mut()
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for InterruptRefMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for InterruptRefMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}