use core::marker::PhantomData;
use std::ops::ControlFlow;
use wtf8::CodePoint;
use crate::engine::Rootable;
use super::Scoped;
#[non_exhaustive]
#[derive(Debug)]
pub(crate) struct GcToken;
#[non_exhaustive]
#[derive(Debug)]
pub(crate) struct ScopeToken;
#[derive(Debug)]
pub struct GcScope<'a, 'b> {
#[expect(dead_code)]
gc: GcToken,
#[expect(dead_code)]
scope: ScopeToken,
_gc_marker: PhantomData<&'a mut GcToken>,
_scope_marker: PhantomData<&'b ScopeToken>,
}
#[derive(Debug, Clone, Copy)]
pub struct NoGcScope<'a, 'b> {
_gc_marker: PhantomData<&'a GcToken>,
_scope_marker: PhantomData<&'b ScopeToken>,
}
impl<'a, 'b> NoGcScope<'a, 'b> {
#[inline(always)]
#[must_use]
pub(crate) fn into_nogc(self) -> Self {
self
}
}
impl GcToken {
unsafe fn new() -> Self {
Self
}
}
impl ScopeToken {
unsafe fn new() -> Self {
Self
}
}
impl<'a, 'b> GcScope<'a, 'b> {
#[inline]
pub(crate) unsafe fn create_root() -> (GcToken, ScopeToken) {
(unsafe { GcToken::new() }, unsafe { ScopeToken::new() })
}
#[inline]
pub(crate) fn new(_: &'a mut GcToken, _: &'b mut ScopeToken) -> Self {
Self {
gc: GcToken,
scope: ScopeToken,
_gc_marker: PhantomData,
_scope_marker: PhantomData,
}
}
#[inline]
pub fn reborrow(&mut self) -> GcScope<'_, 'b> {
Self {
gc: GcToken,
scope: ScopeToken,
_gc_marker: PhantomData,
_scope_marker: PhantomData,
}
}
#[inline]
pub(crate) fn subscope(&mut self) -> GcScope<'a, '_> {
Self {
gc: GcToken,
scope: ScopeToken,
_gc_marker: PhantomData,
_scope_marker: PhantomData,
}
}
#[inline]
#[must_use]
pub fn nogc(&self) -> NoGcScope<'_, 'b> {
NoGcScope::from_gc(self)
}
#[inline]
#[must_use]
pub fn into_nogc(self) -> NoGcScope<'a, 'b> {
NoGcScope {
_gc_marker: PhantomData,
_scope_marker: PhantomData,
}
}
}
impl<'a, 'b> NoGcScope<'a, 'b> {
#[allow(unknown_lints, gc_scope_is_only_passed_by_value)]
#[inline]
pub(crate) fn from_gc(_: &GcScope<'a, 'b>) -> Self {
Self {
_gc_marker: PhantomData,
_scope_marker: PhantomData,
}
}
}
pub unsafe trait Bindable: Sized {
type Of<'a>;
fn unbind(self) -> Self::Of<'static>;
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a>;
}
macro_rules! bindable_handle {
($self:ident) => {
unsafe impl crate::engine::Bindable for $self<'_> {
type Of<'a> = $self<'a>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
unsafe { core::mem::transmute::<Self, Self::Of<'static>>(self) }
}
#[inline(always)]
fn bind<'a>(self, _: crate::engine::NoGcScope<'a, '_>) -> Self::Of<'a> {
unsafe { core::mem::transmute::<Self, Self::Of<'a>>(self) }
}
}
};
}
pub(crate) use bindable_handle;
macro_rules! trivially_bindable {
($self:ty) => {
unsafe impl crate::engine::Bindable for $self {
type Of<'a> = Self;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
self
}
#[inline(always)]
fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
self
}
}
};
}
pub(crate) use trivially_bindable;
trivially_bindable!(());
trivially_bindable!(bool);
trivially_bindable!(i8);
trivially_bindable!(u8);
trivially_bindable!(i16);
trivially_bindable!(u16);
trivially_bindable!(i32);
trivially_bindable!(u32);
trivially_bindable!(i64);
trivially_bindable!(u64);
trivially_bindable!(i128);
trivially_bindable!(u128);
trivially_bindable!(isize);
trivially_bindable!(usize);
#[cfg(feature = "proposal-float16array")]
trivially_bindable!(f16);
trivially_bindable!(f32);
trivially_bindable!(f64);
trivially_bindable!(CodePoint);
unsafe impl<'b, T: 'static + Rootable> Bindable for Scoped<'b, T> {
type Of<'a> = Scoped<'b, T>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
self
}
#[inline(always)]
fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
self
}
}
unsafe impl<T: Bindable> Bindable for Option<T> {
type Of<'a> = Option<T::Of<'a>>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
self.map(T::unbind)
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
self.map(|t| t.bind(gc))
}
}
unsafe impl<T: Bindable> Bindable for Box<T> {
type Of<'a> = Box<T::Of<'a>>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { std::mem::transmute::<_, _>(self) }
}
#[inline(always)]
fn bind<'a>(self, _: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { std::mem::transmute::<_, _>(self) }
}
}
unsafe impl<T: Bindable, E: Bindable> Bindable for Result<T, E> {
type Of<'a> = Result<T::Of<'a>, E::Of<'a>>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
self.map(T::unbind).map_err(E::unbind)
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
self.map(|t| t.bind(gc)).map_err(|e| e.bind(gc))
}
}
unsafe impl<T: Bindable, E: Bindable> Bindable for ControlFlow<T, E> {
type Of<'a> = ControlFlow<T::Of<'a>, E::Of<'a>>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
match self {
ControlFlow::Continue(c) => ControlFlow::Continue(c.unbind()),
ControlFlow::Break(b) => ControlFlow::Break(b.unbind()),
}
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
match self {
ControlFlow::Continue(c) => ControlFlow::Continue(c.bind(gc)),
ControlFlow::Break(b) => ControlFlow::Break(b.bind(gc)),
}
}
}
unsafe impl<T: Bindable> Bindable for Vec<T> {
type Of<'a> = Vec<T::Of<'a>>;
#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { core::mem::transmute::<Vec<T>, Vec<T::Of<'static>>>(self) }
}
#[inline(always)]
fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { core::mem::transmute::<Vec<T>, Vec<T::Of<'a>>>(self) }
}
}
unsafe impl<T: Bindable> Bindable for Box<[T]> {
type Of<'gc> = Box<[T::Of<'gc>]>;
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { core::mem::transmute::<Box<[T]>, Box<[T::Of<'static>]>>(self) }
}
#[inline(always)]
fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { core::mem::transmute::<Box<[T]>, Box<[T::Of<'a>]>>(self) }
}
}
unsafe impl<'slice, T: Bindable> Bindable for &'slice [T]
where
for<'gc> <T as Bindable>::Of<'gc>: 'slice,
{
type Of<'gc> = &'slice [T::Of<'gc>];
fn unbind(self) -> Self::Of<'static> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { core::mem::transmute::<&'slice [T], &'slice [T::Of<'static>]>(self) }
}
#[inline(always)]
fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
const {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<T::Of<'_>>());
assert!(core::mem::align_of::<T>() == core::mem::align_of::<T::Of<'_>>());
}
unsafe { core::mem::transmute::<&'slice [T], &'slice [T::Of<'a>]>(self) }
}
}
unsafe impl<T: Bindable, U: Bindable> Bindable for (T, U) {
type Of<'gc> = (T::Of<'gc>, U::Of<'gc>);
fn unbind(self) -> Self::Of<'static> {
(self.0.unbind(), self.1.unbind())
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
(self.0.bind(gc), self.1.bind(gc))
}
}
unsafe impl<T: Bindable, U: Bindable, V: Bindable> Bindable for (T, U, V) {
type Of<'gc> = (T::Of<'gc>, U::Of<'gc>, V::Of<'gc>);
fn unbind(self) -> Self::Of<'static> {
(self.0.unbind(), self.1.unbind(), self.2.unbind())
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
(self.0.bind(gc), self.1.bind(gc), self.2.bind(gc))
}
}
unsafe impl<T: Bindable, U: Bindable, V: Bindable, W: Bindable> Bindable for (T, U, V, W) {
type Of<'gc> = (T::Of<'gc>, U::Of<'gc>, V::Of<'gc>, W::Of<'gc>);
fn unbind(self) -> Self::Of<'static> {
(
self.0.unbind(),
self.1.unbind(),
self.2.unbind(),
self.3.unbind(),
)
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
(
self.0.bind(gc),
self.1.bind(gc),
self.2.bind(gc),
self.3.bind(gc),
)
}
}
unsafe impl<T: Bindable, U: Bindable, V: Bindable, W: Bindable, X: Bindable> Bindable
for (T, U, V, W, X)
{
type Of<'gc> = (T::Of<'gc>, U::Of<'gc>, V::Of<'gc>, W::Of<'gc>, X::Of<'gc>);
fn unbind(self) -> Self::Of<'static> {
(
self.0.unbind(),
self.1.unbind(),
self.2.unbind(),
self.3.unbind(),
self.4.unbind(),
)
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
(
self.0.bind(gc),
self.1.bind(gc),
self.2.bind(gc),
self.3.bind(gc),
self.4.bind(gc),
)
}
}
unsafe impl<T: Bindable, U: Bindable, V: Bindable, W: Bindable, X: Bindable, Y: Bindable> Bindable
for (T, U, V, W, X, Y)
{
type Of<'gc> = (
T::Of<'gc>,
U::Of<'gc>,
V::Of<'gc>,
W::Of<'gc>,
X::Of<'gc>,
Y::Of<'gc>,
);
fn unbind(self) -> Self::Of<'static> {
(
self.0.unbind(),
self.1.unbind(),
self.2.unbind(),
self.3.unbind(),
self.4.unbind(),
self.5.unbind(),
)
}
#[inline(always)]
fn bind<'a>(self, gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
(
self.0.bind(gc),
self.1.bind(gc),
self.2.bind(gc),
self.3.bind(gc),
self.4.bind(gc),
self.5.bind(gc),
)
}
}