rustler 0.18.0

Safe Rust wrappers for creating Erlang NIF functions
Documentation
//! Functions used by runtime generated code. Should not be used.

use std::panic::catch_unwind;
use types::atom::Atom;
use wrapper::exception;
use NifResult;
use {Env, Term};

// Names used by the `rustler_export_nifs!` macro or other generated code.
pub use wrapper::nif_interface::{c_int, c_void, get_nif_resource_type_init_size, DEF_NIF_ENTRY,
                                 DEF_NIF_FUNC, MUTABLE_NIF_RESOURCE_HANDLE, NIF_ENV,
                                 NIF_MAJOR_VERSION, NIF_MINOR_VERSION, NIF_TERM};

#[cfg(windows)]
pub use erlang_nif_sys::{TWinDynNifCallbacks, WIN_DYN_NIF_CALLBACKS};

/// This is the last level of rust safe rust code before the BEAM.
/// No panics should go above this point, as they will unwrap into the C code and ruin the day.
///
/// # Unsafe
///
/// This takes arguments, including raw pointers, that must be correct. Only the glue code
/// generated by `rustler_export_nifs!` can call this function correctly.
pub unsafe fn handle_nif_call(
    function: for<'a> fn(Env<'a>, &[Term<'a>]) -> NifResult<Term<'a>>,
    _arity: usize,
    r_env: NIF_ENV,
    argc: c_int,
    argv: *const NIF_TERM,
) -> NIF_TERM {
    let env_lifetime = ();
    let env = Env::new(&env_lifetime, r_env);

    let terms = ::std::slice::from_raw_parts(argv, argc as usize)
        .iter()
        .map(|x| Term::new(env, *x))
        .collect::<Vec<Term>>();

    let result: ::std::thread::Result<NIF_TERM> = catch_unwind(|| match function(env, &terms) {
        Ok(ret) => ret.as_c_arg(),
        Err(err) => err.encode(env).as_c_arg(),
    });

    match result {
        Ok(res) => res,
        Err(_err) => exception::raise_exception(
            env.as_c_arg(),
            Atom::from_bytes(env, b"nif_panic").ok().unwrap().as_c_arg(),
        ),
    }
}

/// # Unsafe
///
/// This takes arguments, including raw pointers, that must be correct.
pub unsafe fn handle_nif_init_call(
    function: Option<for<'a> fn(Env<'a>, Term<'a>) -> bool>,
    r_env: NIF_ENV,
    load_info: NIF_TERM,
) -> c_int {
    let env_lifetime = ();
    let env = Env::new(&env_lifetime, r_env);
    let term = Term::new(env, load_info);

    if let Some(inner) = function {
        if inner(env, term) {
            0
        } else {
            1
        }
    } else {
        0
    }
}