use core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
use crate::{
details::{ImplConcurrent, ImplDefault, ImplDetails, StorageDetails},
error::{LockSource, LockingError, RegionBorrowed},
range::ByteRange,
types::*,
};
pub trait ContiguousMemoryReference<T: ?Sized, Impl: ImplDetails> {
type BorrowError;
fn range(&self) -> ByteRange;
fn get<'a>(&'a self) -> Impl::LockResult<MemoryReadGuard<'a, T, Impl>>
where
T: RefSizeReq;
fn try_get<'a>(&'a self) -> Result<MemoryReadGuard<'a, T, Impl>, Self::BorrowError>
where
T: RefSizeReq;
fn get_mut<'a>(&'a mut self) -> Impl::LockResult<MemoryWriteGuard<'a, T, Impl>>
where
T: RefSizeReq;
fn try_get_mut<'a>(&'a mut self) -> Result<MemoryWriteGuard<'a, T, Impl>, Self::BorrowError>
where
T: RefSizeReq;
#[cfg(feature = "ptr_metadata")]
fn into_dyn<R: ?Sized>(self) -> Impl::ReferenceType<R>
where
T: Sized + Unsize<R>;
}
pub struct SyncContiguousMemoryRef<T: ?Sized> {
pub(crate) inner: Arc<ReferenceState<T, ImplConcurrent>>,
#[cfg(feature = "ptr_metadata")]
pub(crate) metadata: <T as Pointee>::Metadata,
#[cfg(not(feature = "ptr_metadata"))]
pub(crate) _phantom: PhantomData<T>,
}
pub type SCMRef<T> = SyncContiguousMemoryRef<T>;
impl<T: ?Sized> ContiguousMemoryReference<T, ImplConcurrent> for SyncContiguousMemoryRef<T> {
type BorrowError = LockingError;
fn range(&self) -> ByteRange {
self.inner.range
}
fn get<'a>(&'a self) -> Result<MemoryReadGuard<'a, T, ImplConcurrent>, LockingError>
where
T: RefSizeReq,
{
let guard = self.inner.borrow_kind.read_named(LockSource::Reference)?;
unsafe {
let base = ImplConcurrent::get_base(&self.inner.state.base)?;
let pos = base.add(self.inner.range.0);
Ok(MemoryReadGuard {
state: self.inner.clone(),
guard,
#[cfg(not(feature = "ptr_metadata"))]
value: &*(pos as *mut T),
#[cfg(feature = "ptr_metadata")]
value: &*core::ptr::from_raw_parts(pos as *const (), self.metadata),
})
}
}
fn try_get<'a>(&'a self) -> Result<MemoryReadGuard<'a, T, ImplConcurrent>, LockingError>
where
T: RefSizeReq,
{
let guard = self
.inner
.borrow_kind
.try_read_named(LockSource::Reference)?;
unsafe {
let base = ImplConcurrent::get_base(&self.inner.state.base)?;
let pos = base.add(self.inner.range.0);
Ok(MemoryReadGuard {
state: self.inner.clone(),
guard,
#[cfg(not(feature = "ptr_metadata"))]
value: &*(pos as *mut T),
#[cfg(feature = "ptr_metadata")]
value: &*core::ptr::from_raw_parts(pos as *const (), self.metadata),
})
}
}
fn get_mut<'a>(&'a mut self) -> Result<MemoryWriteGuard<'a, T, ImplConcurrent>, LockingError>
where
T: RefSizeReq,
{
let guard = self.inner.borrow_kind.write_named(LockSource::Reference)?;
unsafe {
let base = ImplConcurrent::get_base(&self.inner.state.base)?;
let pos = base.add(self.inner.range.0);
Ok(MemoryWriteGuard {
state: self.inner.clone(),
guard,
#[cfg(not(feature = "ptr_metadata"))]
value: &mut *(pos as *mut T),
#[cfg(feature = "ptr_metadata")]
value: &mut *core::ptr::from_raw_parts_mut::<T>(pos as *mut (), self.metadata),
})
}
}
fn try_get_mut<'a>(
&'a mut self,
) -> Result<MemoryWriteGuard<'a, T, ImplConcurrent>, LockingError>
where
T: RefSizeReq,
{
let guard = self
.inner
.borrow_kind
.try_write_named(LockSource::Reference)?;
unsafe {
let base = ImplConcurrent::get_base(&self.inner.state.base)?;
let pos = base.add(self.inner.range.0);
Ok(MemoryWriteGuard {
state: self.inner.clone(),
guard,
#[cfg(not(feature = "ptr_metadata"))]
value: &mut *(pos as *mut T),
#[cfg(feature = "ptr_metadata")]
value: &mut *core::ptr::from_raw_parts_mut::<T>(pos as *mut (), self.metadata),
})
}
}
#[cfg(feature = "ptr_metadata")]
fn into_dyn<R: ?Sized>(self) -> SyncContiguousMemoryRef<R>
where
T: Sized + Unsize<R>,
{
unsafe {
SyncContiguousMemoryRef {
inner: core::mem::transmute(self.inner),
metadata: static_metadata::<T, R>(),
}
}
}
}
impl<T: ?Sized> Clone for SyncContiguousMemoryRef<T> {
fn clone(&self) -> Self {
SyncContiguousMemoryRef {
inner: self.inner.clone(),
#[cfg(feature = "ptr_metadata")]
metadata: self.metadata.clone(),
#[cfg(not(feature = "ptr_metadata"))]
_phantom: PhantomData,
}
}
}
#[cfg(feature = "debug")]
impl<T: ?Sized> core::fmt::Debug for SyncContiguousMemoryRef<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SyncContiguousMemoryRef")
.field("inner", &self.inner)
.finish()
}
}
pub struct ContiguousMemoryRef<T: ?Sized> {
pub(crate) inner: Rc<ReferenceState<T, ImplDefault>>,
#[cfg(feature = "ptr_metadata")]
pub(crate) metadata: <T as Pointee>::Metadata,
#[cfg(not(feature = "ptr_metadata"))]
pub(crate) _phantom: PhantomData<T>,
}
pub type CMRef<T> = ContiguousMemoryRef<T>;
impl<T: ?Sized> ContiguousMemoryReference<T, ImplDefault> for ContiguousMemoryRef<T> {
type BorrowError = RegionBorrowed;
fn range(&self) -> ByteRange {
self.inner.range
}
fn get<'a>(&'a self) -> MemoryReadGuard<'a, T, ImplDefault>
where
T: RefSizeReq,
{
ContiguousMemoryRef::<T>::try_get(self).expect("mutably borrowed")
}
fn try_get<'a>(&'a self) -> Result<MemoryReadGuard<'a, T, ImplDefault>, RegionBorrowed>
where
T: RefSizeReq,
{
let state = self.inner.borrow_kind.get();
if let BorrowState::Read(count) = state {
self.inner.borrow_kind.set(BorrowState::Read(count + 1));
} else {
return Err(RegionBorrowed {
range: self.inner.range,
});
}
unsafe {
let base = ImplDefault::get_base(&self.inner.state.base);
let pos = base.add(self.inner.range.0);
Ok(MemoryReadGuard {
state: self.inner.clone(),
guard: (),
#[cfg(not(feature = "ptr_metadata"))]
value: &*(pos as *mut T),
#[cfg(feature = "ptr_metadata")]
value: &*core::ptr::from_raw_parts_mut::<T>(pos as *mut (), self.metadata),
})
}
}
fn get_mut<'a>(&'a mut self) -> MemoryWriteGuard<'a, T, ImplDefault>
where
T: RefSizeReq,
{
ContiguousMemoryRef::<T>::try_get_mut(self).expect("mutably borrowed")
}
fn try_get_mut<'a>(&'a mut self) -> Result<MemoryWriteGuard<'a, T, ImplDefault>, RegionBorrowed>
where
T: RefSizeReq,
{
if self.inner.borrow_kind.get() != BorrowState::Read(0) {
return Err(RegionBorrowed {
range: self.inner.range,
});
} else {
self.inner.borrow_kind.set(BorrowState::Write);
}
unsafe {
let base = ImplDefault::get_base(&self.inner.state.base);
let pos = base.add(self.inner.range.0);
Ok(MemoryWriteGuard {
state: self.inner.clone(),
guard: (),
#[cfg(not(feature = "ptr_metadata"))]
value: &mut *(pos as *mut T),
#[cfg(feature = "ptr_metadata")]
value: &mut *core::ptr::from_raw_parts_mut::<T>(pos as *mut (), self.metadata),
})
}
}
#[cfg(feature = "ptr_metadata")]
fn into_dyn<R: ?Sized>(self) -> ContiguousMemoryRef<R>
where
T: Sized + Unsize<R>,
{
unsafe {
ContiguousMemoryRef {
inner: core::mem::transmute(self.inner),
metadata: static_metadata::<T, R>(),
}
}
}
}
impl<T: ?Sized> Clone for ContiguousMemoryRef<T> {
fn clone(&self) -> Self {
ContiguousMemoryRef {
inner: self.inner.clone(),
#[cfg(feature = "ptr_metadata")]
metadata: self.metadata.clone(),
#[cfg(not(feature = "ptr_metadata"))]
_phantom: PhantomData,
}
}
}
#[cfg(feature = "debug")]
impl<T: ?Sized> core::fmt::Debug for ContiguousMemoryRef<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ContiguousMemoryRef")
.field("inner", &self.inner)
.finish()
}
}
pub(crate) mod sealed {
use super::*;
pub struct ReferenceState<T: ?Sized, Impl: ImplDetails> {
pub state: Impl::StorageState,
pub range: ByteRange,
pub borrow_kind: Impl::BorrowLock,
#[cfg(feature = "ptr_metadata")]
pub drop_metadata: DynMetadata<dyn HandleDrop>,
pub _phantom: PhantomData<T>,
}
#[cfg(feature = "debug")]
impl<T: ?Sized, Impl: ImplDetails> core::fmt::Debug for ReferenceState<T, Impl>
where
Impl::StorageState: core::fmt::Debug,
Impl::BorrowLock: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ReferenceState")
.field("state", &self.state)
.field("range", &self.range)
.field("borrow_kind", &self.borrow_kind)
.finish()
}
}
impl<T: ?Sized, Impl: ImplDetails> Drop for ReferenceState<T, Impl> {
fn drop(&mut self) {
#[allow(unused_variables)]
if let Some(it) = Impl::free_region(&mut self.state, self.range) {
#[cfg(feature = "ptr_metadata")]
unsafe {
let drop: *mut dyn HandleDrop =
core::ptr::from_raw_parts_mut::<dyn HandleDrop>(it, self.drop_metadata);
(&*drop).do_drop();
}
};
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BorrowKind {
Read,
Write,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BorrowState {
Read(usize),
Write,
}
}
use sealed::*;
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct MemoryWriteGuard<'a, T: ?Sized, Impl: ImplDetails> {
state: Impl::RefState<T>,
#[allow(unused)]
guard: Impl::WriteGuard<'a>,
value: &'a mut T,
}
impl<'a, T: ?Sized, Impl: ImplDetails> Deref for MemoryWriteGuard<'a, T, Impl> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
impl<'a, T: ?Sized, Impl: ImplDetails> DerefMut for MemoryWriteGuard<'a, T, Impl> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.value
}
}
impl<'a, T: ?Sized, Impl: ImplDetails> Drop for MemoryWriteGuard<'a, T, Impl> {
fn drop(&mut self) {
Impl::unborrow_ref::<T>(&self.state, BorrowKind::Write);
}
}
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct MemoryReadGuard<'a, T: ?Sized, Impl: ImplDetails> {
state: Impl::RefState<T>,
#[allow(unused)]
guard: Impl::ReadGuard<'a>,
value: &'a T,
}
impl<'a, T: ?Sized, Impl: ImplDetails> Deref for MemoryReadGuard<'a, T, Impl> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
impl<'a, T: ?Sized, Impl: ImplDetails> Drop for MemoryReadGuard<'a, T, Impl> {
fn drop(&mut self) {
Impl::unborrow_ref::<T>(&self.state, BorrowKind::Read);
}
}