use core::mem::ManuallyDrop;
union Data<Func, Catch, T, E> {
init: (ManuallyDrop<Func>, ManuallyDrop<Catch>),
ok: ManuallyDrop<T>,
err: ManuallyDrop<E>,
}
#[allow(
clippy::missing_errors_doc,
reason = "`Err` value is described immediately"
)]
#[inline]
pub fn intercept<Func: FnOnce() -> T, Catch: FnOnce(*mut u8) -> E, T, E>(
func: Func,
catch: Catch,
) -> Result<T, E> {
let mut data: Data<Func, Catch, T, E> = Data {
init: (ManuallyDrop::new(func), ManuallyDrop::new(catch)),
};
if unsafe {
core::intrinsics::catch_unwind(
do_call::<Func, Catch, T, E>,
(&raw mut data).cast(),
do_catch::<Func, Catch, T, E>,
)
} == 0i32
{
Ok(ManuallyDrop::into_inner(unsafe { data.ok }))
} else {
Err(ManuallyDrop::into_inner(unsafe { data.err }))
}
}
#[inline]
fn do_call<Func: FnOnce() -> R, Catch: FnOnce(*mut u8) -> E, R, E>(data: *mut u8) {
let data: &mut Data<Func, Catch, R, E> = unsafe { &mut *data.cast() };
let func = unsafe { ManuallyDrop::take(&mut data.init.0) };
data.ok = ManuallyDrop::new(func());
}
#[inline]
#[rustc_nounwind]
fn do_catch<Func: FnOnce() -> R, Catch: FnOnce(*mut u8) -> E, R, E>(data: *mut u8, ex: *mut u8) {
let data: &mut Data<Func, Catch, R, E> = unsafe { &mut *data.cast() };
let catch = unsafe { ManuallyDrop::take(&mut data.init.1) };
data.err = ManuallyDrop::new(catch(ex));
}