use crate::collector::{GarbageCollector, Trace};
use crate::gc::Gc;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct GcRootGuard<T: Trace> {
collector: Arc<GarbageCollector>,
root: Gc<T>,
root_id: usize,
ref_count: Arc<AtomicUsize>,
}
impl<T: Trace> GcRootGuard<T> {
pub(crate) fn new(collector: Arc<GarbageCollector>, root_id: usize, root: Gc<T>) -> Self {
let ref_count = Arc::new(AtomicUsize::new(1));
Self {
collector,
root,
root_id,
ref_count,
}
}
#[must_use]
pub fn clone_gc(&self) -> Gc<T> {
self.root.clone()
}
}
impl<T: Trace> Clone for GcRootGuard<T> {
fn clone(&self) -> Self {
self.ref_count.fetch_add(1, Ordering::Relaxed);
Self {
collector: Arc::clone(&self.collector),
root: self.root.clone(),
root_id: self.root_id,
ref_count: Arc::clone(&self.ref_count),
}
}
}
impl<T: Trace> Deref for GcRootGuard<T> {
type Target = Gc<T>;
fn deref(&self) -> &Self::Target {
&self.root
}
}
impl<T: Trace> DerefMut for GcRootGuard<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.root
}
}
impl<T: Trace> Trace for GcRootGuard<T> {
fn trace(&self, collector: &GarbageCollector) {
self.root.trace(collector);
}
}
impl<T: Trace> Drop for GcRootGuard<T> {
fn drop(&mut self) {
let old_count = self.ref_count.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
self.collector.remove_root_by_id(self.root_id);
}
}
}
impl<T: Trace + PartialEq> PartialEq for GcRootGuard<T> {
fn eq(&self, other: &Self) -> bool {
*self.root == *other.root
}
}
impl<T: Trace + Eq> Eq for GcRootGuard<T> {}
impl<T: Trace + Hash> Hash for GcRootGuard<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.root.hash(state);
}
}
impl<T: Trace + PartialOrd> PartialOrd for GcRootGuard<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.root.partial_cmp(&other.root)
}
}
impl<T: Trace + Ord> Ord for GcRootGuard<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.root.cmp(&other.root)
}
}
impl<T: Trace + std::fmt::Debug> std::fmt::Debug for GcRootGuard<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.root.fmt(f)
}
}
impl<T: Trace + std::fmt::Display> std::fmt::Display for GcRootGuard<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.root.fmt(f)
}
}