1use core::marker::PhantomData;
5
6use crate::types::sealed::Sealed;
7use crate::types::{AnyEnv, AnyTerm, Env, Invariant, RawTerm, Term};
8
9#[derive(Clone, Copy)]
11pub struct Map<'id> {
12 raw_term: RawTerm,
13 _id: Invariant<'id>,
14}
15
16impl<'id> Map<'id> {
17 #[crate::raw]
18 pub(crate) fn from_raw(raw_term: RawTerm) -> Self {
19 Self { raw_term, _id: PhantomData }
20 }
21
22 pub fn new(env: impl Env<'id>) -> Map<'id> {
24 let raw_term = unsafe { enif_ffi::make_new_map(env.raw_env()) };
25 Map { raw_term, _id: PhantomData }
26 }
27
28 pub fn size(self, env: impl Env<'id>) -> usize {
30 let mut size: usize = 0;
31 let ok = unsafe { enif_ffi::get_map_size(env.raw_env(), self.raw_term, &mut size) };
34 assert!(ok != 0, "enif_get_map_size failed on a validated Map");
35 size
36 }
37
38 pub fn get(self, env: impl Env<'id>, key: impl Term<'id>) -> Option<AnyTerm<'id>> {
40 let mut value: RawTerm = 0;
41 (unsafe {
42 enif_ffi::get_map_value(env.raw_env(), self.raw_term, key.raw_term(), &mut value)
43 } != 0)
44 .then(|| AnyTerm::wrap(value, env))
45 }
46
47 pub fn put(self, env: impl Env<'id>, key: impl Term<'id>, value: impl Term<'id>) -> Map<'id> {
50 let mut out: RawTerm = 0;
51 let ok = unsafe {
52 enif_ffi::make_map_put(env.raw_env(), self.raw_term, key.raw_term(), value.raw_term(), &mut out)
53 };
54 assert!(ok != 0, "make_map_put on a valid map failed");
55 Map { raw_term: out, _id: PhantomData }
56 }
57
58 pub fn update(
61 self,
62 env: impl Env<'id>,
63 key: impl Term<'id>,
64 value: impl Term<'id>,
65 ) -> Option<Map<'id>> {
66 let mut out: RawTerm = 0;
67 (unsafe {
68 enif_ffi::make_map_update(env.raw_env(), self.raw_term, key.raw_term(), value.raw_term(), &mut out)
69 } != 0)
70 .then_some(Map { raw_term: out, _id: PhantomData })
71 }
72
73 pub fn remove(self, env: impl Env<'id>, key: impl Term<'id>) -> Map<'id> {
76 let mut out: RawTerm = 0;
77 let ok = unsafe {
80 enif_ffi::make_map_remove(env.raw_env(), self.raw_term, key.raw_term(), &mut out)
81 };
82 assert!(ok != 0, "make_map_remove on a valid map failed");
83 Map { raw_term: out, _id: PhantomData }
84 }
85
86 pub fn is_map(env: impl Env<'id>, term: impl Term<'id>) -> bool {
88 unsafe { enif_ffi::is_map(env.raw_env(), term.raw_term()) != 0 }
89 }
90
91 pub fn iter(self, env: impl Env<'id>) -> MapIterator<'id> {
93 let mut iter: Box<enif_ffi::MapIterator> = Box::new(unsafe { std::mem::zeroed() });
94 let ok = unsafe {
98 enif_ffi::map_iterator_create(
99 env.raw_env(),
100 self.raw_term,
101 &mut *iter,
102 enif_ffi::MapIteratorEntry::First,
103 )
104 };
105 assert!(ok != 0, "enif_map_iterator_create failed on a validated Map");
106 MapIterator { iter, env: env.as_any_env(), exhausted: false }
107 }
108}
109
110pub struct MapIterator<'id> {
135 iter: Box<enif_ffi::MapIterator>,
136 env: AnyEnv<'id>,
137 exhausted: bool,
138}
139
140impl<'id> Iterator for MapIterator<'id> {
141 type Item = (AnyTerm<'id>, AnyTerm<'id>);
142
143 fn next(&mut self) -> Option<Self::Item> {
144 if self.exhausted {
145 return None;
146 }
147 let mut key: RawTerm = 0;
148 let mut value: RawTerm = 0;
149 if unsafe {
150 enif_ffi::map_iterator_get_pair(self.env.raw_env(), &mut *self.iter, &mut key, &mut value)
151 } != 0
152 {
153 unsafe { enif_ffi::map_iterator_next(self.env.raw_env(), &mut *self.iter) };
155 Some((AnyTerm::wrap(key, self.env), AnyTerm::wrap(value, self.env)))
156 } else {
157 self.exhausted = true;
158 None
159 }
160 }
161}
162
163impl Drop for MapIterator<'_> {
164 fn drop(&mut self) {
165 unsafe { enif_ffi::map_iterator_destroy(self.env.raw_env(), &mut *self.iter) };
166 }
167}
168
169impl PartialEq for Map<'_> {
170 fn eq(&self, other: &Self) -> bool {
171 unsafe { enif_ffi::is_identical(self.raw_term, other.raw_term) != 0 }
172 }
173}
174
175impl Eq for Map<'_> {}
176
177impl PartialOrd for Map<'_> {
178 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
179 Some(self.cmp(other))
180 }
181}
182
183impl Ord for Map<'_> {
184 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
185 let c = unsafe { enif_ffi::compare(self.raw_term, other.raw_term) };
186 c.cmp(&0)
187 }
188}
189
190impl std::fmt::Debug for Map<'_> {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 write!(f, "Map")
193 }
194}
195
196impl<'id> Sealed for Map<'id> {}
197
198impl<'id> Term<'id> for Map<'id> {
199 fn raw_term(self) -> RawTerm {
200 self.raw_term
201 }
202}