#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc;
use core::fmt;
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
use smr_swap::{LocalReader, ReadGuard, ReaderFactory as SmrReader, SmrSwap};
#[cfg(feature = "std")]
use std::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::sync::Arc;
pub struct LfrLock<T: 'static, const RP: bool = false> {
swap: Arc<Mutex<SmrSwap<T, RP>>>,
local: LocalReader<T, RP>,
}
impl<T: 'static> LfrLock<T, false> {
#[inline]
pub fn new(initial: T) -> Self {
let swap = SmrSwap::new(initial);
let local = swap.local_reader();
LfrLock {
swap: Arc::new(Mutex::new(swap)),
local,
}
}
}
impl<T: 'static> LfrLock<T, true> {
#[inline]
pub fn new_read_preferred(initial: T) -> Self {
let swap = SmrSwap::new_read_preferred(initial);
let local = swap.local_reader();
LfrLock {
swap: Arc::new(Mutex::new(swap)),
local,
}
}
}
impl<T: 'static, const RP: bool> LfrLock<T, RP> {
#[inline]
pub fn store(&self, new_value: T) {
let mut swap = self.swap.lock();
swap.store(new_value);
}
#[inline]
pub fn swap(&self, new_value: T) -> T
where
T: Clone,
{
self.swap.lock().swap(new_value)
}
#[inline]
pub fn update<F>(&self, f: F)
where
F: FnOnce(&T) -> T,
{
self.swap.lock().update(f);
}
#[inline]
pub fn update_and_fetch<F>(&self, f: F) -> ReadGuard<'_, T, RP>
where
F: FnOnce(&T) -> T,
{
self.swap.lock().update(f);
self.local.load()
}
#[inline]
pub fn fetch_and_update<F>(&self, f: F) -> ReadGuard<'_, T, RP>
where
F: FnOnce(&T) -> T,
{
let old_guard = self.local.load();
self.swap.lock().update(f);
old_guard
}
#[inline]
pub fn map<F, U>(&self, f: F) -> U
where
F: FnOnce(&T) -> U,
{
let guard = self.local.load();
f(&*guard)
}
#[inline]
pub fn filter<F>(&self, f: F) -> Option<ReadGuard<'_, T, RP>>
where
F: FnOnce(&T) -> bool,
{
let guard = self.local.load();
if f(&*guard) { Some(guard) } else { None }
}
#[inline]
pub fn get(&self) -> T
where
T: Clone,
{
(*self.local.load()).clone()
}
#[inline]
pub fn write(&self) -> WriteGuard<'_, T, RP>
where
T: Clone,
{
WriteGuard::new(self)
}
#[inline]
pub fn try_write(&self) -> Option<WriteGuard<'_, T, RP>>
where
T: Clone,
{
let swap_guard = self.swap.try_lock().ok()?;
let guard = self.local.load();
let data = (*guard).clone();
Some(WriteGuard {
swap_guard,
data: ManuallyDrop::new(data),
})
}
#[inline]
pub fn read(&self) -> ReadGuard<'_, T, RP> {
self.local.load()
}
#[inline]
pub fn factory(&self) -> LfrLockFactory<T, RP> {
LfrLockFactory {
swap: self.swap.clone(),
reader: self.local.reader_factory(),
}
}
}
impl<T: Default + 'static> Default for LfrLock<T, false> {
#[inline]
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: 'static> From<T> for LfrLock<T, false> {
#[inline]
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: fmt::Debug + 'static, const RP: bool> fmt::Debug for LfrLock<T, RP> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let data = self.read();
f.debug_struct("LfrLock").field("data", &*data).finish()
}
}
impl<T: 'static, const RP: bool> Clone for LfrLock<T, RP> {
#[inline]
fn clone(&self) -> Self {
Self {
swap: self.swap.clone(),
local: self.local.clone(),
}
}
}
pub struct WriteGuard<'a, T: 'static, const RP: bool = false> {
swap_guard: MutexGuard<'a, SmrSwap<T, RP>>,
data: ManuallyDrop<T>,
}
impl<'a, T: 'static + Clone, const RP: bool> WriteGuard<'a, T, RP> {
#[inline]
fn new(lock: &'a LfrLock<T, RP>) -> Self {
let swap_guard = lock.swap.lock();
let guard = lock.local.load();
let data = (*guard).clone();
WriteGuard {
swap_guard,
data: ManuallyDrop::new(data),
}
}
}
impl<'a, T: 'static, const RP: bool> Deref for WriteGuard<'a, T, RP> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<'a, T: 'static, const RP: bool> DerefMut for WriteGuard<'a, T, RP> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<'a, T: 'static, const RP: bool> Drop for WriteGuard<'a, T, RP> {
#[inline]
fn drop(&mut self) {
let new_data = unsafe { ManuallyDrop::take(&mut self.data) };
self.swap_guard.store(new_data);
}
}
pub struct LfrLockFactory<T: 'static, const RP: bool = false> {
swap: Arc<Mutex<SmrSwap<T, RP>>>,
reader: SmrReader<T, RP>,
}
impl<T: 'static> LfrLockFactory<T, false> {
#[inline]
pub fn new(initial: T) -> Self {
let swap = SmrSwap::new(initial);
let reader = swap.reader_factory();
Self {
swap: Arc::new(Mutex::new(swap)),
reader,
}
}
}
impl<T: 'static, const RP: bool> LfrLockFactory<T, RP> {
#[inline]
pub fn create(&self) -> LfrLock<T, RP> {
LfrLock {
swap: self.swap.clone(),
local: self.reader.local_reader(),
}
}
}
impl<T: 'static, const RP: bool> Clone for LfrLockFactory<T, RP> {
#[inline]
fn clone(&self) -> Self {
Self {
swap: self.swap.clone(),
reader: self.reader.clone(),
}
}
}
#[cfg(feature = "parking_lot")]
mod lock_impl {
use core::ops::{Deref, DerefMut};
pub struct Mutex<T: ?Sized>(parking_lot::Mutex<T>);
impl<T> Mutex<T> {
#[inline]
pub fn new(t: T) -> Mutex<T> {
Mutex(parking_lot::Mutex::new(t))
}
}
impl<T: ?Sized> Mutex<T> {
#[inline]
pub fn lock(&self) -> MutexGuard<'_, T> {
MutexGuard(self.0.lock())
}
#[inline]
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
match self.0.try_lock() {
Some(guard) => Ok(MutexGuard(guard)),
None => Err(TryLockError(())),
}
}
}
#[must_use]
pub struct MutexGuard<'a, T: ?Sized + 'a>(parking_lot::MutexGuard<'a, T>);
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&*self.0
}
}
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut *self.0
}
}
pub type TryLockResult<T> = Result<T, TryLockError>;
#[derive(Debug)]
pub struct TryLockError(());
}
#[cfg(all(feature = "std", not(feature = "parking_lot")))]
mod lock_impl {
use std::ops::{Deref, DerefMut};
pub struct Mutex<T: ?Sized>(std::sync::Mutex<T>);
impl<T> Mutex<T> {
#[inline]
pub fn new(t: T) -> Mutex<T> {
Mutex(std::sync::Mutex::new(t))
}
}
impl<T: ?Sized> Mutex<T> {
#[inline]
pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
MutexGuard(self.0.lock().unwrap_or_else(|e| e.into_inner()))
}
#[inline]
pub fn try_lock<'a>(&'a self) -> TryLockResult<MutexGuard<'a, T>> {
match self.0.try_lock() {
Ok(t) => Ok(MutexGuard(t)),
Err(std::sync::TryLockError::Poisoned(e)) => Ok(MutexGuard(e.into_inner())),
Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError(())),
}
}
}
#[must_use]
pub struct MutexGuard<'a, T: ?Sized + 'a>(std::sync::MutexGuard<'a, T>);
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.0.deref()
}
}
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.0.deref_mut()
}
}
pub type TryLockResult<T> = Result<T, TryLockError>;
#[derive(Debug)]
pub struct TryLockError(());
}
#[cfg(all(not(feature = "std"), not(feature = "parking_lot")))]
mod lock_impl {
use core::ops::{Deref, DerefMut};
pub struct Mutex<T: ?Sized>(spin::Mutex<T>);
impl<T> Mutex<T> {
#[inline]
pub fn new(t: T) -> Mutex<T> {
Mutex(spin::Mutex::new(t))
}
}
impl<T: ?Sized> Mutex<T> {
#[inline]
pub fn lock(&self) -> MutexGuard<'_, T> {
MutexGuard(self.0.lock())
}
#[inline]
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
match self.0.try_lock() {
Some(guard) => Ok(MutexGuard(guard)),
None => Err(TryLockError(())),
}
}
}
#[must_use]
pub struct MutexGuard<'a, T: ?Sized + 'a>(spin::MutexGuard<'a, T>);
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&*self.0
}
}
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut *self.0
}
}
pub type TryLockResult<T> = Result<T, TryLockError>;
#[derive(Debug)]
pub struct TryLockError(());
}
use lock_impl::*;