use std::collections::HashMap;
use std::sync::RwLock;
use std::sync::Mutex;
use std::ops::DerefMut;
use super::{ NifTerm, NifEnv };
use ::libc::size_t;
use ::wrapper::nif_interface::{ enif_make_atom_len, enif_alloc_env, NIF_ENV, NIF_TERM };
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct NifAtom {
term: NIF_TERM,
}
impl NifAtom {
pub fn to_term<'a>(self, env: &'a NifEnv) -> NifTerm<'a> {
NifTerm::new(env, self.term)
}
unsafe fn make_atom(env: NIF_ENV, name: &str) -> Self {
NifAtom::from_nif_term(enif_make_atom_len(env, name.as_ptr() as *const u8, name.len() as size_t))
}
unsafe fn from_nif_term(term: NIF_TERM) -> Self {
NifAtom {
term: term
}
}
pub fn from_term(env: &NifEnv, term: NifTerm) -> Option<Self> {
match is_term_atom(env, term) {
true => Some(unsafe { NifAtom::from_nif_term(term.as_c_arg()) }),
false => None
}
}
}
pub fn is_term_atom(env: &NifEnv, term: NifTerm) -> bool {
::wrapper::atom::is_term_atom(env.as_c_arg(), term.as_c_arg())
}
pub fn is_term_truthy(term: NifTerm, _env: &NifEnv) -> bool {
!((term.term == get_atom("false").unwrap().term) || (term.term == get_atom("nil").unwrap().term))
}
unsafe impl Sync for NifAtom {}
unsafe impl Send for NifAtom {}
struct PrivNifEnvWrapper {
env: NIF_ENV
}
unsafe impl Send for PrivNifEnvWrapper {}
lazy_static! {
static ref ATOMS: RwLock<HashMap<&'static str, NifAtom>> = {
let mut map = HashMap::new();
let mut env_guard = ATOM_ENV.lock().unwrap();
let env = env_guard.deref_mut();
map.insert("true", unsafe { NifAtom::make_atom(env.env, "true") });
map.insert("false", unsafe { NifAtom::make_atom(env.env, "false") });
map.insert("nil", unsafe { NifAtom::make_atom(env.env, "nil") });
RwLock::new(map)
};
static ref ATOM_ENV: Mutex<PrivNifEnvWrapper> = {
Mutex::new(PrivNifEnvWrapper { env: unsafe { enif_alloc_env() } })
};
}
pub fn init_atom(name: &'static str) {
let mut atoms = ATOMS.write().unwrap();
let mut env_guard = ATOM_ENV.lock().unwrap();
let env = env_guard.deref_mut();
atoms.insert(name, unsafe { NifAtom::make_atom(env.env, name) });
}
pub fn get_atom(name: &str) -> Option<NifAtom> {
ATOMS.read().unwrap().get(name).cloned()
}
pub fn get_atom_init(name: &'static str) -> NifAtom {
let mut atoms = ATOMS.write().unwrap();
if atoms.contains_key(name) {
atoms.get(name).unwrap().clone()
} else {
let mut env_guard = ATOM_ENV.lock().unwrap();
let env = env_guard.deref_mut();
let atom = unsafe { NifAtom::make_atom(env.env, name) };
atoms.insert(name, atom);
atom
}
}