1use crate::sys::*;
2use crate::types::binary::OwnedBinary;
3use crate::wrapper::env::term_to_binary;
4use crate::wrapper::NIF_TERM;
5use crate::{Binary, Decoder, Env, NifResult};
6use std::cmp::Ordering;
7use std::fmt::{self, Debug};
8use std::hash::{Hash, Hasher};
9
10#[derive(Clone, Copy)]
15pub struct Term<'a> {
16 term: NIF_TERM,
17 env: Env<'a>,
18}
19
20impl Debug for Term<'_> {
21 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
22 crate::wrapper::term::fmt(self.as_c_arg(), f)
23 }
24}
25
26impl<'a> Term<'a> {
27 #[inline]
33 pub unsafe fn new(env: Env<'a>, inner: NIF_TERM) -> Self {
34 Term { term: inner, env }
35 }
36 #[inline]
39 pub fn as_c_arg(&self) -> NIF_TERM {
40 self.term
41 }
42
43 #[inline]
44 pub fn get_env(self) -> Env<'a> {
45 self.env
46 }
47
48 #[inline]
53 pub fn in_env<'b>(&self, env: Env<'b>) -> Term<'b> {
54 if self.get_env() == env {
55 unsafe { Term::new(env, self.as_c_arg()) }
60 } else {
61 unsafe { Term::new(env, enif_make_copy(env.as_c_arg(), self.as_c_arg())) }
62 }
63 }
64
65 pub fn decode<T>(self) -> NifResult<T>
76 where
77 T: Decoder<'a>,
78 {
79 Decoder::decode(self)
80 }
81
82 #[inline]
89 pub fn decode_as_binary(self) -> NifResult<Binary<'a>> {
90 if self.is_binary() {
91 return Binary::from_term(self);
92 }
93 Binary::from_iolist(self)
94 }
95
96 #[inline]
97 pub fn to_binary(self) -> OwnedBinary {
98 let raw_binary = unsafe { term_to_binary(self.env.as_c_arg(), self.as_c_arg()) }.unwrap();
99 unsafe { OwnedBinary::from_raw(raw_binary) }
100 }
101
102 pub fn hash_internal(&self, salt: u32) -> u32 {
107 unsafe {
108 enif_hash(
109 ErlNifHash::ERL_NIF_INTERNAL_HASH,
110 self.as_c_arg(),
111 salt as u64,
112 ) as u32
113 }
114 }
115
116 pub fn hash_phash2(&self) -> u32 {
121 unsafe { enif_hash(ErlNifHash::ERL_NIF_PHASH2, self.as_c_arg(), 0) as u32 }
122 }
123
124 #[cfg(feature = "nif_version_2_15")]
125 pub fn get_erl_type(&self) -> ErlNifTermType {
126 unsafe { enif_term_type(self.env.as_c_arg(), self.as_c_arg()) }
127 }
128}
129
130impl PartialEq for Term<'_> {
131 fn eq(&self, other: &Term) -> bool {
132 unsafe { enif_is_identical(self.as_c_arg(), other.as_c_arg()) == 1 }
133 }
134}
135impl Eq for Term<'_> {}
136
137fn cmp(lhs: &Term, rhs: &Term) -> Ordering {
138 let ord = unsafe { enif_compare(lhs.as_c_arg(), rhs.as_c_arg()) };
139 match ord {
140 0 => Ordering::Equal,
141 n if n < 0 => Ordering::Less,
142 _ => Ordering::Greater,
143 }
144}
145
146impl Ord for Term<'_> {
147 fn cmp(&self, other: &Term) -> Ordering {
148 cmp(self, other)
149 }
150}
151impl<'a> PartialOrd for Term<'a> {
152 fn partial_cmp(&self, other: &Term<'a>) -> Option<Ordering> {
153 Some(self.cmp(other))
154 }
155}
156
157impl Hash for Term<'_> {
158 fn hash<H: Hasher>(&self, state: &mut H) {
159 state.write_u32(self.hash_internal(0));
163 }
164}
165
166unsafe impl Sync for Term<'_> {}
167unsafe impl Send for Term<'_> {}