#![allow(clippy::doc_link_with_quotes)]
use crate::{
Allocator, Gc, Tracer, finalizer_safe,
internals::EphemeronBox,
trace::{Finalize, Trace},
};
use std::ptr::NonNull;
#[derive(Debug)]
pub struct Ephemeron<K: Trace + ?Sized + 'static, V: Trace + 'static> {
inner_ptr: NonNull<EphemeronBox<K, V>>,
}
impl<K: Trace + ?Sized, V: Trace + Clone> Ephemeron<K, V> {
#[must_use]
pub fn value(&self) -> Option<V> {
unsafe { self.inner_ptr.as_ref().value().cloned() }
}
#[inline]
#[must_use]
pub fn key(&self) -> Option<Gc<K>> {
let key_ptr = unsafe { self.inner_ptr.as_ref().key_ptr() }?;
unsafe {
key_ptr.as_ref().inc_ref_count();
}
Some(unsafe { Gc::from_raw(key_ptr) })
}
#[must_use]
pub fn has_value(&self) -> bool {
unsafe { self.inner_ptr.as_ref().value().is_some() }
}
}
impl<K: Trace + ?Sized, V: Trace> Ephemeron<K, V> {
#[must_use]
pub fn new(key: &Gc<K>, value: V) -> Self {
let inner_ptr = Allocator::alloc_ephemeron(EphemeronBox::new(key, value));
Self { inner_ptr }
}
#[must_use]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
std::ptr::addr_eq(this.inner(), other.inner())
}
pub(crate) fn inner_ptr(&self) -> NonNull<EphemeronBox<K, V>> {
assert!(finalizer_safe());
self.inner_ptr
}
pub(crate) fn inner(&self) -> &EphemeronBox<K, V> {
unsafe { self.inner_ptr().as_ref() }
}
#[must_use]
pub(crate) const unsafe fn from_raw(inner_ptr: NonNull<EphemeronBox<K, V>>) -> Self {
Self { inner_ptr }
}
}
impl<K: Trace + ?Sized, V: Trace> Finalize for Ephemeron<K, V> {
fn finalize(&self) {
unsafe {
self.inner_ptr.as_ref().dec_ref_count();
}
}
}
unsafe impl<K: Trace + ?Sized, V: Trace> Trace for Ephemeron<K, V> {
unsafe fn trace(&self, _tracer: &mut Tracer) {
unsafe {
self.inner().mark();
}
}
unsafe fn trace_non_roots(&self) {
self.inner().inc_non_root_count();
}
fn run_finalizer(&self) {
Finalize::finalize(self);
}
}
impl<K: Trace + ?Sized, V: Trace> Clone for Ephemeron<K, V> {
fn clone(&self) -> Self {
let ptr = self.inner_ptr();
self.inner().inc_ref_count();
unsafe { Self::from_raw(ptr) }
}
}
impl<K: Trace + ?Sized, V: Trace> Drop for Ephemeron<K, V> {
fn drop(&mut self) {
if finalizer_safe() {
Finalize::finalize(self);
}
}
}