use std::cell::{BorrowError, BorrowMutError, RefCell};
use std::fmt::{self, Debug, Formatter};
use std::ops::{Deref, DerefMut};
use std::sync::{self, TryLockError};
use crate::{GcGuard, Scan};
rental! {
mod gc_refcell_internals {
use crate::{Scan, GcGuard};
use std::cell::{Ref, RefCell, RefMut};
#[rental(deref_suffix)]
pub struct GcRefInt<'a, T: Scan + 'static> {
gc_guard: GcGuard<'a, RefCell<T>>,
cell_ref: Ref<'gc_guard, T>
}
#[rental(deref_mut_suffix)]
pub struct GcRefMutInt<'a, T: Scan + 'static> {
gc_guard: GcGuard<'a, RefCell<T>>,
cell_ref: RefMut<'gc_guard, T>
}
}
}
pub struct GcRef<'a, T: Scan + 'static> {
internal_ref: gc_refcell_internals::GcRefInt<'a, T>,
}
impl<T: Scan + 'static + Debug> Debug for GcRef<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GcRef").field("ref", self.deref()).finish()
}
}
impl<'a, T: Scan + 'static> GcRef<'a, T> {
pub(crate) fn borrow(g: GcGuard<'a, RefCell<T>>) -> Self {
let internal_ref = gc_refcell_internals::GcRefInt::new(g, RefCell::borrow);
Self { internal_ref }
}
pub(crate) fn try_borrow(g: GcGuard<'a, RefCell<T>>) -> Result<Self, BorrowError> {
let internal_ref =
gc_refcell_internals::GcRefInt::try_new(g, RefCell::try_borrow).map_err(|e| e.0)?;
Ok(Self { internal_ref })
}
}
impl<'a, T: Scan + 'static> Deref for GcRef<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.internal_ref.deref()
}
}
pub struct GcRefMut<'a, T: Scan + 'static> {
internal_ref: gc_refcell_internals::GcRefMutInt<'a, T>,
}
impl<'a, T: Scan + 'static> GcRefMut<'a, T> {
pub(crate) fn borrow_mut(g: GcGuard<'a, RefCell<T>>) -> Self {
let internal_ref = gc_refcell_internals::GcRefMutInt::new(g, RefCell::borrow_mut);
Self { internal_ref }
}
pub(crate) fn try_borrow_mut(g: GcGuard<'a, RefCell<T>>) -> Result<Self, BorrowMutError> {
let internal_ref = gc_refcell_internals::GcRefMutInt::try_new(g, RefCell::try_borrow_mut)
.map_err(|e| e.0)?;
Ok(Self { internal_ref })
}
}
impl<T: Scan + 'static + Debug> Debug for GcRefMut<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GcRefMut")
.field("ref", self.deref())
.finish()
}
}
impl<'a, T: Scan + 'static> Deref for GcRefMut<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.internal_ref.deref()
}
}
impl<'a, T: Scan + 'static> DerefMut for GcRefMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.internal_ref.deref_mut()
}
}
#[derive(Debug)]
pub struct GcPoisonError<T> {
pub(crate) guard: T,
}
impl<T> GcPoisonError<T> {
pub fn into_inner(self) -> T {
self.guard
}
}
#[derive(Debug)]
pub enum GcTryLockError<T> {
Poisoned(GcPoisonError<T>),
WouldBlock,
}
rental! {
mod gc_mutex_internals {
use std::sync::{Mutex, MutexGuard};
use crate::{Scan, GcGuard};
#[rental(deref_mut_suffix)]
pub struct GcMutexGuardInt<'a, T: Scan + 'static> {
gc_guard: GcGuard<'a, Mutex<T>>,
cell_ref: MutexGuard<'gc_guard, T>
}
}
}
pub struct GcMutexGuard<'a, T: Scan + 'static> {
internal_guard: gc_mutex_internals::GcMutexGuardInt<'a, T>,
}
impl<'a, T: Scan + 'static> GcMutexGuard<'a, T> {
pub(crate) fn lock(g: GcGuard<'a, sync::Mutex<T>>) -> Result<Self, GcPoisonError<Self>> {
let mut was_poisoned = false;
let internal_guard = gc_mutex_internals::GcMutexGuardInt::new(g, |g| match g.lock() {
Ok(v) => v,
Err(e) => {
was_poisoned = true;
e.into_inner()
}
});
let guard = Self { internal_guard };
if was_poisoned {
Err(GcPoisonError { guard })
} else {
Ok(guard)
}
}
pub(crate) fn try_lock(g: GcGuard<'a, sync::Mutex<T>>) -> Result<Self, GcTryLockError<Self>> {
let mut was_poisoned = false;
let internal_guard =
gc_mutex_internals::GcMutexGuardInt::try_new(g, |g| match g.try_lock() {
Ok(g) => Ok(g),
Err(TryLockError::Poisoned(e)) => {
was_poisoned = true;
Ok(e.into_inner())
}
Err(TryLockError::WouldBlock) => {
Err(GcTryLockError::<GcMutexGuard<'_, T>>::WouldBlock)
}
})
.map_err(|e| e.0)?;
let guard = GcMutexGuard { internal_guard };
if was_poisoned {
Err(GcTryLockError::Poisoned(GcPoisonError { guard }))
} else {
Ok(guard)
}
}
}
impl<T: Scan + 'static> Deref for GcMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.internal_guard.deref()
}
}
impl<T: Scan + 'static> DerefMut for GcMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.internal_guard.deref_mut()
}
}
impl<T: Scan + 'static + Debug> Debug for GcMutexGuard<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GcMutexGuard")
.field("guarding", self.deref())
.finish()
}
}
rental! {
mod gc_rwlock_internals {
use std::sync::{RwLock, MutexGuard, RwLockReadGuard, RwLockWriteGuard};
use crate::{Scan, GcGuard};
#[rental(deref_suffix)]
pub struct GcRwLockReadGuardInternal<'a, T: Scan + 'static> {
gc_guard: GcGuard<'a, RwLock<T>>,
cell_ref: RwLockReadGuard<'gc_guard, T>
}
#[rental(deref_mut_suffix)]
pub struct GcRwLockWriteGuardInternal<'a, T: Scan + 'static> {
gc_guard: GcGuard<'a, RwLock<T>>,
cell_ref: RwLockWriteGuard<'gc_guard, T>
}
}
}
pub struct GcRwLockReadGuard<'a, T: Scan + 'static> {
internal_guard: gc_rwlock_internals::GcRwLockReadGuardInternal<'a, T>,
}
impl<'a, T: Scan + 'static> GcRwLockReadGuard<'a, T> {
pub(crate) fn read(g: GcGuard<'a, sync::RwLock<T>>) -> Result<Self, GcPoisonError<Self>> {
let mut was_poisoned = false;
let internal_guard =
gc_rwlock_internals::GcRwLockReadGuardInternal::new(g, |g| match g.read() {
Ok(v) => v,
Err(e) => {
was_poisoned = true;
e.into_inner()
}
});
let guard = Self { internal_guard };
if was_poisoned {
Err(GcPoisonError { guard })
} else {
Ok(guard)
}
}
pub(crate) fn try_read(g: GcGuard<'a, sync::RwLock<T>>) -> Result<Self, GcTryLockError<Self>> {
let mut was_poisoned = false;
let internal_guard =
gc_rwlock_internals::GcRwLockReadGuardInternal::try_new(g, |g| match g.try_read() {
Ok(g) => Ok(g),
Err(TryLockError::Poisoned(e)) => {
was_poisoned = true;
Ok(e.into_inner())
}
Err(TryLockError::WouldBlock) => {
Err(GcTryLockError::<GcRwLockReadGuard<'_, T>>::WouldBlock)
}
})
.map_err(|e| e.0)?;
let guard = Self { internal_guard };
if was_poisoned {
Err(GcTryLockError::Poisoned(GcPoisonError { guard }))
} else {
Ok(guard)
}
}
}
impl<T: Scan + 'static + Debug> Debug for GcRwLockReadGuard<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GcRwLockReadGuard")
.field("guarding", self.deref())
.finish()
}
}
impl<'a, T: Scan + 'static> Deref for GcRwLockReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.internal_guard.deref()
}
}
pub struct GcRwLockWriteGuard<'a, T: Scan + 'static> {
internal_guard: gc_rwlock_internals::GcRwLockWriteGuardInternal<'a, T>,
}
impl<'a, T: Scan + 'static> GcRwLockWriteGuard<'a, T> {
pub(crate) fn write(g: GcGuard<'a, sync::RwLock<T>>) -> Result<Self, GcPoisonError<Self>> {
let mut was_poisoned = false;
let internal_guard =
gc_rwlock_internals::GcRwLockWriteGuardInternal::new(g, |g| match g.write() {
Ok(v) => v,
Err(e) => {
was_poisoned = true;
e.into_inner()
}
});
let guard = Self { internal_guard };
if was_poisoned {
Err(GcPoisonError { guard })
} else {
Ok(guard)
}
}
pub(crate) fn try_write(g: GcGuard<'a, sync::RwLock<T>>) -> Result<Self, GcTryLockError<Self>> {
let mut was_poisoned = false;
let internal_guard =
gc_rwlock_internals::GcRwLockWriteGuardInternal::try_new(g, |g| match g.try_write() {
Ok(g) => Ok(g),
Err(TryLockError::Poisoned(e)) => {
was_poisoned = true;
Ok(e.into_inner())
}
Err(TryLockError::WouldBlock) => {
Err(GcTryLockError::<GcRwLockWriteGuard<'_, T>>::WouldBlock)
}
})
.map_err(|e| e.0)?;
let guard = GcRwLockWriteGuard { internal_guard };
if was_poisoned {
Err(GcTryLockError::Poisoned(GcPoisonError { guard }))
} else {
Ok(guard)
}
}
}
impl<T: Scan + 'static + Debug> Debug for GcRwLockWriteGuard<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GcRwLockWriteGuard")
.field("guarding", self.deref())
.finish()
}
}
impl<'a, T: Scan + 'static> Deref for GcRwLockWriteGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.internal_guard.deref()
}
}
impl<'a, T: Scan + 'static> DerefMut for GcRwLockWriteGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.internal_guard.deref_mut()
}
}