napi/bindgen_runtime/js_values/
bigint.rsuse std::ptr;
use crate::{check_status, sys};
use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue};
#[repr(transparent)]
#[allow(non_camel_case_types)]
pub struct i64n(pub i64);
#[derive(Debug, Clone)]
pub struct BigInt {
pub sign_bit: bool,
pub words: Vec<u64>,
}
impl TypeName for BigInt {
fn type_name() -> &'static str {
"BigInt"
}
fn value_type() -> crate::ValueType {
crate::ValueType::BigInt
}
}
impl ValidateNapiValue for BigInt {}
impl FromNapiValue for BigInt {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
let mut word_count = 0usize;
check_status!(unsafe {
sys::napi_get_value_bigint_words(
env,
napi_val,
ptr::null_mut(),
&mut word_count,
ptr::null_mut(),
)
})?;
let mut words: Vec<u64> = Vec::with_capacity(word_count);
let mut sign_bit = 0;
unsafe {
check_status!(sys::napi_get_value_bigint_words(
env,
napi_val,
&mut sign_bit,
&mut word_count,
words.as_mut_ptr(),
))?;
words.set_len(word_count);
}
if word_count == 0 {
words = vec![0];
}
Ok(BigInt {
sign_bit: sign_bit == 1,
words,
})
}
}
impl BigInt {
pub fn get_u64(&self) -> (bool, u64, bool) {
(
self.sign_bit,
self.words[0],
!self.sign_bit && self.words.len() == 1,
)
}
pub fn get_i64(&self) -> (i64, bool) {
if self.sign_bit && self.words[0] == i64::MIN.unsigned_abs() {
return (i64::MIN, self.words.len() == 1);
}
(
self.words[0] as i64 * if self.sign_bit { -1 } else { 1 },
self.words.len() == 1 && self.words[0] as i64 >= 0,
)
}
pub fn get_i128(&self) -> (i128, bool) {
let len = self.words.len();
if len == 1 {
(
self.words[0] as i128 * if self.sign_bit { -1 } else { 1 },
true,
)
} else {
let val = self.words[0] as u128 + ((self.words[1] as u128) << 64);
if self.sign_bit && val == i128::MIN.unsigned_abs() {
return (i128::MIN, len > 2);
}
(
val as i128 * if self.sign_bit { -1 } else { 1 },
len == 2 && self.words[1] as i64 >= 0,
)
}
}
pub fn get_u128(&self) -> (bool, u128, bool) {
let len = self.words.len();
if len == 1 {
(self.sign_bit, self.words[0] as u128, true)
} else {
let val = self.words[0] as u128 + ((self.words[1] as u128) << 64);
(self.sign_bit, val, len == 2)
}
}
}
impl ToNapiValue for BigInt {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut();
let len = val.words.len();
check_status!(unsafe {
sys::napi_create_bigint_words(
env,
match val.sign_bit {
true => 1,
false => 0,
},
len,
val.words.as_ptr(),
&mut raw_value,
)
})?;
Ok(raw_value)
}
}
pub(crate) unsafe fn u128_with_sign_to_napi_value(
env: sys::napi_env,
val: u128,
sign_bit: i32,
) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut();
if cfg!(target_endian = "little") {
let words = &val as *const u128 as *const u64;
check_status!(unsafe {
sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value)
})?;
return Ok(raw_value);
}
let arr: [u64; 2] = [val as _, (val >> 64) as _];
let words = &arr as *const u64;
check_status!(unsafe { sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) })?;
Ok(raw_value)
}
impl ToNapiValue for i128 {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let sign_bit = i32::from(val <= 0);
let val = val.unsigned_abs();
u128_with_sign_to_napi_value(env, val, sign_bit)
}
}
impl ToNapiValue for u128 {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
u128_with_sign_to_napi_value(env, val, 0)
}
}
impl ToNapiValue for i64n {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut();
check_status!(unsafe { sys::napi_create_bigint_int64(env, val.0, &mut raw_value) })?;
Ok(raw_value)
}
}
impl ToNapiValue for u64 {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut();
check_status!(unsafe { sys::napi_create_bigint_uint64(env, val, &mut raw_value) })?;
Ok(raw_value)
}
}
impl ToNapiValue for usize {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut();
check_status!(unsafe { sys::napi_create_bigint_uint64(env, val as u64, &mut raw_value) })?;
Ok(raw_value)
}
}
impl ToNapiValue for isize {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut();
check_status!(unsafe { sys::napi_create_bigint_int64(env, val as i64, &mut raw_value) })?;
Ok(raw_value)
}
}
impl From<i64> for BigInt {
fn from(val: i64) -> Self {
BigInt {
sign_bit: val < 0,
words: vec![val.unsigned_abs()],
}
}
}
impl From<u64> for BigInt {
fn from(val: u64) -> Self {
BigInt {
sign_bit: false,
words: vec![val],
}
}
}
impl From<i128> for BigInt {
fn from(val: i128) -> Self {
let sign_bit = val < 0;
let val = val.unsigned_abs();
BigInt {
sign_bit,
words: vec![val as _, (val >> 64) as _],
}
}
}
impl From<u128> for BigInt {
fn from(val: u128) -> Self {
BigInt {
sign_bit: false,
words: vec![val as _, (val >> 64) as _],
}
}
}