Documentation
use crate::node::State::{Trace, Unknown};
use crate::node::{NodeHead, NodeTrait};
use crate::root_ref::RootRef;
use crate::target::RefSet;
use std::cell::Cell;
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::ptr::NonNull;

/// 可以为 [`None`] 的内部可变强引用位
pub struct StrongRef<'gc, T: ?Sized + NodeTrait<'gc> + 'gc> {
    _marker: PhantomData<*mut &'gc ()>,
    cell: Cell<Option<NonNull<T>>>,
}

impl<'gc, T: ?Sized + NodeTrait<'gc> + 'gc> StrongRef<'gc, T> {
    #[inline(always)]
    pub fn get(&self) -> Option<RootRef<'gc, T>> {
        self.cell.get().map(|r| unsafe { RootRef::new(r.as_ref()) })
    }

    #[inline(always)]
    pub fn set(&self, r: Option<&T>) {
        self.cell.set(r.map(Into::into));
    }

    #[inline(always)]
    pub fn set_ref(&self, r: &T) {
        self.cell.set(Some(NonNull::from(r)));
    }

    #[inline(always)]
    pub fn set_none(&self) {
        self.cell.set(None);
    }
}

impl<'gc, T: ?Sized + NodeTrait<'gc>> Debug for StrongRef<'gc, T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let mut s = f.debug_tuple("StrongRef");
        if let Some(r) = self.cell.get() {
            s.field(&r);
        } else {
            s.field(&None::<()>);
        }
        s.finish()
    }
}

unsafe impl<'gc, T: ?Sized + NodeTrait<'gc>> RefSet<'gc> for StrongRef<'gc, T> {
    #[inline(always)]
    unsafe fn build() -> Self {
        Self {
            _marker: PhantomData,
            cell: Cell::new(None),
        }
    }

    #[inline(always)]
    unsafe fn collect(&self, stack: &mut Vec<&dyn NodeTrait<'gc>>) {
        if let Some(r) = self.cell.get() {
            let r = r.as_ref();
            if NodeHead::from_node_trait(r).get_marker() == Unknown {
                NodeHead::from_node_trait(r).set_marker(Trace);
                stack.push(r.as_dyn_node());
            }
        }
    }
}