use std::{
future::Future,
mem::{self, MaybeUninit},
ptr::NonNull,
};
use crate::{raw_scope::RawScope, Family, Never, TopScope};
#[repr(transparent)]
pub struct BoxScope<T, F: ?Sized = dyn Future<Output = Never> + 'static>(
std::ptr::NonNull<RawScope<T, F>>,
)
where
T: for<'a> Family<'a>,
F: Future<Output = Never>;
impl<T, F: ?Sized> Drop for BoxScope<T, F>
where
T: for<'a> Family<'a>,
F: Future<Output = Never>,
{
fn drop(&mut self) {
drop(unsafe { Box::from_raw(self.0.as_ptr()) })
}
}
impl<T> BoxScope<T>
where
T: for<'a> Family<'a>,
{
pub fn new_dyn<S: TopScope<Family = T>>(scope: S) -> Self
where
S::Future: 'static,
{
let this = mem::ManuallyDrop::new(BoxScope::new(scope));
Self(this.0)
}
}
impl<T, F> BoxScope<T, F>
where
T: for<'a> Family<'a>,
F: Future<Output = Never>,
{
pub fn new<S: TopScope<Family = T, Future = F>>(scope: S) -> BoxScope<T, F>
where
S: TopScope<Family = T>,
{
let raw_scope = Box::new(RawScope::<T, F>::new_uninit());
let raw_scope: *mut RawScope<T, MaybeUninit<F>> = Box::into_raw(raw_scope);
struct Guard<Sc> {
raw_scope: *mut Sc,
}
let panic_guard = Guard { raw_scope };
impl<Sc> Drop for Guard<Sc> {
fn drop(&mut self) {
drop(unsafe { Box::from_raw(self.raw_scope) })
}
}
let raw_scope: *mut RawScope<T, F> = raw_scope.cast();
unsafe {
RawScope::open(raw_scope, scope);
}
mem::forget(panic_guard);
BoxScope(unsafe { NonNull::new_unchecked(raw_scope) })
}
}
impl<T, F: ?Sized> BoxScope<T, F>
where
T: for<'a> Family<'a>,
F: Future<Output = Never>,
{
pub fn enter<'borrow, Output, G>(&'borrow mut self, f: G) -> Output
where
G: for<'a> FnOnce(&'borrow mut <T as Family<'a>>::Family) -> Output,
{
unsafe { RawScope::enter(self.0, f) }
}
}