1 | use std::convert::TryFrom; |
2 | use std::ptr; |
3 | |
4 | use super::*; |
5 | use crate::{bindgen_runtime::TypeName, check_status, sys, Result}; |
6 | |
7 | #[derive (Clone, Copy)] |
8 | pub struct JsBigInt { |
9 | pub(crate) raw: Value, |
10 | pub word_count: usize, |
11 | } |
12 | |
13 | impl TypeName for JsBigInt { |
14 | fn type_name() -> &'static str { |
15 | "BigInt" |
16 | } |
17 | |
18 | fn value_type() -> ValueType { |
19 | ValueType::BigInt |
20 | } |
21 | } |
22 | |
23 | impl ValidateNapiValue for JsBigInt {} |
24 | |
25 | impl JsBigInt { |
26 | pub(crate) fn from_raw_unchecked( |
27 | env: sys::napi_env, |
28 | value: sys::napi_value, |
29 | word_count: usize, |
30 | ) -> Self { |
31 | Self { |
32 | raw: Value { |
33 | env, |
34 | value, |
35 | value_type: ValueType::Object, |
36 | }, |
37 | word_count, |
38 | } |
39 | } |
40 | |
41 | pub fn into_unknown(self) -> Result<JsUnknown> { |
42 | unsafe { JsUnknown::from_raw(self.raw.env, self.raw.value) } |
43 | } |
44 | |
45 | pub fn coerce_to_number(self) -> Result<JsNumber> { |
46 | let mut new_raw_value = ptr::null_mut(); |
47 | check_status!(unsafe { |
48 | sys::napi_coerce_to_number(self.raw.env, self.raw.value, &mut new_raw_value) |
49 | })?; |
50 | Ok(JsNumber(Value { |
51 | env: self.raw.env, |
52 | value: new_raw_value, |
53 | value_type: ValueType::Number, |
54 | })) |
55 | } |
56 | |
57 | pub fn coerce_to_string(self) -> Result<JsString> { |
58 | let mut new_raw_value = ptr::null_mut(); |
59 | check_status!(unsafe { |
60 | sys::napi_coerce_to_string(self.raw.env, self.raw.value, &mut new_raw_value) |
61 | })?; |
62 | Ok(JsString(Value { |
63 | env: self.raw.env, |
64 | value: new_raw_value, |
65 | value_type: ValueType::String, |
66 | })) |
67 | } |
68 | |
69 | pub fn coerce_to_object(self) -> Result<JsObject> { |
70 | let mut new_raw_value = ptr::null_mut(); |
71 | check_status!(unsafe { |
72 | sys::napi_coerce_to_object(self.raw.env, self.raw.value, &mut new_raw_value) |
73 | })?; |
74 | Ok(JsObject(Value { |
75 | env: self.raw.env, |
76 | value: new_raw_value, |
77 | value_type: ValueType::Object, |
78 | })) |
79 | } |
80 | |
81 | pub fn is_date(&self) -> Result<bool> { |
82 | let mut is_date = true; |
83 | check_status!(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?; |
84 | Ok(is_date) |
85 | } |
86 | |
87 | pub fn is_error(&self) -> Result<bool> { |
88 | let mut result = false; |
89 | check_status!(unsafe { sys::napi_is_error(self.raw.env, self.raw.value, &mut result) })?; |
90 | Ok(result) |
91 | } |
92 | |
93 | pub fn is_typedarray(&self) -> Result<bool> { |
94 | let mut result = false; |
95 | check_status!(unsafe { sys::napi_is_typedarray(self.raw.env, self.raw.value, &mut result) })?; |
96 | Ok(result) |
97 | } |
98 | |
99 | pub fn is_dataview(&self) -> Result<bool> { |
100 | let mut result = false; |
101 | check_status!(unsafe { sys::napi_is_dataview(self.raw.env, self.raw.value, &mut result) })?; |
102 | Ok(result) |
103 | } |
104 | |
105 | pub fn is_array(&self) -> Result<bool> { |
106 | let mut is_array = false; |
107 | check_status!(unsafe { sys::napi_is_array(self.raw.env, self.raw.value, &mut is_array) })?; |
108 | Ok(is_array) |
109 | } |
110 | |
111 | pub fn is_buffer(&self) -> Result<bool> { |
112 | let mut is_buffer = false; |
113 | check_status!(unsafe { sys::napi_is_buffer(self.raw.env, self.raw.value, &mut is_buffer) })?; |
114 | Ok(is_buffer) |
115 | } |
116 | |
117 | pub fn instanceof<Constructor: NapiRaw>(&self, constructor: Constructor) -> Result<bool> { |
118 | let mut result = false; |
119 | check_status!(unsafe { |
120 | sys::napi_instanceof(self.raw.env, self.raw.value, constructor.raw(), &mut result) |
121 | })?; |
122 | Ok(result) |
123 | } |
124 | } |
125 | |
126 | impl NapiRaw for JsBigInt { |
127 | unsafe fn raw(&self) -> sys::napi_value { |
128 | self.raw.value |
129 | } |
130 | } |
131 | |
132 | impl<'env> NapiRaw for &'env JsBigInt { |
133 | unsafe fn raw(&self) -> sys::napi_value { |
134 | self.raw.value |
135 | } |
136 | } |
137 | |
138 | impl NapiValue for JsBigInt { |
139 | unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> { |
140 | let mut word_count = 0usize; |
141 | check_status!(unsafe { |
142 | sys::napi_get_value_bigint_words( |
143 | env, |
144 | value, |
145 | ptr::null_mut(), |
146 | &mut word_count, |
147 | ptr::null_mut(), |
148 | ) |
149 | })?; |
150 | Ok(JsBigInt { |
151 | raw: Value { |
152 | env, |
153 | value, |
154 | value_type: ValueType::BigInt, |
155 | }, |
156 | word_count, |
157 | }) |
158 | } |
159 | |
160 | unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self { |
161 | let mut word_count = 0usize; |
162 | let status = unsafe { |
163 | sys::napi_get_value_bigint_words( |
164 | env, |
165 | value, |
166 | ptr::null_mut(), |
167 | &mut word_count, |
168 | ptr::null_mut(), |
169 | ) |
170 | }; |
171 | debug_assert!( |
172 | Status::from(status) == Status::Ok, |
173 | "napi_get_value_bigint_words failed" |
174 | ); |
175 | JsBigInt { |
176 | raw: Value { |
177 | env, |
178 | value, |
179 | value_type: ValueType::BigInt, |
180 | }, |
181 | word_count, |
182 | } |
183 | } |
184 | } |
185 | |
186 | /// The BigInt will be converted losslessly when the value is over what an int64 could hold. |
187 | impl TryFrom<JsBigInt> for i64 { |
188 | type Error = Error; |
189 | |
190 | fn try_from(value: JsBigInt) -> Result<i64> { |
191 | value.get_i64().map(|(v: i64, _)| v) |
192 | } |
193 | } |
194 | |
195 | /// The BigInt will be converted losslessly when the value is over what an uint64 could hold. |
196 | impl TryFrom<JsBigInt> for u64 { |
197 | type Error = Error; |
198 | |
199 | fn try_from(value: JsBigInt) -> Result<u64> { |
200 | value.get_u64().map(|(v: u64, _)| v) |
201 | } |
202 | } |
203 | |
204 | impl JsBigInt { |
205 | /// <https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words> |
206 | pub fn get_words(&mut self) -> Result<(bool, Vec<u64>)> { |
207 | let mut words: Vec<u64> = Vec::with_capacity(self.word_count); |
208 | let word_count = &mut self.word_count; |
209 | let mut sign_bit = 0; |
210 | check_status!(unsafe { |
211 | sys::napi_get_value_bigint_words( |
212 | self.raw.env, |
213 | self.raw.value, |
214 | &mut sign_bit, |
215 | word_count, |
216 | words.as_mut_ptr(), |
217 | ) |
218 | })?; |
219 | |
220 | unsafe { |
221 | words.set_len(self.word_count); |
222 | }; |
223 | |
224 | Ok((sign_bit == 1, words)) |
225 | } |
226 | |
227 | pub fn get_u64(&self) -> Result<(u64, bool)> { |
228 | let mut val: u64 = 0; |
229 | let mut lossless = false; |
230 | check_status!(unsafe { |
231 | sys::napi_get_value_bigint_uint64(self.raw.env, self.raw.value, &mut val, &mut lossless) |
232 | })?; |
233 | |
234 | Ok((val, lossless)) |
235 | } |
236 | |
237 | pub fn get_i64(&self) -> Result<(i64, bool)> { |
238 | let mut val: i64 = 0; |
239 | let mut lossless: bool = false; |
240 | check_status!(unsafe { |
241 | sys::napi_get_value_bigint_int64(self.raw.env, self.raw.value, &mut val, &mut lossless) |
242 | })?; |
243 | Ok((val, lossless)) |
244 | } |
245 | |
246 | pub fn get_i128(&mut self) -> Result<(i128, bool)> { |
247 | let (signed, words) = self.get_words()?; |
248 | |
249 | let high_part = words.first().copied().unwrap_or(0).to_le_bytes(); |
250 | let low_part = words.get(1).copied().unwrap_or(0).to_le_bytes(); |
251 | |
252 | let mut val = [0_u8; std::mem::size_of::<i128>()]; |
253 | |
254 | let (high_val, low_val) = val.split_at_mut(low_part.len()); |
255 | |
256 | high_val.copy_from_slice(&high_part); |
257 | low_val.copy_from_slice(&low_part); |
258 | |
259 | let mut val = i128::from_le_bytes(val); |
260 | |
261 | let mut loss = words.len() > 2; |
262 | let mut overflow = false; |
263 | |
264 | if signed { |
265 | let result = val.overflowing_neg(); |
266 | val = result.0; |
267 | overflow = result.1; |
268 | } |
269 | |
270 | loss = overflow || loss; |
271 | |
272 | Ok((val, loss)) |
273 | } |
274 | |
275 | pub fn get_u128(&mut self) -> Result<(bool, u128, bool)> { |
276 | let (signed, words) = self.get_words()?; |
277 | |
278 | let high_part = words.first().copied().unwrap_or(0).to_le_bytes(); |
279 | let low_part = words.get(1).copied().unwrap_or(0).to_le_bytes(); |
280 | |
281 | let mut val = [0_u8; std::mem::size_of::<u128>()]; |
282 | |
283 | let (high_val, low_val) = val.split_at_mut(low_part.len()); |
284 | |
285 | high_val.copy_from_slice(&high_part); |
286 | low_val.copy_from_slice(&low_part); |
287 | |
288 | let val = u128::from_le_bytes(val); |
289 | let len = words.len(); |
290 | |
291 | Ok((signed, val, len > 2)) |
292 | } |
293 | } |
294 | |