1use std::convert::TryFrom;
2use std::ptr;
3
4use super::*;
5use crate::{
6 bindgen_runtime::{FromNapiValue, TypeName},
7 check_status, sys, Result,
8};
9
10#[deprecated(since = "3.0.0", note = "Use `napi::bindgen_prelude::BigInt` instead")]
11#[derive(Clone, Copy)]
12pub struct JsBigInt {
13 pub(crate) raw: Value,
14 pub word_count: usize,
15}
16
17impl TypeName for JsBigInt {
18 fn type_name() -> &'static str {
19 "BigInt"
20 }
21
22 fn value_type() -> ValueType {
23 ValueType::BigInt
24 }
25}
26
27impl ValidateNapiValue for JsBigInt {}
28
29impl JsValue<'_> for JsBigInt {
30 fn value(&self) -> Value {
31 self.raw
32 }
33}
34
35impl FromNapiValue for JsBigInt {
36 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
37 let mut word_count = 0usize;
38 check_status!(unsafe {
39 sys::napi_get_value_bigint_words(
40 env,
41 napi_val,
42 ptr::null_mut(),
43 &mut word_count,
44 ptr::null_mut(),
45 )
46 })?;
47 Ok(JsBigInt {
48 raw: Value {
49 env,
50 value: napi_val,
51 value_type: ValueType::BigInt,
52 },
53 word_count,
54 })
55 }
56}
57
58impl JsBigInt {
59 pub(crate) fn from_raw_unchecked(
60 env: sys::napi_env,
61 value: sys::napi_value,
62 word_count: usize,
63 ) -> Self {
64 Self {
65 raw: Value {
66 env,
67 value,
68 value_type: ValueType::Object,
69 },
70 word_count,
71 }
72 }
73}
74
75impl NapiRaw for JsBigInt {
76 unsafe fn raw(&self) -> sys::napi_value {
77 self.raw.value
78 }
79}
80
81impl NapiRaw for &JsBigInt {
82 unsafe fn raw(&self) -> sys::napi_value {
83 self.raw.value
84 }
85}
86
87impl NapiValue for JsBigInt {
88 unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
89 let mut word_count = 0usize;
90 check_status!(unsafe {
91 sys::napi_get_value_bigint_words(
92 env,
93 value,
94 ptr::null_mut(),
95 &mut word_count,
96 ptr::null_mut(),
97 )
98 })?;
99 Ok(JsBigInt {
100 raw: Value {
101 env,
102 value,
103 value_type: ValueType::BigInt,
104 },
105 word_count,
106 })
107 }
108
109 unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
110 let mut word_count = 0usize;
111 let status = unsafe {
112 sys::napi_get_value_bigint_words(
113 env,
114 value,
115 ptr::null_mut(),
116 &mut word_count,
117 ptr::null_mut(),
118 )
119 };
120 debug_assert!(
121 Status::from(status) == Status::Ok,
122 "napi_get_value_bigint_words failed"
123 );
124 JsBigInt {
125 raw: Value {
126 env,
127 value,
128 value_type: ValueType::BigInt,
129 },
130 word_count,
131 }
132 }
133}
134
135impl TryFrom<JsBigInt> for i64 {
137 type Error = Error;
138
139 fn try_from(value: JsBigInt) -> Result<i64> {
140 value.get_i64().map(|(v, _)| v)
141 }
142}
143
144impl TryFrom<JsBigInt> for u64 {
146 type Error = Error;
147
148 fn try_from(value: JsBigInt) -> Result<u64> {
149 value.get_u64().map(|(v, _)| v)
150 }
151}
152
153impl JsBigInt {
154 pub fn get_words(&mut self) -> Result<(bool, Vec<u64>)> {
156 let mut words: Vec<u64> = Vec::with_capacity(self.word_count);
157 let word_count = &mut self.word_count;
158 let mut sign_bit = 0;
159 check_status!(unsafe {
160 sys::napi_get_value_bigint_words(
161 self.raw.env,
162 self.raw.value,
163 &mut sign_bit,
164 word_count,
165 words.as_mut_ptr(),
166 )
167 })?;
168
169 unsafe {
170 words.set_len(self.word_count);
171 };
172
173 Ok((sign_bit == 1, words))
174 }
175
176 pub fn get_u64(&self) -> Result<(u64, bool)> {
177 let mut val: u64 = 0;
178 let mut lossless = false;
179 check_status!(unsafe {
180 sys::napi_get_value_bigint_uint64(self.raw.env, self.raw.value, &mut val, &mut lossless)
181 })?;
182
183 Ok((val, lossless))
184 }
185
186 pub fn get_i64(&self) -> Result<(i64, bool)> {
187 let mut val: i64 = 0;
188 let mut lossless: bool = false;
189 check_status!(unsafe {
190 sys::napi_get_value_bigint_int64(self.raw.env, self.raw.value, &mut val, &mut lossless)
191 })?;
192 Ok((val, lossless))
193 }
194
195 pub fn get_i128(&mut self) -> Result<(i128, bool)> {
196 let (signed, words) = self.get_words()?;
197
198 let low_part = words.first().copied().unwrap_or(0).to_ne_bytes();
199 let high_part = words.get(1).copied().unwrap_or(0).to_ne_bytes();
200
201 let mut val = [0_u8; std::mem::size_of::<i128>()];
202 let high_val: &mut [u8];
203 let low_val: &mut [u8];
204 if cfg!(target_endian = "little") {
205 (low_val, high_val) = val.split_at_mut(low_part.len());
206 } else {
207 (high_val, low_val) = val.split_at_mut(low_part.len());
208 }
209
210 high_val.copy_from_slice(&high_part);
211 low_val.copy_from_slice(&low_part);
212
213 let mut val = i128::from_ne_bytes(val);
214
215 let mut loss = words.len() > 2;
216 let mut overflow = false;
217
218 if signed {
219 let result = val.overflowing_neg();
220 val = result.0;
221 overflow = result.1;
222 }
223
224 loss = overflow || loss;
225
226 Ok((val, loss))
227 }
228
229 pub fn get_u128(&mut self) -> Result<(bool, u128, bool)> {
230 let (signed, words) = self.get_words()?;
231
232 let low_part = words.first().copied().unwrap_or(0).to_ne_bytes();
233 let high_part = words.get(1).copied().unwrap_or(0).to_ne_bytes();
234
235 let mut val = [0_u8; std::mem::size_of::<i128>()];
236 let high_val: &mut [u8];
237 let low_val: &mut [u8];
238 if cfg!(target_endian = "little") {
239 (low_val, high_val) = val.split_at_mut(low_part.len());
240 } else {
241 (high_val, low_val) = val.split_at_mut(low_part.len());
242 }
243
244 high_val.copy_from_slice(&high_part);
245 low_val.copy_from_slice(&low_part);
246
247 let val = u128::from_ne_bytes(val);
248
249 let len = words.len();
250
251 Ok((signed, val, len > 2))
252 }
253}