use std::ascii::AsciiExt;
use ::{ NifTerm, NifEnv, NifResult, NifError, NifEncoder };
use ::wrapper::nif_interface::NIF_TERM;
use ::wrapper::atom;
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct NifAtom {
term: NIF_TERM,
}
impl NifAtom {
pub fn as_c_arg(&self) -> NIF_TERM {
self.term
}
pub fn to_term<'a>(self, env: NifEnv<'a>) -> NifTerm<'a> {
unsafe { NifTerm::new(env, self.term) }
}
unsafe fn from_nif_term(term: NIF_TERM) -> Self {
NifAtom {
term: term
}
}
pub fn from_term(term: NifTerm) -> NifResult<Self> {
match term.is_atom() {
true => Ok(unsafe { NifAtom::from_nif_term(term.as_c_arg()) }),
false => Err(NifError::BadArg)
}
}
pub fn from_bytes<'a>(env: NifEnv<'a>, bytes: &[u8]) -> NifResult<NifAtom> {
if bytes.len() > 255 {
return Err(NifError::BadArg);
}
unsafe {
Ok(NifAtom::from_nif_term(atom::make_atom(env.as_c_arg(), bytes)))
}
}
pub fn from_str<'a>(env: NifEnv<'a>, string: &str) -> NifResult<NifAtom> {
if string.is_ascii() {
NifAtom::from_bytes(env, string.as_bytes())
} else {
let mut bytes = Vec::with_capacity(string.len());
for c in string.chars() {
if (c as u32) >= 256 {
return Err(NifError::BadArg);
}
bytes.push(c as u8);
}
NifAtom::from_bytes(env, &bytes)
}
}
}
impl NifEncoder for NifAtom {
fn encode<'a>(&self, env: NifEnv<'a>) -> NifTerm<'a> {
self.to_term(env)
}
}
impl<'a> PartialEq<NifTerm<'a>> for NifAtom {
fn eq(&self, other: &NifTerm<'a>) -> bool {
self.as_c_arg() == other.as_c_arg()
}
}
impl<'a> NifTerm<'a> {
pub fn atom_to_string(&self) -> NifResult<String> {
unsafe { atom::get_atom(self.get_env().as_c_arg(), self.as_c_arg()) }
}
}
pub fn is_truthy(term: NifTerm) -> bool {
!((term.as_c_arg() == false_().as_c_arg()) || (term.as_c_arg() == nil().as_c_arg()))
}
unsafe impl Sync for NifAtom {}
unsafe impl Send for NifAtom {}
#[macro_export]
macro_rules! rustler_atoms {
{
$(
$( #[$attr:meta] )*
atom $name:ident $( = $str:expr )*;
)*
} => {
#[allow(non_snake_case)]
struct RustlerAtoms {
$( $name : $crate::types::atom::NifAtom ),*
}
lazy_static! {
static ref RUSTLER_ATOMS: RustlerAtoms = $crate::env::OwnedEnv::new().run(|env| {
RustlerAtoms {
$( $name: rustler_atoms!(@internal_make_atom(env, $name $( = $str)* )) ),*
}
});
}
$(
$( #[$attr] )*
pub fn $name() -> $crate::types::atom::NifAtom {
RUSTLER_ATOMS.$name
}
)*
};
{ @internal_make_atom($env:ident, $name:ident) } => {
rustler_atoms!(@internal_make_atom($env, $name = stringify!($name)))
};
{ @internal_make_atom($env:ident, $name:ident = $str:expr) } => {
$crate::types::atom::NifAtom::from_str($env, $str)
.ok().expect("rustler_atoms: bad atom string")
};
}
rustler_atoms! {
atom nil;
atom ok;
atom error;
atom badarg;
atom false_ = "false";
atom true_ = "true";
atom __struct__;
}