napi/bindgen_runtime/js_values/
map.rs1use std::collections::{BTreeMap, HashMap};
2use std::hash::{BuildHasher, Hash};
3
4#[cfg(feature = "object_indexmap")]
5use indexmap::IndexMap;
6
7use crate::bindgen_prelude::*;
8
9impl<K, V, S> TypeName for HashMap<K, V, S> {
10 fn type_name() -> &'static str {
11 "HashMap"
12 }
13
14 fn value_type() -> ValueType {
15 ValueType::Object
16 }
17}
18
19impl<K: From<String> + Eq + Hash, V: FromNapiValue, S> ValidateNapiValue for HashMap<K, V, S> {}
20
21impl<K, V, S> ToNapiValue for HashMap<K, V, S>
22where
23 K: AsRef<str>,
24 V: ToNapiValue,
25{
26 unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
27 let env = Env::from(raw_env);
28 #[cfg_attr(feature = "experimental", allow(unused_mut))]
29 let mut obj = Object::new(&env)?;
30 for (k, v) in val.into_iter() {
31 #[cfg(all(
32 feature = "experimental",
33 feature = "node_version_detect",
34 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
35 ))]
36 {
37 if NODE_VERSION_MAJOR >= 20 && NODE_VERSION_MINOR >= 18 {
38 fast_set_property(raw_env, obj.0.value, k, v)?;
39 } else {
40 obj.set(k.as_ref(), v)?;
41 }
42 }
43 #[cfg(not(all(
44 feature = "experimental",
45 feature = "node_version_detect",
46 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
47 )))]
48 obj.set(k.as_ref(), v)?;
49 }
50
51 unsafe { Object::to_napi_value(raw_env, obj) }
52 }
53}
54
55impl<K, V, S> FromNapiValue for HashMap<K, V, S>
56where
57 K: From<String> + Eq + Hash,
58 V: FromNapiValue,
59 S: Default + BuildHasher,
60{
61 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
62 let obj = unsafe { Object::from_napi_value(env, napi_val)? };
63 let keys = Object::keys(&obj)?;
64 let mut map: HashMap<K, V, S> = HashMap::with_capacity_and_hasher(keys.len(), S::default());
65 for key in keys.into_iter() {
66 if let Some(val) = obj.get(&key)? {
67 map.insert(K::from(key), val);
68 }
69 }
70
71 Ok(map)
72 }
73}
74
75impl<K, V> TypeName for BTreeMap<K, V> {
76 fn type_name() -> &'static str {
77 "BTreeMap"
78 }
79
80 fn value_type() -> ValueType {
81 ValueType::Object
82 }
83}
84
85impl<K: From<String> + Ord, V: FromNapiValue> ValidateNapiValue for BTreeMap<K, V> {}
86
87impl<K, V> ToNapiValue for BTreeMap<K, V>
88where
89 K: AsRef<str>,
90 V: ToNapiValue,
91{
92 unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
93 let env = Env::from(raw_env);
94 #[cfg_attr(feature = "experimental", allow(unused_mut))]
95 let mut obj = Object::new(&env)?;
96 for (k, v) in val.into_iter() {
97 #[cfg(all(
98 feature = "experimental",
99 feature = "node_version_detect",
100 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
101 ))]
102 {
103 if crate::bindgen_runtime::NODE_VERSION_MAJOR >= 20 && NODE_VERSION_MINOR >= 18 {
104 fast_set_property(raw_env, obj.0.value, k, v)?;
105 } else {
106 obj.set(k.as_ref(), v)?;
107 }
108 }
109 #[cfg(not(all(
110 feature = "experimental",
111 feature = "node_version_detect",
112 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
113 )))]
114 obj.set(k.as_ref(), v)?;
115 }
116
117 unsafe { Object::to_napi_value(raw_env, obj) }
118 }
119}
120
121impl<K, V> FromNapiValue for BTreeMap<K, V>
122where
123 K: From<String> + Ord,
124 V: FromNapiValue,
125{
126 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
127 let obj = unsafe { Object::from_napi_value(env, napi_val)? };
128 let mut map = BTreeMap::default();
129 for key in Object::keys(&obj)?.into_iter() {
130 if let Some(val) = obj.get(&key)? {
131 map.insert(K::from(key), val);
132 }
133 }
134
135 Ok(map)
136 }
137}
138
139#[cfg(feature = "object_indexmap")]
140impl<K, V, S> TypeName for IndexMap<K, V, S> {
141 fn type_name() -> &'static str {
142 "IndexMap"
143 }
144
145 fn value_type() -> ValueType {
146 ValueType::Object
147 }
148}
149
150#[cfg(feature = "object_indexmap")]
151impl<K: From<String> + Hash + Eq, V: FromNapiValue> ValidateNapiValue for IndexMap<K, V> {}
152
153#[cfg(feature = "object_indexmap")]
154impl<K, V, S> ToNapiValue for IndexMap<K, V, S>
155where
156 K: AsRef<str>,
157 V: ToNapiValue,
158 S: Default + BuildHasher,
159{
160 unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
161 let env = Env::from(raw_env);
162 #[cfg_attr(feature = "experimental", allow(unused_mut))]
163 let mut obj = Object::new(&env)?;
164 for (k, v) in val.into_iter() {
165 #[cfg(all(
166 feature = "experimental",
167 feature = "node_version_detect",
168 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
169 ))]
170 {
171 if crate::bindgen_runtime::NODE_VERSION_MAJOR >= 20 && NODE_VERSION_MINOR >= 18 {
172 fast_set_property(raw_env, obj.0.value, k, v)?;
173 } else {
174 obj.set(k.as_ref(), v)?;
175 }
176 }
177 #[cfg(not(all(
178 feature = "experimental",
179 feature = "node_version_detect",
180 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
181 )))]
182 obj.set(k.as_ref(), v)?;
183 }
184
185 unsafe { Object::to_napi_value(raw_env, obj) }
186 }
187}
188
189#[cfg(feature = "object_indexmap")]
190impl<K, V, S> FromNapiValue for IndexMap<K, V, S>
191where
192 K: From<String> + Hash + Eq,
193 V: FromNapiValue,
194 S: Default + BuildHasher,
195{
196 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
197 let obj = unsafe { Object::from_napi_value(env, napi_val)? };
198 let mut map = IndexMap::default();
199 for key in Object::keys(&obj)?.into_iter() {
200 if let Some(val) = obj.get(&key)? {
201 map.insert(K::from(key), val);
202 }
203 }
204
205 Ok(map)
206 }
207}
208
209#[cfg(all(
210 feature = "experimental",
211 feature = "node_version_detect",
212 any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
213))]
214fn fast_set_property<K: AsRef<str>, V: ToNapiValue>(
215 raw_env: sys::napi_env,
216 obj: sys::napi_value,
217 k: K,
218 v: V,
219) -> Result<()> {
220 let mut property_key = std::ptr::null_mut();
221 check_status!(
222 unsafe {
223 sys::node_api_create_property_key_utf8(
224 raw_env,
225 k.as_ref().as_ptr().cast(),
226 k.as_ref().len() as isize,
227 &mut property_key,
228 )
229 },
230 "Create property key failed"
231 )?;
232 check_status!(
233 unsafe { sys::napi_set_property(raw_env, obj, property_key, V::to_napi_value(raw_env, v)?,) },
234 "Failed to set property"
235 )?;
236 Ok(())
237}