use core::{
fmt,
future::Future,
mem,
ops::{Deref, DerefMut, Range},
pin::Pin,
ptr::NonNull,
task::{Context, Poll},
};
use futures::{future::FusedFuture, ready};
use stable_deref_trait::StableDeref;
use crate::raw::{self, RawAsyncIntervalRwLock, RawBlockingIntervalRwLock, RawIntervalRwLock};
#[cfg(test)]
mod tests;
if_alloc! {
use alloc::boxed::Box;
use crate::utils::PinDerefMut;
#[pin_project::pin_project]
struct WithState<LockGuard, State> {
guard: Option<LockGuard>,
#[pin]
state: State,
_phantom: core::marker::PhantomPinned,
}
impl<LockGuard, State: Default> Default for WithState<LockGuard, State> {
#[inline]
fn default() -> Self {
Self {
guard: None,
state: State::default(),
_phantom: core::marker::PhantomPinned,
}
}
}
impl<LockGuard: Deref, State> Deref for WithState<LockGuard, State> {
type Target = LockGuard::Target;
#[inline]
fn deref(&self) -> &Self::Target {
self.guard.as_ref().unwrap()
}
}
impl<LockGuard: DerefMut, State> PinDerefMut for WithState<LockGuard, State> {
#[inline]
fn pin_deref_mut(self: Pin<&mut Self>) -> &mut Self::Target {
self.project().guard.as_mut().unwrap()
}
}
#[inline]
unsafe fn transmute_lifetime_mut<'a, T: ?Sized>(x: Pin<&mut T>) -> Pin<&'a mut T> {
unsafe { Pin::new_unchecked(&mut *( x.get_unchecked_mut() as *mut T)) }
}
}
#[pin_project::pin_project]
pub struct SliceIntervalRwLock<Container, Element, RawLock> {
container: Container,
#[pin]
raw: RawLock,
ptr: NonNull<[Element]>,
}
unsafe impl<Container: Send, RawLock: Send, Element: Send> Send
for SliceIntervalRwLock<Container, Element, RawLock>
{
}
unsafe impl<Container: Sync, RawLock: Sync, Element: Send + Sync> Sync
for SliceIntervalRwLock<Container, Element, RawLock>
{
}
impl<Container, Element, RawLock> SliceIntervalRwLock<Container, Element, RawLock>
where
Container: Deref<Target = [Element]> + DerefMut + StableDeref,
RawLock: RawIntervalRwLock<Index = usize>,
{
#[inline]
pub fn new(mut container: Container) -> Self {
Self {
ptr: NonNull::from(&mut *container),
container,
raw: RawLock::INIT,
}
}
#[inline]
pub fn replace_container(self: Pin<&mut Self>, mut container: Container) -> Container {
let this = self.project();
let ptr = NonNull::from(&mut *container);
let old_container = mem::replace(this.container, container);
*this.ptr = ptr;
old_container
}
#[inline]
pub fn take_container(self: Pin<&mut Self>) -> Container
where
Container: Default,
{
self.replace_container(Container::default())
}
#[inline]
pub fn update_container<R>(
self: Pin<&mut Self>,
updater: impl FnOnce(&mut Container) -> R,
) -> R {
struct Guard<'a, Container: DerefMut>(
&'a mut Container,
&'a mut NonNull<Container::Target>,
);
let this = self.project();
let guard = Guard(this.container, this.ptr);
let output = updater(guard.0);
impl<Container: DerefMut> Drop for Guard<'_, Container> {
fn drop(&mut self) {
*self.1 = NonNull::from(&mut **self.0);
}
}
output
}
#[inline]
pub fn len(&self) -> usize {
self.ptr.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn as_ptr(&self) -> *mut [Element] {
self.ptr.as_ptr()
}
#[inline]
pub fn as_non_null_ptr(&self) -> NonNull<[Element]> {
self.ptr
}
#[inline]
pub fn get_mut(self: Pin<&mut Self>) -> &mut [Element] {
unsafe { self.project().ptr.as_mut() }
}
#[inline]
fn slice(&self, range: Range<usize>) -> NonNull<[Element]> {
let ptr = self.ptr;
assert!(
range.start <= range.end && range.end <= ptr.len(),
"out of bounds"
);
unsafe { ptr.get_unchecked_mut(range) }
}
pub fn try_read<'a>(
self: Pin<&'a Self>,
range: Range<usize>,
mut lock_state: Pin<&'a mut RawLock::TryReadLockState>,
) -> Result<TryReadLockGuard<'a, Element, RawLock, RawLock::TryReadLockState>, TryLockError>
{
let this = self.project_ref();
let ptr = self.slice(range.clone()); if this.raw.try_lock_read(range, Pin::as_mut(&mut lock_state)) {
Ok(TryReadLockGuard {
lock_state,
raw: this.raw,
ptr,
})
} else {
Err(TryLockError::WouldBlock)
}
}
pub fn try_write<'a>(
self: Pin<&'a Self>,
range: Range<usize>,
mut lock_state: Pin<&'a mut RawLock::TryWriteLockState>,
) -> Result<TryWriteLockGuard<'a, Element, RawLock, RawLock::TryWriteLockState>, TryLockError>
{
let this = self.project_ref();
let ptr = self.slice(range.clone()); if this.raw.try_lock_write(range, Pin::as_mut(&mut lock_state)) {
Ok(TryWriteLockGuard {
lock_state,
raw: this.raw,
ptr,
})
} else {
Err(TryLockError::WouldBlock)
}
}
if_alloc! {
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub fn try_read_boxed(
self: Pin<&Self>,
range: Range<usize>,
) -> Result<Pin<Box<impl Deref<Target = [Element]> + '_>>, TryLockError>
{
let mut guard_with_state = Box::pin(WithState::default());
{
let guard_with_state = WithState::project(Pin::as_mut(&mut guard_with_state));
let state = unsafe { transmute_lifetime_mut(guard_with_state.state) };
*guard_with_state.guard = Some(self.try_read(range, state)?);
}
Ok(guard_with_state)
}
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub fn try_write_boxed(
self: Pin<&Self>,
range: Range<usize>,
) -> Result<Pin<Box<impl PinDerefMut<Target = [Element]> + '_>>, TryLockError>
{
let mut guard_with_state = Box::pin(WithState::default());
{
let guard_with_state = WithState::project(Pin::as_mut(&mut guard_with_state));
let state = unsafe { transmute_lifetime_mut(guard_with_state.state) };
*guard_with_state.guard = Some(self.try_write(range, state)?);
}
Ok(guard_with_state)
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
pub enum TryLockError {
#[cfg_attr(
feature = "std",
error("lock failed because the operation would block")
)]
WouldBlock,
}
impl<Container, Element, RawLock> SliceIntervalRwLock<Container, Element, RawLock>
where
Container: Deref<Target = [Element]> + DerefMut + StableDeref,
RawLock: RawIntervalRwLock<Index = usize> + RawBlockingIntervalRwLock,
{
pub fn read<'a>(
self: Pin<&'a Self>,
range: Range<usize>,
priority: RawLock::Priority,
mut lock_state: Pin<&'a mut RawLock::ReadLockState>,
) -> ReadLockGuard<'a, Element, RawLock, RawLock::ReadLockState> {
let this = self.project_ref();
let ptr = self.slice(range.clone()); this.raw
.lock_read(range, priority, Pin::as_mut(&mut lock_state));
ReadLockGuard {
lock_state,
raw: this.raw,
ptr,
}
}
pub fn write<'a>(
self: Pin<&'a Self>,
range: Range<usize>,
priority: RawLock::Priority,
mut lock_state: Pin<&'a mut RawLock::WriteLockState>,
) -> WriteLockGuard<'a, Element, RawLock, RawLock::WriteLockState> {
let this = self.project_ref();
let ptr = self.slice(range.clone()); this.raw
.lock_write(range, priority, Pin::as_mut(&mut lock_state));
WriteLockGuard {
lock_state,
raw: this.raw,
ptr,
}
}
if_alloc! {
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub fn read_boxed(
self: Pin<&Self>,
range: Range<usize>,
priority: RawLock::Priority,
) -> Pin<Box<impl Deref<Target = [Element]> + '_>>
{
let mut guard_with_state = Box::pin(WithState::default());
{
let guard_with_state = WithState::project(Pin::as_mut(&mut guard_with_state));
let state = unsafe { transmute_lifetime_mut(guard_with_state.state) };
*guard_with_state.guard = Some(self.read(range, priority, state));
}
guard_with_state
}
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub fn write_boxed(
self: Pin<&Self>,
range: Range<usize>,
priority: RawLock::Priority,
) -> Pin<Box<impl PinDerefMut<Target = [Element]> + '_>>
{
let mut guard_with_state = Box::pin(WithState::default());
{
let guard_with_state = WithState::project(Pin::as_mut(&mut guard_with_state));
let state = unsafe { transmute_lifetime_mut(guard_with_state.state) };
*guard_with_state.guard = Some(self.write(range, priority, state));
}
guard_with_state
}
}
}
impl<Container, Element, RawLock> SliceIntervalRwLock<Container, Element, RawLock>
where
Container: Deref<Target = [Element]> + DerefMut + StableDeref,
RawLock: RawIntervalRwLock<Index = usize> + RawAsyncIntervalRwLock,
{
pub fn async_read<'a>(
self: Pin<&'a Self>,
range: Range<usize>,
priority: RawLock::Priority,
mut lock_state: Pin<&'a mut RawLock::ReadLockState>,
) -> ReadLockFuture<'a, Element, RawLock, RawLock::ReadLockState> {
let this = self.project_ref();
let ptr = self.slice(range.clone()); this.raw
.start_lock_read(range, priority, Pin::as_mut(&mut lock_state));
ReadLockFuture {
guard: Some(AsyncReadLockGuard {
lock_state,
raw: this.raw,
ptr,
}),
}
}
pub fn async_write<'a>(
self: Pin<&'a Self>,
range: Range<usize>,
priority: RawLock::Priority,
mut lock_state: Pin<&'a mut RawLock::WriteLockState>,
) -> WriteLockFuture<'a, Element, RawLock, RawLock::WriteLockState> {
let this = self.project_ref();
let ptr = self.slice(range.clone()); this.raw
.start_lock_write(range, priority, Pin::as_mut(&mut lock_state));
WriteLockFuture {
guard: Some(AsyncWriteLockGuard {
lock_state,
raw: this.raw,
ptr,
}),
}
}
if_alloc! {
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub async fn async_read_boxed(
self: Pin<&Self>,
range: Range<usize>,
priority: RawLock::Priority,
) -> Pin<Box<impl Deref<Target = [Element]> + '_>>
{
let mut guard_with_state = Box::pin(WithState::default());
{
let guard_with_state = WithState::project(Pin::as_mut(&mut guard_with_state));
let state = unsafe { transmute_lifetime_mut(guard_with_state.state) };
*guard_with_state.guard = Some(self.async_read(range, priority, state).await);
}
guard_with_state
}
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub async fn async_write_boxed(
self: Pin<&Self>,
range: Range<usize>,
priority: RawLock::Priority,
) -> Pin<Box<impl PinDerefMut<Target = [Element]> + '_>>
{
let mut guard_with_state = Box::pin(WithState::default());
{
let guard_with_state = WithState::project(Pin::as_mut(&mut guard_with_state));
let state = unsafe { transmute_lifetime_mut(guard_with_state.state) };
*guard_with_state.guard = Some(self.async_write(range, priority, state).await);
}
guard_with_state
}
}
}
macro_rules! define_lock_future {
(
$( #[$meta:meta] )*
pub struct $ident:ident<'_, Element, RawLock, LockState>
where
RawLock: [$($raw_lock_bounds:tt)*]
{
guard: $guard_ty:ident,
}
impl Future for _ { => $poll_method:ident }
) => {
$( #[$meta] )*
pub struct $ident<'a, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
guard: Option<$guard_ty<'a, Element, RawLock, LockState>>,
}
impl<'a, Element, RawLock, LockState> Future
for $ident<'a, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
type Output = $guard_ty<'a, Element, RawLock, LockState>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = Pin::into_inner(self);
let guard = this.guard.as_mut().expect("future polled after completion");
ready!(guard.raw.$poll_method(Pin::as_mut(&mut guard.lock_state), cx));
Poll::Ready(this.guard.take().unwrap())
}
}
impl<'a, Element, RawLock, LockState> FusedFuture
for $ident<'a, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
#[inline]
fn is_terminated(&self) -> bool {
self.guard.is_none()
}
}
};
}
define_lock_future! {
pub struct ReadLockFuture<'_, Element, RawLock, LockState>
where
RawLock: [RawAsyncIntervalRwLock<Index = usize, ReadLockState = LockState>]
{
guard: AsyncReadLockGuard,
}
impl Future for _ { => poll_lock_read }
}
define_lock_future! {
pub struct WriteLockFuture<'_, Element, RawLock, LockState>
where
RawLock: [RawAsyncIntervalRwLock<Index = usize, WriteLockState = LockState>]
{
guard: AsyncWriteLockGuard,
}
impl Future for _ { => poll_lock_write }
}
macro_rules! define_lock_guard {
(
$( #[$meta:meta] )*
pub struct $ident:ident<'_, Element, RawLock, LockState>
where
RawLock: [$($raw_lock_bounds:tt)*];
impl $deref:tt for _;
impl Drop for _ { => $unlock_method:ident }
) => {
$( #[$meta] )*
pub struct $ident<'a, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
lock_state: Pin<&'a mut LockState>,
raw: Pin<&'a RawLock>,
ptr: NonNull<[Element]>,
}
unsafe impl<Element: Send + Sync, RawLock: Sync, LockState: Send> Send
for $ident<'_, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
}
unsafe impl<Element: Send + Sync, RawLock: Sync, LockState: Sync> Sync
for $ident<'_, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
}
define_lock_guard!(@deref $deref [$($raw_lock_bounds)*] $ident);
impl<Element, RawLock, LockState> fmt::Debug for $ident<'_, Element, RawLock, LockState>
where
Element: fmt::Debug,
RawLock: $($raw_lock_bounds)*,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<Element, RawLock, LockState> Drop for $ident<'_, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
#[inline]
fn drop(&mut self) {
self.raw.$unlock_method(Pin::as_mut(&mut self.lock_state));
}
}
};
(@deref DerefMut [$($raw_lock_bounds:tt)*] $ident:ident) => {
impl<Element, RawLock, LockState> DerefMut for $ident<'_, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
define_lock_guard!(@deref Deref [$($raw_lock_bounds)*] $ident);
};
(@deref Deref [$($raw_lock_bounds:tt)*] $ident:ident) => {
impl<Element, RawLock, LockState> Deref for $ident<'_, Element, RawLock, LockState>
where
RawLock: $($raw_lock_bounds)*,
{
type Target = [Element];
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
};
}
define_lock_guard! {
pub struct TryReadLockGuard<'_, Element, RawLock, LockState>
where
RawLock: [RawIntervalRwLock<Index = usize, TryReadLockState = LockState>];
impl Deref for _;
impl Drop for _ { => unlock_try_read }
}
define_lock_guard! {
pub struct TryWriteLockGuard<'_, Element, RawLock, LockState>
where
RawLock: [RawIntervalRwLock<Index = usize, TryWriteLockState = LockState>];
impl DerefMut for _;
impl Drop for _ { => unlock_try_write }
}
define_lock_guard! {
pub struct ReadLockGuard<'_, Element, RawLock, LockState>
where
RawLock: [RawBlockingIntervalRwLock<Index = usize, ReadLockState = LockState>];
impl Deref for _;
impl Drop for _ { => unlock_read }
}
define_lock_guard! {
pub struct WriteLockGuard<'_, Element, RawLock, LockState>
where
RawLock: [RawBlockingIntervalRwLock<Index = usize, WriteLockState = LockState>];
impl DerefMut for _;
impl Drop for _ { => unlock_write }
}
define_lock_guard! {
pub struct AsyncReadLockGuard<'_, Element, RawLock, LockState>
where
RawLock: [RawAsyncIntervalRwLock<Index = usize, ReadLockState = LockState>];
impl Deref for _;
impl Drop for _ { => unlock_read }
}
define_lock_guard! {
pub struct AsyncWriteLockGuard<'_, Element, RawLock, LockState>
where
RawLock: [RawAsyncIntervalRwLock<Index = usize, WriteLockState = LockState>];
impl DerefMut for _;
impl Drop for _ { => unlock_write }
}
mod hidden {
pub trait DerefToSlice {
type Element;
}
impl<Element, T: ?Sized + core::ops::DerefMut<Target = [Element]>> DerefToSlice for T {
type Element = Element;
}
}
pub type LocalRbTreeSliceIntervalRwLock<Container> = SliceIntervalRwLock<
Container,
<Container as hidden::DerefToSlice>::Element,
raw::local::LocalRawRbTreeIntervalRwLock<usize>,
>;
#[cfg(feature = "std")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "std")))]
pub type SyncRbTreeSliceIntervalRwLock<Container, Priority = ()> = SliceIntervalRwLock<
Container,
<Container as hidden::DerefToSlice>::Element,
raw::sync::SyncRawRbTreeIntervalRwLock<usize, Priority>,
>;
#[cfg(feature = "async")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "async")))]
pub type AsyncRbTreeSliceIntervalRwLock<RawMutex, Container, Priority = ()> = SliceIntervalRwLock<
Container,
<Container as hidden::DerefToSlice>::Element,
raw::future::AsyncRawRbTreeIntervalRwLock<RawMutex, usize, Priority>,
>;
pub type LocalRbTreeSliceRefIntervalRwLock<'a, Element> = SliceIntervalRwLock<
&'a mut [Element],
Element,
raw::local::LocalRawRbTreeIntervalRwLock<usize>,
>;
#[cfg(feature = "std")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "std")))]
pub type SyncRbTreeSliceRefIntervalRwLock<'a, Element, Priority = ()> = SliceIntervalRwLock<
&'a mut [Element],
Element,
raw::sync::SyncRawRbTreeIntervalRwLock<usize, Priority>,
>;
#[cfg(feature = "async")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "async")))]
pub type AsyncRbTreeSliceRefIntervalRwLock<'a, RawMutex, Element, Priority = ()> =
SliceIntervalRwLock<
&'a mut [Element],
Element,
raw::future::AsyncRawRbTreeIntervalRwLock<RawMutex, usize, Priority>,
>;
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "alloc")))]
pub type LocalRbTreeVecIntervalRwLock<Element> = SliceIntervalRwLock<
alloc::vec::Vec<Element>,
Element,
raw::local::LocalRawRbTreeIntervalRwLock<usize>,
>;
#[cfg(feature = "std")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "std")))]
pub type SyncRbTreeVecIntervalRwLock<Element, Priority = ()> = SliceIntervalRwLock<
alloc::vec::Vec<Element>,
Element,
raw::sync::SyncRawRbTreeIntervalRwLock<usize, Priority>,
>;
#[cfg(all(feature = "async", feature = "alloc"))]
#[cfg_attr(
feature = "doc_cfg",
doc(cfg(all(feature = "async", feature = "alloc")))
)]
pub type AsyncRbTreeVecIntervalRwLock<RawMutex, Element, Priority = ()> = SliceIntervalRwLock<
alloc::vec::Vec<Element>,
Element,
raw::future::AsyncRawRbTreeIntervalRwLock<RawMutex, usize, Priority>,
>;