use std::io::{self, Write};
use std::panic::{self, AssertUnwindSafe};
use std::process;

pub fn catch_unwind<F, R>(label: &'static str, foreign_call: F) -> R
where
    F: FnOnce() -> R,
{
    // Regarding the AssertUnwindSafe: we immediately abort on panic so it
    // doesn't matter whether the types involved are unwind-safe. The UnwindSafe
    // bound on catch_unwind is about ensuring nothing is in a broken state if
    // your program plans to continue after the panic.
    match panic::catch_unwind(AssertUnwindSafe(foreign_call)) {
        Ok(ret) => ret,
        Err(_) => abort(label),
    }
}

#[cold]
fn abort(label: &'static str) -> ! {
    let mut stderr = io::stderr();
    let _ = writeln!(stderr, "Error: panic in ffi function {}, aborting.", label);
    process::abort();
}
