use core::{intrinsics, any::Any, mem::ManuallyDrop};
use super::Box;
use crate::println;
extern crate panic_unwind;
use panic_unwind::__rust_panic_cleanup;
extern crate rmin_eh;
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __rust_foreign_exception()->!{println!("__rust_foreign_exception called, abort.");core::intrinsics::abort()}
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __rust_drop_panic()->!{println!("__rust_drop_panic called, abort.");core::intrinsics::abort()}
pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
union Data<F, R> {
f: ManuallyDrop<F>,
r: ManuallyDrop<R>,
p: ManuallyDrop<Box<dyn Any + Send>>,
}
let mut data = Data { f: ManuallyDrop::new(f) };
let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8;
unsafe {
return if intrinsics::catch_unwind(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
Ok(ManuallyDrop::into_inner(data.r))
} else {
Err(ManuallyDrop::into_inner(data.p))
};
}
#[cold]
unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) };
obj
}
#[inline]
fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
let f = ManuallyDrop::take(&mut data.f);
data.r = ManuallyDrop::new(f());
}
}
#[inline]
#[rustc_nounwind] fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
let obj = cleanup(payload);
data.p = ManuallyDrop::new(obj);
}
}
}