#![doc = include_str!("../README.md")]
#![cfg_attr(not(test), no_std)]
use core::{
cell::Cell,
fmt::Debug,
mem,
ops::{Deref, DerefMut},
};
use option_lock::OptionLock;
#[repr(transparent)]
pub struct LoopCell<T>(Cell<Option<T>>);
impl<T> LoopCell<T> {
#[inline]
pub const fn new(initial_value: T) -> Self {
Self(Cell::new(Some(initial_value)))
}
#[inline]
pub fn new_default() -> Self
where
T: Default,
{
Self::default()
}
#[inline]
pub const fn new_empty() -> Self {
Self(Cell::new(None))
}
#[inline]
pub fn access(&self) -> Option<LoopCellAccess<'_, T>> {
let maybe_available = self.0.replace(None);
maybe_available.map(|value| LoopCellAccess::new(self, value))
}
}
impl<T: Copy + Debug> Debug for LoopCell<T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("LoopCell").field(&self.0).finish()
}
}
impl<T> From<T> for LoopCell<T> {
#[inline]
fn from(value: T) -> Self {
Self(Cell::new(Some(value)))
}
}
impl<T: Default> Default for LoopCell<T> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
#[clippy::has_significant_drop]
pub struct LoopCellAccess<'cell, T> {
loop_cell: &'cell LoopCell<T>,
value: Option<T>,
}
impl<'cell, T> LoopCellAccess<'cell, T> {
#[inline]
const fn new(cell: &'cell LoopCell<T>, value: T) -> Self {
Self {
loop_cell: cell,
value: Some(value),
}
}
#[inline]
pub fn commit(self) {
mem::drop(self)
}
#[inline]
pub fn consume(mut self) -> T {
self.value
.take()
.expect("value inside loop cell accessor should always be Some")
}
#[inline]
pub fn into_mapped_access(self) -> LoopCellMappedAccess<'cell, T, ()> {
self.into()
}
#[inline]
pub fn map_loopcell_access<O>(
mut self,
f: impl FnOnce(&mut T) -> O,
) -> LoopCellMappedAccess<'cell, T, O> {
let o = f(&mut self);
LoopCellMappedAccess {
bare_access: self,
value: o,
}
}
#[inline]
pub fn as_loopcell_value(&self) -> &T {
self
}
#[inline]
pub fn as_loopcell_value_mut(&mut self) -> &mut T {
self
}
}
impl<'cell, T: Debug> Debug for LoopCellAccess<'cell, T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LoopCellAccess")
.field("loop_cell", &"<opaque>")
.field("value", &self.value)
.finish()
}
}
impl<'cell, T> Deref for LoopCellAccess<'cell, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value
.as_ref()
.expect("value should always be Some inside loopcell accessor")
}
}
impl<'cell, T> DerefMut for LoopCellAccess<'cell, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.value
.as_mut()
.expect("value should always be Some inside loopcell accessor")
}
}
impl<'cell, T> AsRef<T> for LoopCellAccess<'cell, T> {
#[inline]
fn as_ref(&self) -> &T {
self
}
}
impl<'cell, T> AsMut<T> for LoopCellAccess<'cell, T> {
#[inline]
fn as_mut(&mut self) -> &mut T {
self
}
}
impl<'cell, T> Drop for LoopCellAccess<'cell, T> {
fn drop(&mut self) {
if let Some(v) = self.value.take() {
self.loop_cell.0.set(Some(v))
}
}
}
#[clippy::has_significant_drop]
pub struct LoopCellMappedAccess<'cell, T, V = ()> {
bare_access: LoopCellAccess<'cell, T>,
value: V,
}
impl<'cell, T, V> LoopCellMappedAccess<'cell, T, V> {
#[inline]
pub fn map_loopcell_access<O>(
self,
f: impl FnOnce(&mut T, V) -> O,
) -> LoopCellMappedAccess<'cell, T, O> {
let Self {
mut bare_access,
value,
} = self;
let o = f(&mut bare_access, value);
LoopCellMappedAccess {
bare_access,
value: o,
}
}
#[inline]
pub fn commit(self) -> V {
self.bare_access.commit();
self.value
}
#[inline]
pub fn consume(self) -> (T, V) {
let cell_v = self.bare_access.consume();
(cell_v, self.value)
}
#[inline]
pub fn get_loopcell_value(&self) -> &T {
&self.bare_access
}
#[inline]
pub fn get_loopcell_value_mut(&mut self) -> &mut T {
&mut self.bare_access
}
#[inline]
pub fn get_value(&self) -> &V {
&self.value
}
#[inline]
pub fn get_value_mut(&mut self) -> &mut V {
&mut self.value
}
#[inline]
pub fn unmap_access(self) -> (LoopCellAccess<'cell, T>, V) {
(self.bare_access, self.value)
}
}
impl<'cell, T, V: Default> From<LoopCellAccess<'cell, T>> for LoopCellMappedAccess<'cell, T, V> {
#[inline]
fn from(bare_access: LoopCellAccess<'cell, T>) -> Self {
Self {
bare_access,
value: Default::default(),
}
}
}
impl<'cell, T, V> Deref for LoopCellMappedAccess<'cell, T, V> {
type Target = V;
#[inline]
fn deref(&self) -> &Self::Target {
self.get_value()
}
}
impl<'cell, T, V> DerefMut for LoopCellMappedAccess<'cell, T, V> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_value_mut()
}
}
impl<'cell, T, V> AsRef<V> for LoopCellMappedAccess<'cell, T, V> {
#[inline]
fn as_ref(&self) -> &V {
self
}
}
impl<'cell, T, V> AsMut<V> for LoopCellMappedAccess<'cell, T, V> {
#[inline]
fn as_mut(&mut self) -> &mut V {
self
}
}
#[repr(transparent)]
pub struct LoopSyncCell<T>(OptionLock<T>);
impl<T> LoopSyncCell<T> {
#[inline]
pub const fn new(initial_value: T) -> Self {
Self(OptionLock::new(initial_value))
}
#[inline]
pub fn new_default() -> Self
where
T: Default,
{
Self::default()
}
#[inline]
pub const fn new_empty() -> Self {
Self(OptionLock::empty())
}
#[inline]
pub fn access(&self) -> Option<LoopSyncCellAccess<'_, T>> {
let maybe_available = self.0.spin_lock().take();
maybe_available.map(|value| LoopSyncCellAccess::new(self, value))
}
}
impl<T: Copy + Debug> Debug for LoopSyncCell<T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("LoopSyncCell").field(&self.0).finish()
}
}
impl<T> From<T> for LoopSyncCell<T> {
#[inline]
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: Default> Default for LoopSyncCell<T> {
#[inline]
fn default() -> Self {
Self::new(T::default())
}
}
#[clippy::has_significant_drop]
pub struct LoopSyncCellAccess<'cell, T> {
loop_cell: &'cell LoopSyncCell<T>,
value: Option<T>,
}
impl<'cell, T> LoopSyncCellAccess<'cell, T> {
#[inline]
const fn new(cell: &'cell LoopSyncCell<T>, value: T) -> Self {
Self {
loop_cell: cell,
value: Some(value),
}
}
#[inline]
pub fn commit(self) {
mem::drop(self)
}
#[inline]
pub fn consume(mut self) -> T {
self.value
.take()
.expect("value inside loop cell accessor should always be Some")
}
#[inline]
pub fn into_mapped_access(self) -> LoopSyncCellMappedAccess<'cell, T, ()> {
self.into()
}
#[inline]
pub fn map_loopcell_access<O>(
mut self,
f: impl FnOnce(&mut T) -> O,
) -> LoopSyncCellMappedAccess<'cell, T, O> {
let o = f(&mut self);
LoopSyncCellMappedAccess {
bare_access: self,
value: o,
}
}
#[inline]
pub fn as_loopcell_value(&self) -> &T {
self
}
#[inline]
pub fn as_loopcell_value_mut(&mut self) -> &mut T {
self
}
}
impl<'cell, T: Debug> Debug for LoopSyncCellAccess<'cell, T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LoopSyncCellAccess")
.field("loop_cell", &"<opaque>")
.field("value", &self.value)
.finish()
}
}
impl<'cell, T> Deref for LoopSyncCellAccess<'cell, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value
.as_ref()
.expect("value should always be Some inside loopcell accessor")
}
}
impl<'cell, T> DerefMut for LoopSyncCellAccess<'cell, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.value
.as_mut()
.expect("value should always be Some inside loopcell accessor")
}
}
impl<'cell, T> AsRef<T> for LoopSyncCellAccess<'cell, T> {
#[inline]
fn as_ref(&self) -> &T {
self
}
}
impl<'cell, T> AsMut<T> for LoopSyncCellAccess<'cell, T> {
#[inline]
fn as_mut(&mut self) -> &mut T {
self
}
}
impl<'cell, T> Drop for LoopSyncCellAccess<'cell, T> {
fn drop(&mut self) {
if let Some(v) = self.value.take() {
self.loop_cell.0.spin_lock().replace(v);
}
}
}
#[clippy::has_significant_drop]
pub struct LoopSyncCellMappedAccess<'cell, T, V = ()> {
bare_access: LoopSyncCellAccess<'cell, T>,
value: V,
}
impl<'cell, T, V> LoopSyncCellMappedAccess<'cell, T, V> {
#[inline]
pub fn map_loopcell_access<O>(
self,
f: impl FnOnce(&mut T, V) -> O,
) -> LoopSyncCellMappedAccess<'cell, T, O> {
let Self {
mut bare_access,
value,
} = self;
let o = f(&mut bare_access, value);
LoopSyncCellMappedAccess {
bare_access,
value: o,
}
}
#[inline]
pub fn commit(self) -> V {
self.bare_access.commit();
self.value
}
#[inline]
pub fn consume(self) -> (T, V) {
let cell_v = self.bare_access.consume();
(cell_v, self.value)
}
#[inline]
pub fn get_loopcell_value(&self) -> &T {
&self.bare_access
}
#[inline]
pub fn get_loopcell_value_mut(&mut self) -> &mut T {
&mut self.bare_access
}
#[inline]
pub fn get_value(&self) -> &V {
&self.value
}
#[inline]
pub fn get_value_mut(&mut self) -> &mut V {
&mut self.value
}
#[inline]
pub fn unmap_access(self) -> (LoopSyncCellAccess<'cell, T>, V) {
(self.bare_access, self.value)
}
}
impl<'cell, T, V: Default> From<LoopSyncCellAccess<'cell, T>>
for LoopSyncCellMappedAccess<'cell, T, V>
{
#[inline]
fn from(bare_access: LoopSyncCellAccess<'cell, T>) -> Self {
Self {
bare_access,
value: Default::default(),
}
}
}
impl<'cell, T, V> Deref for LoopSyncCellMappedAccess<'cell, T, V> {
type Target = V;
#[inline]
fn deref(&self) -> &Self::Target {
self.get_value()
}
}
impl<'cell, T, V> DerefMut for LoopSyncCellMappedAccess<'cell, T, V> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_value_mut()
}
}
impl<'cell, T, V> AsRef<V> for LoopSyncCellMappedAccess<'cell, T, V> {
#[inline]
fn as_ref(&self) -> &V {
self
}
}
impl<'cell, T, V> AsMut<V> for LoopSyncCellMappedAccess<'cell, T, V> {
#[inline]
fn as_mut(&mut self) -> &mut V {
self
}
}