use std::any::Any;
use std::panic::{catch_unwind, AssertUnwindSafe};
pub(crate) fn catch_host<R>(call: impl FnOnce() -> R) -> Result<R, Box<dyn Any + Send>> {
catch_unwind(AssertUnwindSafe(call))
}
pub(crate) fn reraise(payload: Box<dyn Any + Send>) -> ! {
std::panic::resume_unwind(payload)
}
pub(crate) fn restore_after_panic(
inner: &mut crate::store::StoreInner,
roots_mark: usize,
pending: Option<crate::value::Rooted<crate::value::ExnRef>>,
pending_generation: u64,
) {
inner.clear_internal_error();
#[cfg(feature = "async")]
inner.recover_cancelled_async_calls();
let mut exec = inner.take_exec();
match exec.discard_current_call() {
Ok((value_base, stop_depth)) => {
#[cfg(feature = "async")]
inner.abandon_async_call_boundary(value_base, stop_depth);
if stop_depth != 0 {
inner.park_exec(exec);
}
}
Err(error) => {
if let Some(error) = error.downcast_ref::<crate::error::InternalError>() {
inner.latch_internal_error(*error);
}
}
}
inner.gc_roots_truncate(roots_mark);
inner.restore_pending_exception(pending, pending_generation);
}
pub(crate) fn restore_direct_after_panic(
inner: &mut crate::store::StoreInner,
roots_mark: usize,
pending: Option<crate::value::Rooted<crate::value::ExnRef>>,
pending_generation: u64,
) {
#[cfg(feature = "async")]
inner.recover_cancelled_async_calls();
inner.gc_roots_truncate(roots_mark);
inner.restore_pending_exception(pending, pending_generation);
}
#[cfg(feature = "async")]
pub(crate) struct AsyncCancellation {
token: std::sync::Arc<std::sync::atomic::AtomicBool>,
armed: bool,
}
#[cfg(feature = "async")]
impl AsyncCancellation {
pub(crate) fn new(token: std::sync::Arc<std::sync::atomic::AtomicBool>) -> Self {
AsyncCancellation { token, armed: true }
}
pub(crate) fn token(&self) -> &std::sync::Arc<std::sync::atomic::AtomicBool> {
&self.token
}
pub(crate) fn disarm(&mut self) {
self.armed = false;
}
}
#[cfg(feature = "async")]
impl Drop for AsyncCancellation {
fn drop(&mut self) {
if self.armed {
self.token.store(true, std::sync::atomic::Ordering::Release);
}
}
}
#[cfg(feature = "async")]
pub(crate) struct CatchUnwind<F>(pub(crate) F);
#[cfg(feature = "async")]
impl<F: std::future::Future + Unpin> std::future::Future for CatchUnwind<F> {
type Output = Result<F::Output, Box<dyn Any + Send>>;
fn poll(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
use std::task::Poll;
let inner = &mut self.get_mut().0;
match catch_unwind(AssertUnwindSafe(|| std::pin::Pin::new(inner).poll(cx))) {
Ok(Poll::Pending) => Poll::Pending,
Ok(Poll::Ready(v)) => Poll::Ready(Ok(v)),
Err(payload) => Poll::Ready(Err(payload)),
}
}
}