napi_h/js_values/
bigint.rs

1use std::convert::TryFrom;
2use std::ptr;
3
4use super::*;
5use crate::{bindgen_runtime::TypeName, check_status, sys, Result};
6
7#[derive(Clone, Copy)]
8pub struct JsBigInt {
9  pub(crate) raw: Value,
10  pub word_count: usize,
11}
12
13impl TypeName for JsBigInt {
14  fn type_name() -> &'static str {
15    "BigInt"
16  }
17
18  fn value_type() -> ValueType {
19    ValueType::BigInt
20  }
21}
22
23impl ValidateNapiValue for JsBigInt {}
24
25impl 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
126impl NapiRaw for JsBigInt {
127  unsafe fn raw(&self) -> sys::napi_value {
128    self.raw.value
129  }
130}
131
132impl<'env> NapiRaw for &'env JsBigInt {
133  unsafe fn raw(&self) -> sys::napi_value {
134    self.raw.value
135  }
136}
137
138impl 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.
187impl TryFrom<JsBigInt> for i64 {
188  type Error = Error;
189
190  fn try_from(value: JsBigInt) -> Result<i64> {
191    value.get_i64().map(|(v, _)| v)
192  }
193}
194
195/// The BigInt will be converted losslessly when the value is over what an uint64 could hold.
196impl TryFrom<JsBigInt> for u64 {
197  type Error = Error;
198
199  fn try_from(value: JsBigInt) -> Result<u64> {
200    value.get_u64().map(|(v, _)| v)
201  }
202}
203
204impl 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}