use std::any::{Any, TypeId};
use std::borrow::Borrow;
use std::cell::{BorrowError, BorrowMutError, RefCell};
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::sync;
use std::sync::atomic;
#[cfg(feature = "nightly-features")]
use std::{marker::Unsize, ops::CoerceUnsized};
use stable_deref_trait::StableDeref;
use crate::collector::{GcGuardWarrant, InternalGcRef, COLLECTOR};
use crate::marker::{GcDeref, GcDrop, GcSafe};
use crate::wrappers::{
GcMutexGuard, GcPoisonError, GcRef, GcRefMut, GcRwLockReadGuard, GcRwLockWriteGuard,
GcTryLockError,
};
use crate::{Finalize, Scan, Scanner, ToScan};
pub struct Gc<T: Scan + ?Sized> {
backing_handle: InternalGcRef,
direct_ptr: *const T,
}
impl<T: Scan + ?Sized> Gc<T> {
pub fn new(v: T) -> Self
where
T: Sized + GcDrop,
{
let (handle, ptr) = COLLECTOR.track_with_drop(v);
Self {
backing_handle: handle,
direct_ptr: ptr,
}
}
pub fn new_no_drop(v: T) -> Self
where
T: Sized,
{
let (handle, ptr) = COLLECTOR.track_with_no_drop(v);
Self {
backing_handle: handle,
direct_ptr: ptr,
}
}
pub fn new_with_finalizer(v: T) -> Self
where
T: Sized + Finalize,
{
let (handle, ptr) = COLLECTOR.track_with_finalization(v);
Self {
backing_handle: handle,
direct_ptr: ptr,
}
}
pub fn from_box(v: Box<T>) -> Self
where
T: ToScan + GcDrop,
{
let (handle, ptr) = COLLECTOR.track_boxed_value(v);
Self {
backing_handle: handle,
direct_ptr: ptr,
}
}
pub(crate) fn new_raw(backing_handle: InternalGcRef, direct_ptr: *const T) -> Self {
Self {
backing_handle,
direct_ptr,
}
}
#[must_use]
pub fn get(&self) -> GcGuard<'_, T> {
let warrant = COLLECTOR.get_data_warrant(&self.backing_handle);
GcGuard {
gc_ptr: self,
_warrant: warrant,
}
}
pub(crate) fn assert_live(&self) {
let ordering = atomic::Ordering::Relaxed;
let is_deallocated = self.backing_handle.data().deallocated.load(ordering);
assert!(!is_deallocated);
}
pub(crate) fn internal_handle(&self) -> InternalGcRef {
self.backing_handle.clone()
}
pub(crate) fn internal_handle_ref(&self) -> &InternalGcRef {
&self.backing_handle
}
}
#[allow(clippy::use_self)]
impl<T: Scan + ?Sized> Gc<T> {
#[must_use]
pub fn downcast<S>(&self) -> Option<Gc<S>>
where
T: Any + 'static,
S: Scan + Any + 'static,
{
let gc_guard = self.get();
let ptr: &T = gc_guard.deref();
if ptr.type_id() == TypeId::of::<S>() {
let new_handle = COLLECTOR.clone_handle(&self.backing_handle);
Some(Gc {
backing_handle: new_handle,
direct_ptr: self.direct_ptr as *const S,
})
} else {
None
}
}
}
impl<T: Scan + ?Sized> Clone for Gc<T> {
#[must_use]
fn clone(&self) -> Self {
let new_handle = COLLECTOR.clone_handle(&self.backing_handle);
Self {
backing_handle: new_handle,
direct_ptr: self.direct_ptr,
}
}
}
unsafe impl<T: Scan + ?Sized> Scan for Gc<T> {
#[allow(clippy::inline_always)]
#[inline(always)]
fn scan(&self, scanner: &mut Scanner<'_>) {
scanner.add_internal_handle(self.internal_handle());
}
}
unsafe impl<T: Scan + ?Sized> GcSafe for Gc<T> {}
unsafe impl<T: Scan + ?Sized> GcDrop for Gc<T> {}
unsafe impl<T: Scan + Send + Sync + ?Sized> GcDeref for Gc<T> {}
#[cfg(feature = "nightly-features")]
impl<T, U> CoerceUnsized<Gc<U>> for Gc<T>
where
T: Scan + ?Sized + Unsize<U>,
U: Scan + ?Sized,
{
}
unsafe impl<T: Scan + ?Sized> Sync for Gc<T> where T: Sync + Send {}
unsafe impl<T: Scan + ?Sized> Send for Gc<T> where T: Sync + Send {}
impl<T: Scan + ?Sized> Drop for Gc<T> {
fn drop(&mut self) {
self.backing_handle.invalidate();
}
}
unsafe impl<T: Scan + ?Sized> Finalize for Gc<T> {
unsafe fn finalize(&mut self) {
self.internal_handle().invalidate();
}
}
impl<T: Scan + ?Sized> Debug for Gc<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Gc")
.field("backing_handle", &"<SNIP>")
.field("direct_ptr", &self.direct_ptr)
.finish()
}
}
impl<T: Scan + ?Sized> Default for Gc<T>
where
T: Default + GcDrop,
{
#[must_use]
fn default() -> Self {
let v = T::default();
Self::new(v)
}
}
impl<T: Scan + ?Sized> Display for Gc<T>
where
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let a = self.get();
a.fmt(f)
}
}
impl<T: Scan + ?Sized> fmt::Pointer for Gc<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.direct_ptr, f)
}
}
impl<T: Scan + ?Sized> Eq for Gc<T> where T: Eq {}
impl<T: Scan + ?Sized> Hash for Gc<T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.get().hash(state)
}
}
impl<T: Scan + ?Sized> Ord for Gc<T>
where
T: Ord,
{
#[must_use]
fn cmp(&self, other: &Self) -> Ordering {
let a = self.get();
let b = other.get();
a.cmp(b.deref())
}
}
#[allow(clippy::partialeq_ne_impl)]
impl<T: Scan + ?Sized> PartialEq for Gc<T>
where
T: PartialEq,
{
#[must_use]
fn eq(&self, other: &Self) -> bool {
let a = self.get();
let b = other.get();
a.eq(&b)
}
#[must_use]
fn ne(&self, other: &Self) -> bool {
let a = self.get();
let b = other.get();
a.ne(&b)
}
}
impl<T: Scan + ?Sized> PartialOrd for Gc<T>
where
T: PartialOrd,
{
#[must_use]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let a = self.get();
let b = other.get();
a.partial_cmp(&b)
}
#[must_use]
fn lt(&self, other: &Self) -> bool {
let a = self.get();
let b = other.get();
a.lt(&b)
}
#[must_use]
fn le(&self, other: &Self) -> bool {
let a = self.get();
let b = other.get();
a.le(&b)
}
#[must_use]
fn gt(&self, other: &Self) -> bool {
let a = self.get();
let b = other.get();
a.gt(&b)
}
#[must_use]
fn ge(&self, other: &Self) -> bool {
let a = self.get();
let b = other.get();
a.ge(&b)
}
}
pub struct GcGuard<'a, T: Scan + ?Sized> {
gc_ptr: &'a Gc<T>,
_warrant: GcGuardWarrant,
}
impl<'a, T: Scan + ?Sized> Deref for GcGuard<'a, T> {
type Target = T;
#[must_use]
fn deref(&self) -> &Self::Target {
unsafe { &*self.gc_ptr.direct_ptr }
}
}
unsafe impl<'a, T: Scan + ?Sized> StableDeref for GcGuard<'a, T> {}
impl<'a, T: Scan + ?Sized> AsRef<T> for GcGuard<'a, T> {
#[must_use]
fn as_ref(&self) -> &T {
self.deref()
}
}
impl<'a, T: Scan + ?Sized> Borrow<T> for GcGuard<'a, T> {
#[must_use]
fn borrow(&self) -> &T {
self.deref()
}
}
impl<'a, T: Scan + Debug> Debug for GcGuard<'a, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GcGuard")
.field("v", self.deref())
.field("warrant", &"<SNIP>")
.finish()
}
}
impl<T: Scan + 'static> Gc<RefCell<T>> {
#[must_use]
pub fn borrow(&self) -> GcRef<'_, T> {
let g = self.get();
GcRef::borrow(g)
}
pub fn try_borrow(&self) -> Result<GcRef<'_, T>, BorrowError> {
let g = self.get();
GcRef::try_borrow(g)
}
#[must_use]
pub fn borrow_mut(&self) -> GcRefMut<'_, T> {
let g = self.get();
GcRefMut::borrow_mut(g)
}
pub fn try_borrow_mut(&self) -> Result<GcRefMut<'_, T>, BorrowMutError> {
let g = self.get();
GcRefMut::try_borrow_mut(g)
}
}
impl<T: Scan + 'static> Gc<sync::Mutex<T>> {
pub fn lock(&self) -> Result<GcMutexGuard<'_, T>, GcPoisonError<GcMutexGuard<'_, T>>> {
let g = self.get();
GcMutexGuard::lock(g)
}
pub fn try_lock(&self) -> Result<GcMutexGuard<'_, T>, GcTryLockError<GcMutexGuard<'_, T>>> {
let g = self.get();
GcMutexGuard::try_lock(g)
}
}
impl<T: Scan + 'static> Gc<sync::RwLock<T>> {
pub fn read(
&self,
) -> Result<GcRwLockReadGuard<'_, T>, GcPoisonError<GcRwLockReadGuard<'_, T>>> {
let g = self.get();
GcRwLockReadGuard::read(g)
}
pub fn write(
&self,
) -> Result<GcRwLockWriteGuard<'_, T>, GcPoisonError<GcRwLockWriteGuard<'_, T>>> {
let g = self.get();
GcRwLockWriteGuard::write(g)
}
pub fn try_read(
&self,
) -> Result<GcRwLockReadGuard<'_, T>, GcTryLockError<GcRwLockReadGuard<'_, T>>> {
let g = self.get();
GcRwLockReadGuard::try_read(g)
}
pub fn try_write(
&self,
) -> Result<GcRwLockWriteGuard<'_, T>, GcTryLockError<GcRwLockWriteGuard<'_, T>>> {
let g = self.get();
GcRwLockWriteGuard::try_write(g)
}
}
#[cfg(test)]
mod test {
use crate::{Gc, Scan};
use std::{
cell::RefCell,
sync::{Mutex, RwLock},
};
#[test]
fn dyn_gc_ptr() {
trait NoSize: Scan {
fn do_stuff(&self);
}
let _: Gc<dyn NoSize>;
let _: Gc<RefCell<dyn NoSize>>;
let _: Gc<Mutex<dyn NoSize>>;
let _: Gc<RwLock<dyn NoSize>>;
}
}