maybe-unwind 0.3.1

A wrapper of catch_unwind that also captures the panic information.
Documentation
use crate::unwind::Captured;
use std::{cell::Cell, ptr::NonNull};

pub(crate) struct Context<'a> {
    pub(crate) captured: &'a mut Option<Captured>,
}

impl Context<'_> {
    pub(crate) fn is_set() -> bool {
        TLS_CTX.with(|tls| tls.get().is_some())
    }

    pub(crate) fn try_with<F, R>(f: F) -> Result<R, AccessError>
    where
        F: FnOnce(&mut Context<'_>) -> R,
    {
        let ctx_ptr = TLS_CTX.with(|tls| tls.take());
        let _guard = Guard(ctx_ptr);
        match ctx_ptr {
            Some(mut ctx_ptr) => unsafe { Ok(f(ctx_ptr.as_mut())) },
            None => Err(AccessError(())),
        }
    }
}

thread_local! {
    pub(crate) static TLS_CTX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
}

pub(crate) struct Guard(pub(crate) Option<NonNull<Context<'static>>>);

impl Drop for Guard {
    fn drop(&mut self) {
        TLS_CTX.with(|tls| {
            tls.set(self.0.take());
        });
    }
}

pub(crate) struct AccessError(());

macro_rules! with_set_ctx {
    ($ctx:expr, $body:block) => {{
        use crate::context::{Context, Guard, TLS_CTX};
        use std::{mem, ptr::NonNull};
        let ctx = $ctx;
        let old_ctx = unsafe {
            let ctx_ptr = mem::transmute::<_, &mut Context<'static>>(ctx);
            TLS_CTX.with(|tls| tls.replace(Some(NonNull::from(ctx_ptr))))
        };
        let _guard = Guard(old_ctx);
        $body
    }};
}