use jlrs_sys::unsized_local_scope;
use super::target::{
Target,
frame::{GcFrame, LocalFrame, LocalGcFrame, UnsizedLocalGcFrame},
};
use crate::catch::{Exception, catch_exceptions};
pub unsafe trait LocalScope: private::LocalScopePriv {
#[inline]
fn local_scope<T, const N: usize>(
&self,
func: impl for<'scope> FnOnce(LocalGcFrame<'scope, N>) -> T,
) -> T {
let mut local_frame = LocalFrame::new();
unsafe {
let pinned = local_frame.pin();
let res = func(LocalGcFrame::new(&pinned));
pinned.pop();
res
}
}
fn catching_local_scope<T, E, const N: usize>(
&self,
func: impl for<'scope> FnOnce(LocalGcFrame<'scope, N>) -> T,
exception_handler: impl for<'exc> FnOnce(Exception<'exc, '_>) -> E,
) -> Result<T, E> {
let cb = || self.local_scope(func);
unsafe { catch_exceptions(cb, exception_handler) }
}
#[inline]
fn unsized_local_scope<T>(
&self,
size: usize,
func: impl for<'scope> FnOnce(UnsizedLocalGcFrame<'scope>) -> T,
) -> T {
let mut func = Some(func);
unsafe {
unsized_local_scope(size, |frame| {
let frame = UnsizedLocalGcFrame::new(frame);
func.take().unwrap()(frame)
})
}
}
fn catching_unsized_local_scope<T, E>(
&self,
size: usize,
func: impl for<'scope> FnOnce(UnsizedLocalGcFrame<'scope>) -> T,
exception_handler: impl for<'exc> FnOnce(Exception<'exc, '_>) -> E,
) -> Result<T, E> {
let cb = || self.unsized_local_scope(size, func);
unsafe { catch_exceptions(cb, exception_handler) }
}
}
pub unsafe trait LocalScopeExt<'target>: Target<'target> {
#[inline]
fn with_local_scope<T, const N: usize>(
self,
func: impl for<'inner> FnOnce(Self, LocalGcFrame<'inner, N>) -> T,
) -> T {
let mut local_frame = LocalFrame::new();
unsafe {
let pinned = local_frame.pin();
let res = func(self, LocalGcFrame::new(&pinned));
pinned.pop();
res
}
}
fn with_unsized_local_scope<T>(
self,
size: usize,
func: impl for<'scope> FnOnce(Self, UnsizedLocalGcFrame<'scope>) -> T,
) -> T {
let mut func = Some(func);
let mut self_container = Some(self);
unsafe {
unsized_local_scope(size, |frame| {
let frame = UnsizedLocalGcFrame::new(frame);
func.take().unwrap()(self_container.take().unwrap(), frame)
})
}
}
}
pub unsafe trait Scope: LocalScope {
fn scope<T>(&mut self, func: impl for<'scope> FnOnce(GcFrame<'scope>) -> T) -> T;
}
#[cfg(feature = "async")]
pub unsafe trait AsyncScope: Scope {
fn async_scope<T>(
&mut self,
func: impl for<'inner> AsyncFnOnce(crate::prelude::AsyncGcFrame<'inner>) -> T,
) -> impl std::future::Future<Output = T>;
}
pub(crate) mod private {
pub trait LocalScopePriv {}
}