rustler 0.6.0

Safe Rust wrappers for creating Erlang NIF functions
extern crate ruster_unsafe;

use super::{ NifEnv, NifError, NifTerm, NifEncoder, NifDecoder };
use libc::{ size_t, c_void };
use std::mem::uninitialized;
use ::wrapper::nif_interface::NIF_TERM;

#[repr(C)]
#[derive(Clone)]
struct ErlNifBinary {
    pub size: size_t,
    pub data: *mut u8,
    bin_term: NIF_TERM,
    ref_bin: *mut c_void,
}
impl ErlNifBinary {
    unsafe fn new_empty() -> Self {
        ErlNifBinary {
            size: uninitialized(),
            data: uninitialized(),
            bin_term: uninitialized(),
            ref_bin: uninitialized(),
        }
    }
    fn as_c_arg(&mut self) -> *mut ruster_unsafe::ErlNifBinary {
        (self as *mut ErlNifBinary) as *mut ruster_unsafe::ErlNifBinary
    }
}

pub struct OwnedNifBinary {
    inner: ErlNifBinary,
    release: bool,
}
pub struct NifBinary<'a> {
    inner: ErlNifBinary,
    term: NifTerm<'a>,
}

impl Drop for OwnedNifBinary {
    fn drop(&mut self) {
        if self.release {
            unsafe { ruster_unsafe::enif_release_binary(self.inner.as_c_arg()) };
        }
    }
}

impl<'a> OwnedNifBinary {
    pub fn alloc(size: usize) -> Option<OwnedNifBinary> {
        let mut binary = unsafe { ErlNifBinary::new_empty() };
        if unsafe { ruster_unsafe::enif_alloc_binary(
                size as size_t, 
                binary.as_c_arg()) } == 0 {
            return None;
        }
        Some(OwnedNifBinary {
            inner: binary,
            release: true,
        })
    }
    pub fn as_slice(&self) -> &'a [u8] {
        unsafe { ::std::slice::from_raw_parts(self.inner.data, self.inner.size as usize) }
    }
    pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
        unsafe { ::std::slice::from_raw_parts_mut(self.inner.data, self.inner.size as usize) }
    }
    pub fn release<'b>(self, env: &'b NifEnv) -> NifBinary<'b> {
        NifBinary::from_owned(self, env)
    }
}
impl<'a> NifBinary<'a> {
    pub fn from_owned(mut bin: OwnedNifBinary, env: &'a NifEnv) -> Self {
        bin.release = false;
        let term = NifTerm::new(env, unsafe { ruster_unsafe::enif_make_binary(env.as_c_arg(), bin.inner.as_c_arg()) });
        NifBinary {
            inner: bin.inner.clone(),
            term: term,
        }
    }
    pub fn from_term(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError> {
        let mut binary = unsafe { ErlNifBinary::new_empty() };
        if unsafe { ruster_unsafe::enif_inspect_binary(env.as_c_arg(), term.as_c_arg(), binary.as_c_arg()) } == 0 {
            return Err(NifError::BadArg);
        }
        Ok(NifBinary {
            inner: binary,
            term: term,
        })
    }
    pub fn as_slice(&self) -> &'a [u8] {
        unsafe { ::std::slice::from_raw_parts(self.inner.data, self.inner.size as usize) }
    }
    pub fn get_term(&self, _env: &'a NifEnv) -> NifTerm<'a> {
        self.term
    }
}

impl<'a> NifDecoder<'a> for NifBinary<'a> {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError> {
        NifBinary::from_term(term, env)
    }
}