use std::ptr::NonNull;
use crate::{heaped_object::GCHeapedObject, traceable::GCTraceable};
#[allow(dead_code)]
pub trait GCRef {
fn strong_ref(&self) -> usize;
fn weak_ref(&self) -> usize;
fn inc_ref(&self);
fn dec_ref(&self);
fn inc_weak_ref(&self);
fn dec_weak_ref(&self);
}
pub struct GCArc {
obj: NonNull<GCHeapedObject>,
}
#[allow(dead_code)]
impl GCArc {
pub fn new<T: GCTraceable + 'static>(obj: T) -> Self {
let heaped_obj = Box::new(GCHeapedObject::new(obj));
let obj_ptr = Box::into_raw(heaped_obj);
Self {
obj: NonNull::new(obj_ptr).expect("Unable to create GCArc"),
}
}
pub unsafe fn inc_ref(&self) {
unsafe {
self.obj
.as_ref()
.strong_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
pub unsafe fn dec_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to decrement a GCArc with 0 strong references");
}
if self
.obj
.as_ref()
.strong_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
pub fn as_weak(&self) -> GCArcWeak {
unsafe {
self.obj
.as_ref()
.weak_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
GCArcWeak { obj: self.obj }
}
pub fn is_marked(&self) -> bool {
unsafe { self.obj.as_ref().is_marked() }
}
pub fn mark_and_visit(&self) {
unsafe {
if self.obj.as_ref().is_marked() {
return;
}
self.obj.as_ref().mark();
}
self.visit();
}
pub fn unmark(&self) {
unsafe {
self.obj.as_ref().unmark();
}
}
pub fn downcast<T: GCTraceable + 'static>(&self) -> &T {
unsafe { self.obj.as_ref().downcast::<T>() }
}
pub fn downcast_mut<T: GCTraceable + 'static>(&mut self) -> &mut T {
unsafe { self.obj.as_mut().downcast_mut::<T>() }
}
pub fn raw_ptr(&self) -> *mut dyn GCTraceable {
unsafe { self.obj.as_ref().value }
}
pub fn raw_mut(&mut self) -> &mut dyn GCTraceable {
unsafe { &mut *self.obj.as_mut().value }
}
pub fn raw_ref(&self) -> &dyn GCTraceable {
unsafe { &*self.obj.as_ref().value }
}
pub fn isinstance<T: GCTraceable + 'static>(self: &Self) -> bool {
unsafe { self.obj.as_ref().isinstance::<T>() }
}
fn visit(&self) {
unsafe {
self.obj.as_ref().as_ref().visit();
}
}
pub(crate) fn ptr_eq(a: &GCArc, b: &GCArc) -> bool {
unsafe { std::ptr::eq(a.obj.as_ref(), b.obj.as_ref()) }
}
}
impl Clone for GCArc {
fn clone(&self) -> Self {
unsafe {
self.obj
.as_ref()
.strong_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
Self { obj: self.obj }
}
}
impl GCRef for GCArc {
fn strong_ref(&self) -> usize {
unsafe { self.obj.as_ref().strong_ref() }
}
fn weak_ref(&self) -> usize {
unsafe { self.obj.as_ref().weak_ref() }
}
fn inc_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to increment a GCArc with 0 strong references");
}
self.obj
.as_ref()
.strong_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
fn dec_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to decrement a GCArc with 0 strong references");
}
if self
.obj
.as_ref()
.strong_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
fn inc_weak_ref(&self) {
unsafe {
self.obj
.as_ref()
.weak_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
fn dec_weak_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.weak_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to decrement a GCArc with 0 weak references");
}
if self
.obj
.as_ref()
.weak_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
}
impl Drop for GCArc {
fn drop(&mut self) {
unsafe {
if self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to drop a GCArc with 0 strong references");
}
if self
.obj
.as_mut()
.strong_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
self.obj.as_mut().drop_value();
if self.obj.as_ref().weak_ref() == 0 {
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
}
}
unsafe impl Send for GCArc {}
unsafe impl Sync for GCArc {}
pub struct GCArcWeak {
obj: NonNull<GCHeapedObject>,
}
#[allow(dead_code)]
impl GCArcWeak {
pub unsafe fn from_raw(obj: NonNull<GCHeapedObject>) -> Self {
Self { obj }
}
pub fn upgrade(&self) -> Option<GCArc> {
unsafe {
let strong_count = self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst);
if strong_count == 0 {
return None;
}
self.obj
.as_ref()
.strong_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Some(GCArc { obj: self.obj })
}
}
pub fn is_valid(&self) -> bool {
unsafe { self.obj.as_ref().strong_ref() > 0 }
}
}
impl Clone for GCArcWeak {
fn clone(&self) -> Self {
unsafe {
self.obj
.as_ref()
.weak_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
Self { obj: self.obj }
}
}
impl GCRef for GCArcWeak {
fn strong_ref(&self) -> usize {
unsafe { self.obj.as_ref().strong_ref() }
}
fn weak_ref(&self) -> usize {
unsafe { self.obj.as_ref().weak_ref() }
}
fn inc_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to increment a GCArcWeak with 0 strong references");
}
self.obj
.as_ref()
.strong_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
fn dec_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.strong_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to decrement a GCArcWeak with 0 strong references");
}
if self
.obj
.as_ref()
.strong_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
fn inc_weak_ref(&self) {
unsafe {
self.obj
.as_ref()
.weak_rc
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
fn dec_weak_ref(&self) {
unsafe {
if self
.obj
.as_ref()
.weak_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to decrement a GCArcWeak with 0 weak references");
}
if self
.obj
.as_ref()
.weak_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
}
impl Drop for GCArcWeak {
fn drop(&mut self) {
unsafe {
if self
.obj
.as_ref()
.weak_rc
.load(std::sync::atomic::Ordering::SeqCst)
== 0
{
panic!("Attempted to drop a GCArcWeak with 0 weak references");
}
if self
.obj
.as_ref()
.weak_rc
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
== 1
{
if self.obj.as_ref().strong_ref() == 0 {
drop(Box::from_raw(self.obj.as_ptr()));
}
}
}
}
}
unsafe impl Send for GCArcWeak {}
unsafe impl Sync for GCArcWeak {}