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` |
94 | /// return true if the value is lossless |
95 | /// or the value is truncated |
96 | pub fn get_i64(&self) -> (i64, bool) { |
97 | let val = self.words[0] as i64; |
98 | (val, val as u64 == self.words[0] && self.words.len() == 1) |
99 | } |
100 | |
101 | /// (value, lossless) |
102 | /// get the first two words of the BigInt as `i128` |
103 | /// return true if the value is lossless |
104 | /// or the value is truncated |
105 | pub fn get_i128(&self) -> (i128, bool) { |
106 | let len = self.words.len(); |
107 | if len == 1 { |
108 | (self.words[0] as i128, false) |
109 | } else { |
110 | let i128_words: [i64; 2] = [self.words[0] as _, self.words[1] as _]; |
111 | let mut val = unsafe { ptr::read(i128_words.as_ptr() as *const i128) }; |
112 | if self.sign_bit { |
113 | val = -val; |
114 | } |
115 | (val, len > 2) |
116 | } |
117 | } |
118 | |
119 | /// (signed, value, lossless) |
120 | /// get the first two words of the BigInt as `u128` |
121 | /// return true if the value is lossless |
122 | /// or the value is truncated |
123 | pub fn get_u128(&self) -> (bool, u128, bool) { |
124 | let len = self.words.len(); |
125 | if len == 1 { |
126 | (self.sign_bit, self.words[0] as u128, false) |
127 | } else { |
128 | let u128_words: [u64; 2] = [self.words[0], self.words[1]]; |
129 | let val = unsafe { ptr::read(u128_words.as_ptr() as *const u128) }; |
130 | (self.sign_bit, val, len > 2) |
131 | } |
132 | } |
133 | } |
134 | |
135 | impl ToNapiValue for BigInt { |
136 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
137 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
138 | let len: usize = val.words.len(); |
139 | check_status!(unsafe { |
140 | sys::napi_create_bigint_words( |
141 | env, |
142 | match val.sign_bit { |
143 | true => 1, |
144 | false => 0, |
145 | }, |
146 | len, |
147 | val.words.as_ptr(), |
148 | &mut raw_value, |
149 | ) |
150 | })?; |
151 | Ok(raw_value) |
152 | } |
153 | } |
154 | |
155 | impl ToNapiValue for i128 { |
156 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
157 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
158 | let sign_bit: i32 = i32::from(val <= 0); |
159 | let words: *const u64 = &val as *const i128 as *const u64; |
160 | check_status!(unsafe { |
161 | sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) |
162 | })?; |
163 | Ok(raw_value) |
164 | } |
165 | } |
166 | |
167 | impl ToNapiValue for u128 { |
168 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
169 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
170 | let words: *const u64 = &val as *const u128 as *const u64; |
171 | check_status!(unsafe { sys::napi_create_bigint_words(env, 0, 2, words, &mut raw_value) })?; |
172 | Ok(raw_value) |
173 | } |
174 | } |
175 | |
176 | impl ToNapiValue for i64n { |
177 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
178 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
179 | check_status!(unsafe { sys::napi_create_bigint_int64(env, val.0, &mut raw_value) })?; |
180 | Ok(raw_value) |
181 | } |
182 | } |
183 | |
184 | impl ToNapiValue for u64 { |
185 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
186 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
187 | check_status!(unsafe { sys::napi_create_bigint_uint64(env, val, &mut raw_value) })?; |
188 | Ok(raw_value) |
189 | } |
190 | } |
191 | |
192 | impl ToNapiValue for usize { |
193 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
194 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
195 | check_status!(unsafe { sys::napi_create_bigint_uint64(env, val as u64, &mut raw_value) })?; |
196 | Ok(raw_value) |
197 | } |
198 | } |
199 | |
200 | impl ToNapiValue for isize { |
201 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { |
202 | let mut raw_value: *mut napi_value__ = ptr::null_mut(); |
203 | check_status!(unsafe { sys::napi_create_bigint_int64(env, val as i64, &mut raw_value) })?; |
204 | Ok(raw_value) |
205 | } |
206 | } |
207 | |
208 | impl From<i64> for BigInt { |
209 | fn from(val: i64) -> Self { |
210 | BigInt { |
211 | sign_bit: val < 0, |
212 | words: vec![val as u64], |
213 | } |
214 | } |
215 | } |
216 | |
217 | impl From<u64> for BigInt { |
218 | fn from(val: u64) -> Self { |
219 | BigInt { |
220 | sign_bit: false, |
221 | words: vec![val], |
222 | } |
223 | } |
224 | } |
225 | |
226 | impl From<i128> for BigInt { |
227 | fn from(val: i128) -> Self { |
228 | let sign_bit: bool = val < 0; |
229 | let words: [u8; 16] = (if sign_bit { -val } else { val }).to_ne_bytes(); |
230 | BigInt { |
231 | sign_bit, |
232 | words: unsafe { std::slice::from_raw_parts(data:words.as_ptr() as *mut _, len:2).to_vec() }, |
233 | } |
234 | } |
235 | } |
236 | |
237 | impl From<u128> for BigInt { |
238 | fn from(val: u128) -> Self { |
239 | let words: [u8; 16] = val.to_ne_bytes(); |
240 | BigInt { |
241 | sign_bit: false, |
242 | words: unsafe { std::slice::from_raw_parts(data:words.as_ptr() as *mut _, len:2).to_vec() }, |
243 | } |
244 | } |
245 | } |
246 | |