1 | /// We don't implement `FromNapiValue` for `i64` `u64` `i128` `u128` `isize` `usize` here |
2 | /// Because converting directly from `JsBigInt` to these values may result in a loss of precision and thus unintended behavior |
3 | /// ```rust |
4 | /// use napi::{bindgen_prelude::*, JsBigint}; |
5 | /// |
6 | /// #[napi] |
7 | /// fn bigint_add(mut a: Bigint, mut b: Bigint) -> u128 { |
8 | /// a.get_u128().1 + b.get_u128().1 // We have opportunity to check if the `u128` has lost precision |
9 | /// } |
10 | /// ``` |
11 | use std::ptr; |
12 | |
13 | use crate::{check_status, sys}; |
14 | |
15 | use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; |
16 | |
17 | /// i64 is converted to `Number` |
18 | #[repr (transparent)] |
19 | #[allow (non_camel_case_types)] |
20 | pub struct i64n(pub i64); |
21 | |
22 | /// <https://nodejs.org/api/n-api.html#napi_create_bigint_words> |
23 | /// The resulting BigInt is calculated as: (–1)^sign_bit (words\[0\] × (2^64)^0 + words\[1\] × (2^64)^1 + …) |
24 | #[derive (Debug, Clone)] |
25 | pub struct BigInt { |
26 | /// true for negative numbers |
27 | pub sign_bit: bool, |
28 | pub words: Vec<u64>, |
29 | } |
30 | |
31 | impl TypeName for BigInt { |
32 | fn type_name() -> &'static str { |
33 | "BigInt" |
34 | } |
35 | |
36 | fn value_type() -> crate::ValueType { |
37 | crate::ValueType::BigInt |
38 | } |
39 | } |
40 | |
41 | impl ValidateNapiValue for BigInt {} |
42 | |
43 | impl FromNapiValue for BigInt { |
44 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> { |
45 | let mut word_count = 0usize; |
46 | check_status!(unsafe { |
47 | sys::napi_get_value_bigint_words( |
48 | env, |
49 | napi_val, |
50 | ptr::null_mut(), |
51 | &mut word_count, |
52 | ptr::null_mut(), |
53 | ) |
54 | })?; |
55 | let mut words: Vec<u64> = Vec::with_capacity(word_count); |
56 | let mut sign_bit = 0; |
57 | |
58 | unsafe { |
59 | check_status!(sys::napi_get_value_bigint_words( |
60 | env, |
61 | napi_val, |
62 | &mut sign_bit, |
63 | &mut word_count, |
64 | words.as_mut_ptr(), |
65 | ))?; |
66 | |
67 | words.set_len(word_count); |
68 | } |
69 | if word_count == 0 { |
70 | words = vec![0]; |
71 | } |
72 | Ok(BigInt { |
73 | sign_bit: sign_bit == 1, |
74 | words, |
75 | }) |
76 | } |
77 | } |
78 | |
79 | impl BigInt { |
80 | /// (signed, value, lossless) |
81 | /// get the first word of the BigInt as `u64` |
82 | /// return true in the last element of tuple if the value is lossless |
83 | /// or the value is truncated |
84 | pub fn get_u64(&self) -> (bool, u64, bool) { |
85 | ( |
86 | self.sign_bit, |
87 | self.words[0], |
88 | !self.sign_bit && self.words.len() == 1, |
89 | ) |
90 | } |
91 | |
92 | /// (value, lossless) |
93 | /// get the first word of the BigInt as `i64` with the sign applied |
94 | /// return true if the value is lossless |
95 | /// or the value is truncated |
96 | pub fn get_i64(&self) -> (i64, bool) { |
97 | if self.sign_bit && self.words[0] == i64::MIN.unsigned_abs() { |
98 | return (i64::MIN, self.words.len() == 1); |
99 | } |
100 | ( |
101 | self.words[0] as i64 * if self.sign_bit { -1 } else { 1 }, |
102 | self.words.len() == 1 && self.words[0] as i64 >= 0, |
103 | ) |
104 | } |
105 | |
106 | /// (value, lossless) |
107 | /// get the first two words of the BigInt as `i128` with the sign applied |
108 | /// return true if the value is lossless |
109 | /// or the value is truncated |
110 | pub fn get_i128(&self) -> (i128, bool) { |
111 | let len = self.words.len(); |
112 | if len == 1 { |
113 | ( |
114 | self.words[0] as i128 * if self.sign_bit { -1 } else { 1 }, |
115 | true, |
116 | ) |
117 | } else { |
118 | let val = self.words[0] as u128 + ((self.words[1] as u128) << 64); |
119 | if self.sign_bit && val == i128::MIN.unsigned_abs() { |
120 | return (i128::MIN, len > 2); |
121 | } |
122 | ( |
123 | val as i128 * if self.sign_bit { -1 } else { 1 }, |
124 | len == 2 && self.words[1] as i64 >= 0, |
125 | ) |
126 | } |
127 | } |
128 | |
129 | /// (signed, value, lossless) |
130 | /// get the first two words of the BigInt as `u128` |
131 | /// return true if the value is lossless |
132 | /// or the value is truncated |
133 | pub fn get_u128(&self) -> (bool, u128, bool) { |
134 | let len = self.words.len(); |
135 | if len == 1 { |
136 | (self.sign_bit, self.words[0] as u128, true) |
137 | } else { |
138 | let val = self.words[0] as u128 + ((self.words[1] as u128) << 64); |
139 | (self.sign_bit, val, len == 2) |
140 | } |
141 | } |
142 | } |
143 | |
144 | impl ToNapiValue for BigInt { |
145 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
146 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
147 | let len: usize = val.words.len(); |
148 | check_status!(unsafe { |
149 | sys::napi_create_bigint_words( |
150 | env, |
151 | match val.sign_bit { |
152 | true => 1, |
153 | false => 0, |
154 | }, |
155 | len, |
156 | val.words.as_ptr(), |
157 | &mut raw_value, |
158 | ) |
159 | })?; |
160 | Ok(raw_value) |
161 | } |
162 | } |
163 | |
164 | pub(crate) unsafe fn u128_with_sign_to_napi_value( |
165 | env: sys::napi_env, |
166 | val: u128, |
167 | sign_bit: i32, |
168 | ) -> crate::Result<sys::napi_value> { |
169 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
170 | if cfg!(target_endian = "little" ) { |
171 | let words: *const u64 = &val as *const u128 as *const u64; |
172 | check_status!(unsafe { |
173 | sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) |
174 | })?; |
175 | return Ok(raw_value); |
176 | } |
177 | |
178 | let arr: [u64; 2] = [val as _, (val >> 64) as _]; |
179 | let words: *const u64 = &arr as *const u64; |
180 | check_status!(unsafe { sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) })?; |
181 | Ok(raw_value) |
182 | } |
183 | |
184 | impl ToNapiValue for i128 { |
185 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
186 | let sign_bit: i32 = i32::from(val <= 0); |
187 | let val: u128 = val.unsigned_abs(); |
188 | u128_with_sign_to_napi_value(env, val, sign_bit) |
189 | } |
190 | } |
191 | |
192 | impl ToNapiValue for u128 { |
193 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
194 | u128_with_sign_to_napi_value(env, val, sign_bit:0) |
195 | } |
196 | } |
197 | |
198 | impl ToNapiValue for i64n { |
199 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
200 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
201 | check_status!(unsafe { sys::napi_create_bigint_int64(env, val.0, &mut raw_value) })?; |
202 | Ok(raw_value) |
203 | } |
204 | } |
205 | |
206 | impl ToNapiValue for u64 { |
207 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
208 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
209 | check_status!(unsafe { sys::napi_create_bigint_uint64(env, val, &mut raw_value) })?; |
210 | Ok(raw_value) |
211 | } |
212 | } |
213 | |
214 | impl ToNapiValue for usize { |
215 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
216 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
217 | check_status!(unsafe { sys::napi_create_bigint_uint64(env, val as u64, &mut raw_value) })?; |
218 | Ok(raw_value) |
219 | } |
220 | } |
221 | |
222 | impl ToNapiValue for isize { |
223 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
224 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
225 | check_status!(unsafe { sys::napi_create_bigint_int64(env, val as i64, &mut raw_value) })?; |
226 | Ok(raw_value) |
227 | } |
228 | } |
229 | |
230 | impl From<i64> for BigInt { |
231 | fn from(val: i64) -> Self { |
232 | BigInt { |
233 | sign_bit: val < 0, |
234 | words: vec![val.unsigned_abs()], |
235 | } |
236 | } |
237 | } |
238 | |
239 | impl From<u64> for BigInt { |
240 | fn from(val: u64) -> Self { |
241 | BigInt { |
242 | sign_bit: false, |
243 | words: vec![val], |
244 | } |
245 | } |
246 | } |
247 | |
248 | impl From<i128> for BigInt { |
249 | fn from(val: i128) -> Self { |
250 | let sign_bit: bool = val < 0; |
251 | let val: u128 = val.unsigned_abs(); |
252 | BigInt { |
253 | sign_bit, |
254 | words: vec![val as _, (val >> 64) as _], |
255 | } |
256 | } |
257 | } |
258 | |
259 | impl From<u128> for BigInt { |
260 | fn from(val: u128) -> Self { |
261 | BigInt { |
262 | sign_bit: false, |
263 | words: vec![val as _, (val >> 64) as _], |
264 | } |
265 | } |
266 | } |
267 | |