1use std::ffi::c_double;
2
3#[cfg(feature = "nif_version_2_15")]
4use crate::sys::ErlNifTermType;
5
6use crate::wrapper::check;
7use crate::Term;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum TermType {
11 Atom,
12 Binary,
13 Fun,
14 List,
15 Map,
16 Integer,
17 Float,
18 Pid,
19 Port,
20 Ref,
21 Tuple,
22 Unknown,
23}
24
25#[cfg(feature = "nif_version_2_15")]
26impl From<ErlNifTermType> for TermType {
27 fn from(term_type: ErlNifTermType) -> Self {
28 use ErlNifTermType::*;
29 use TermType::*;
30 match term_type {
31 ERL_NIF_TERM_TYPE_ATOM => Atom,
32 ERL_NIF_TERM_TYPE_BITSTRING => Binary,
33 ERL_NIF_TERM_TYPE_FLOAT => Float,
34 ERL_NIF_TERM_TYPE_FUN => Fun,
35 ERL_NIF_TERM_TYPE_INTEGER => Integer,
36 ERL_NIF_TERM_TYPE_LIST => List,
37 ERL_NIF_TERM_TYPE_MAP => Map,
38 ERL_NIF_TERM_TYPE_PID => Pid,
39 ERL_NIF_TERM_TYPE_PORT => Port,
40 ERL_NIF_TERM_TYPE_REFERENCE => Ref,
41 ERL_NIF_TERM_TYPE_TUPLE => Tuple,
42 _ => Unknown,
43 }
44 }
45}
46
47pub fn get_type(term: Term) -> TermType {
48 if cfg!(feature = "nif_version_2_15") {
49 term.get_erl_type().into()
50 } else if term.is_atom() {
51 TermType::Atom
52 } else if term.is_binary() {
53 TermType::Binary
54 } else if term.is_fun() {
55 TermType::Fun
56 } else if term.is_list() || term.is_empty_list() {
57 TermType::List
58 } else if term.is_map() {
59 TermType::Map
60 } else if term.is_number() {
61 if term.is_float() {
62 TermType::Float
63 } else {
64 TermType::Integer
65 }
66 } else if term.is_pid() {
67 TermType::Pid
68 } else if term.is_port() {
69 TermType::Port
70 } else if term.is_ref() {
71 TermType::Ref
72 } else if term.is_tuple() {
73 TermType::Tuple
74 } else {
75 TermType::Unknown
76 }
77}
78
79macro_rules! impl_check {
80 ($check_fun:ident) => {
81 pub fn $check_fun(self) -> bool {
82 unsafe { check::$check_fun(self.get_env().as_c_arg(), self.as_c_arg()) }
83 }
84 };
85}
86
87impl Term<'_> {
89 pub fn get_type(self) -> TermType {
93 get_type(self)
94 }
95
96 impl_check!(is_atom);
97 impl_check!(is_binary);
98 impl_check!(is_empty_list);
99 impl_check!(is_fun);
100 impl_check!(is_list);
101 impl_check!(is_map);
102 impl_check!(is_number);
103 impl_check!(is_pid);
104 impl_check!(is_port);
105 impl_check!(is_ref);
106 impl_check!(is_tuple);
107
108 pub fn is_float(self) -> bool {
109 let mut val: c_double = 0.0;
110 unsafe {
111 crate::sys::enif_get_double(self.get_env().as_c_arg(), self.as_c_arg(), &mut val) == 1
112 }
113 }
114
115 pub fn is_integer(self) -> bool {
116 self.is_number() && !self.is_float()
117 }
118}