Merge pull request #846 from napi-rs/bigint
feat(napi): BigInt codegen support
This commit is contained in:
commit
9a8484144c
18 changed files with 313 additions and 53 deletions
|
@ -241,9 +241,9 @@ yarn test
|
||||||
| Result<()> | Error | 1 | v8.0.0 |
|
| Result<()> | Error | 1 | v8.0.0 |
|
||||||
| T: Fn(...) -> Result<T> | Function | 1 | v8.0.0 |
|
| T: Fn(...) -> Result<T> | Function | 1 | v8.0.0 |
|
||||||
| Async/Future | Promise<T> | 4 | v10.6.0 | async |
|
| Async/Future | Promise<T> | 4 | v10.6.0 | async |
|
||||||
| Task | Promise<T> | 1 | v8.5.0 |
|
| AsyncTask | Promise<T> | 1 | v8.5.0 |
|
||||||
| (NOT YET) | global | 1 | v8.0.0 |
|
| (NOT YET) | global | 1 | v8.0.0 |
|
||||||
| (NOT YET) | Symbol | 1 | v8.0.0 |
|
| JsSymbol | Symbol | 1 | v8.0.0 |
|
||||||
| (NOT YET) | ArrayBuffer/TypedArray | 1 | v8.0.0 |
|
| (NOT YET) | ArrayBuffer/TypedArray | 1 | v8.0.0 |
|
||||||
| (NOT YET) | threadsafe function | 4 | v10.6.0 | napi4 |
|
| (NOT YET) | threadsafe function | 4 | v10.6.0 | napi4 |
|
||||||
| (NOT YET) | BigInt | 6 | v10.7.0 | napi6 |
|
| BigInt | BigInt | 6 | v10.7.0 | napi6 |
|
||||||
|
|
|
@ -40,10 +40,12 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||||
("u16", "number"),
|
("u16", "number"),
|
||||||
("u32", "number"),
|
("u32", "number"),
|
||||||
("u64", "BigInt"),
|
("u64", "BigInt"),
|
||||||
|
("i64n", "BigInt"),
|
||||||
("u128", "BigInt"),
|
("u128", "BigInt"),
|
||||||
("i128", "BigInt"),
|
("i128", "BigInt"),
|
||||||
("usize", "BigInt"),
|
("usize", "BigInt"),
|
||||||
("isize", "BigInt"),
|
("isize", "BigInt"),
|
||||||
|
("JsBigInt", "BigInt"),
|
||||||
("BigInt", "BigInt"),
|
("BigInt", "BigInt"),
|
||||||
("bool", "boolean"),
|
("bool", "boolean"),
|
||||||
("String", "string"),
|
("String", "string"),
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use crate::{check_status, sys, Error, JsUnknown, NapiRaw, NapiValue, Result, Status, ValueType};
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use crate::{check_status, sys, Error, JsUnknown, NapiRaw, NapiValue, Result, Status, ValueType};
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
|
mod bigint;
|
||||||
mod boolean;
|
mod boolean;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod either;
|
mod either;
|
||||||
|
@ -15,6 +18,8 @@ mod string;
|
||||||
mod task;
|
mod task;
|
||||||
|
|
||||||
pub use array::*;
|
pub use array::*;
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
|
pub use bigint::*;
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
pub use either::*;
|
pub use either::*;
|
||||||
pub use nil::*;
|
pub use nil::*;
|
||||||
|
|
211
crates/napi/src/bindgen_runtime/js_values/bigint.rs
Normal file
211
crates/napi/src/bindgen_runtime/js_values/bigint.rs
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/// We don't implement `FromNapiValue` for `i64` `u64` `i128` `u128` `isize` `usize` here
|
||||||
|
/// Because converting directly from `JsBigInt` to these values may result in a loss of precision and thus unintended behavior
|
||||||
|
/// ```rust
|
||||||
|
/// use napi::{bindgen_prelude::*, JsBigint};
|
||||||
|
///
|
||||||
|
/// #[napi]
|
||||||
|
/// fn bigint_add(mut a: Bigint, mut b: Bigint) -> u128 {
|
||||||
|
/// a.get_u128().1 + b.get_u128().1 // We have opportunity to check if the `u128` has lost precision
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use crate::{check_status, sys};
|
||||||
|
|
||||||
|
use super::{FromNapiValue, ToNapiValue, TypeName};
|
||||||
|
|
||||||
|
/// i64 is converted to `Number`
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct i64n(pub i64);
|
||||||
|
|
||||||
|
/// https://nodejs.org/api/n-api.html#napi_create_bigint_words
|
||||||
|
/// The resulting BigInt is calculated as: (–1)^sign_bit (words[0] × (2^64)^0 + words[1] × (2^64)^1 + …)
|
||||||
|
pub struct BigInt {
|
||||||
|
/// true for negative numbers
|
||||||
|
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 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!(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 as usize);
|
||||||
|
let mut sign_bit = 0;
|
||||||
|
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 as usize);
|
||||||
|
Ok(BigInt {
|
||||||
|
sign_bit: sign_bit == 1,
|
||||||
|
words,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BigInt {
|
||||||
|
/// (signed, value, lossless)
|
||||||
|
/// get the first word of the BigInt as `u64`
|
||||||
|
/// return true in the last element of tuple if the value is lossless
|
||||||
|
/// or the value is truncated
|
||||||
|
pub fn get_u64(&self) -> (bool, u64, bool) {
|
||||||
|
(
|
||||||
|
self.sign_bit,
|
||||||
|
self.words[0],
|
||||||
|
self.sign_bit && self.words.len() == 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (value, lossless)
|
||||||
|
/// get the first word of the BigInt as `i64`
|
||||||
|
/// return true if the value is lossless
|
||||||
|
/// or the value is truncated
|
||||||
|
pub fn get_i64(&self) -> (i64, bool) {
|
||||||
|
let val = self.words[0] as i64;
|
||||||
|
(val, val as u64 == self.words[0] && self.words.len() == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (value, lossless)
|
||||||
|
/// get the first two words of the BigInt as `i128`
|
||||||
|
/// return true if the value is lossless
|
||||||
|
/// or the value is truncated
|
||||||
|
pub fn get_i128(&self) -> (i128, bool) {
|
||||||
|
let len = self.words.len();
|
||||||
|
if len == 1 {
|
||||||
|
(self.words[0] as i128, false)
|
||||||
|
} else {
|
||||||
|
let i128_words: [i64; 2] = [self.words[0] as _, self.words[1] as _];
|
||||||
|
let mut val = unsafe { ptr::read(i128_words.as_ptr() as *const i128) };
|
||||||
|
if self.sign_bit {
|
||||||
|
val = -val;
|
||||||
|
}
|
||||||
|
(val, len > 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (signed, value, lossless)
|
||||||
|
/// get the first two words of the BigInt as `u128`
|
||||||
|
/// return true if the value is lossless
|
||||||
|
/// or the value is truncated
|
||||||
|
pub fn get_u128(&self) -> (bool, u128, bool) {
|
||||||
|
let len = self.words.len();
|
||||||
|
if len == 1 {
|
||||||
|
(self.sign_bit, self.words[0] as u128, false)
|
||||||
|
} else {
|
||||||
|
let u128_words: [u64; 2] = [self.words[0], self.words[1]];
|
||||||
|
let val = unsafe { ptr::read(u128_words.as_ptr() as *const u128) };
|
||||||
|
(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!(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToNapiValue for i128 {
|
||||||
|
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
|
||||||
|
let mut raw_value = ptr::null_mut();
|
||||||
|
let sign_bit = if val > 0 { 0 } else { 1 };
|
||||||
|
let words = &val as *const i128 as *const u64;
|
||||||
|
check_status!(sys::napi_create_bigint_words(
|
||||||
|
env,
|
||||||
|
sign_bit,
|
||||||
|
2,
|
||||||
|
words,
|
||||||
|
&mut raw_value
|
||||||
|
))?;
|
||||||
|
Ok(raw_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToNapiValue for u128 {
|
||||||
|
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
|
||||||
|
let mut raw_value = ptr::null_mut();
|
||||||
|
let words = &val as *const u128 as *const u64;
|
||||||
|
check_status!(sys::napi_create_bigint_words(
|
||||||
|
env,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
words,
|
||||||
|
&mut raw_value
|
||||||
|
))?;
|
||||||
|
Ok(raw_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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!(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!(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!(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!(sys::napi_create_bigint_int64(
|
||||||
|
env,
|
||||||
|
val as i64,
|
||||||
|
&mut raw_value
|
||||||
|
))?;
|
||||||
|
Ok(raw_value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ impl FromNapiValue for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
ValueType::Bigint => todo!(),
|
ValueType::BigInt => todo!(),
|
||||||
_ => Value::Null,
|
_ => Value::Null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -100,43 +100,43 @@ impl Env {
|
||||||
|
|
||||||
/// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
|
/// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigint> {
|
pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigInt> {
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
check_status!(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
|
check_status!(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
|
||||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
|
Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigint> {
|
pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigInt> {
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
check_status!(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
|
check_status!(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
|
||||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
|
Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigint> {
|
pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigInt> {
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
let sign_bit = if value > 0 { 0 } else { 1 };
|
let sign_bit = if value > 0 { 0 } else { 1 };
|
||||||
let words = &value as *const i128 as *const u64;
|
let words = &value as *const i128 as *const u64;
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value)
|
sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value)
|
||||||
})?;
|
})?;
|
||||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
|
Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigint> {
|
pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigInt> {
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
let words = &value as *const u128 as *const u64;
|
let words = &value as *const u128 as *const u64;
|
||||||
check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
|
check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
|
||||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
|
Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
|
/// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
|
||||||
///
|
///
|
||||||
/// The resulting BigInt will be negative when sign_bit is true.
|
/// The resulting BigInt will be negative when sign_bit is true.
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigint> {
|
pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigInt> {
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
let len = words.len();
|
let len = words.len();
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
|
@ -151,7 +151,7 @@ impl Env {
|
||||||
&mut raw_value,
|
&mut raw_value,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, len))
|
Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, len))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_string(&self, s: &str) -> Result<JsString> {
|
pub fn create_string(&self, s: &str) -> Result<JsString> {
|
||||||
|
|
|
@ -5,22 +5,22 @@ use super::*;
|
||||||
use crate::{bindgen_runtime::TypeName, check_status, sys, Result};
|
use crate::{bindgen_runtime::TypeName, check_status, sys, Result};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsBigint {
|
pub struct JsBigInt {
|
||||||
pub(crate) raw: Value,
|
pub(crate) raw: Value,
|
||||||
pub word_count: usize,
|
pub word_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeName for JsBigint {
|
impl TypeName for JsBigInt {
|
||||||
fn type_name() -> &'static str {
|
fn type_name() -> &'static str {
|
||||||
"BigInt"
|
"BigInt"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value_type() -> ValueType {
|
fn value_type() -> ValueType {
|
||||||
ValueType::Bigint
|
ValueType::BigInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsBigint {
|
impl JsBigInt {
|
||||||
pub(crate) fn from_raw_unchecked(
|
pub(crate) fn from_raw_unchecked(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
value: sys::napi_value,
|
value: sys::napi_value,
|
||||||
|
@ -76,7 +76,6 @@ impl JsBigint {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi5")]
|
|
||||||
pub fn is_date(&self) -> Result<bool> {
|
pub fn is_date(&self) -> Result<bool> {
|
||||||
let mut is_date = true;
|
let mut is_date = true;
|
||||||
check_status!(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?;
|
check_status!(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?;
|
||||||
|
@ -122,19 +121,19 @@ impl JsBigint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NapiRaw for JsBigint {
|
impl NapiRaw for JsBigInt {
|
||||||
unsafe fn raw(&self) -> sys::napi_value {
|
unsafe fn raw(&self) -> sys::napi_value {
|
||||||
self.raw.value
|
self.raw.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'env> NapiRaw for &'env JsBigint {
|
impl<'env> NapiRaw for &'env JsBigInt {
|
||||||
unsafe fn raw(&self) -> sys::napi_value {
|
unsafe fn raw(&self) -> sys::napi_value {
|
||||||
self.raw.value
|
self.raw.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NapiValue for JsBigint {
|
impl NapiValue for JsBigInt {
|
||||||
unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
|
unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
|
||||||
let mut word_count = 0usize;
|
let mut word_count = 0usize;
|
||||||
check_status!(sys::napi_get_value_bigint_words(
|
check_status!(sys::napi_get_value_bigint_words(
|
||||||
|
@ -144,11 +143,11 @@ impl NapiValue for JsBigint {
|
||||||
&mut word_count,
|
&mut word_count,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
))?;
|
))?;
|
||||||
Ok(JsBigint {
|
Ok(JsBigInt {
|
||||||
raw: Value {
|
raw: Value {
|
||||||
env,
|
env,
|
||||||
value,
|
value,
|
||||||
value_type: ValueType::Bigint,
|
value_type: ValueType::BigInt,
|
||||||
},
|
},
|
||||||
word_count,
|
word_count,
|
||||||
})
|
})
|
||||||
|
@ -167,11 +166,11 @@ impl NapiValue for JsBigint {
|
||||||
Status::from(status) == Status::Ok,
|
Status::from(status) == Status::Ok,
|
||||||
"napi_get_value_bigint_words failed"
|
"napi_get_value_bigint_words failed"
|
||||||
);
|
);
|
||||||
JsBigint {
|
JsBigInt {
|
||||||
raw: Value {
|
raw: Value {
|
||||||
env,
|
env,
|
||||||
value,
|
value,
|
||||||
value_type: ValueType::Bigint,
|
value_type: ValueType::BigInt,
|
||||||
},
|
},
|
||||||
word_count,
|
word_count,
|
||||||
}
|
}
|
||||||
|
@ -179,24 +178,24 @@ impl NapiValue for JsBigint {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The BigInt will be converted losslessly when the value is over what an int64 could hold.
|
/// The BigInt will be converted losslessly when the value is over what an int64 could hold.
|
||||||
impl TryFrom<JsBigint> for i64 {
|
impl TryFrom<JsBigInt> for i64 {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(value: JsBigint) -> Result<i64> {
|
fn try_from(value: JsBigInt) -> Result<i64> {
|
||||||
value.get_i64().map(|(v, _)| v)
|
value.get_i64().map(|(v, _)| v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The BigInt will be converted losslessly when the value is over what an uint64 could hold.
|
/// The BigInt will be converted losslessly when the value is over what an uint64 could hold.
|
||||||
impl TryFrom<JsBigint> for u64 {
|
impl TryFrom<JsBigInt> for u64 {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(value: JsBigint) -> Result<u64> {
|
fn try_from(value: JsBigInt) -> Result<u64> {
|
||||||
value.get_u64().map(|(v, _)| v)
|
value.get_u64().map(|(v, _)| v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsBigint {
|
impl JsBigInt {
|
||||||
/// https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words
|
/// https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words
|
||||||
pub fn get_words(&mut self) -> Result<(bool, Vec<u64>)> {
|
pub fn get_words(&mut self) -> Result<(bool, Vec<u64>)> {
|
||||||
let mut words: Vec<u64> = Vec::with_capacity(self.word_count as usize);
|
let mut words: Vec<u64> = Vec::with_capacity(self.word_count as usize);
|
||||||
|
@ -221,21 +220,21 @@ impl JsBigint {
|
||||||
|
|
||||||
pub fn get_u64(&self) -> Result<(u64, bool)> {
|
pub fn get_u64(&self) -> Result<(u64, bool)> {
|
||||||
let mut val: u64 = 0;
|
let mut val: u64 = 0;
|
||||||
let mut loss = false;
|
let mut lossless = false;
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
sys::napi_get_value_bigint_uint64(self.raw.env, self.raw.value, &mut val, &mut loss)
|
sys::napi_get_value_bigint_uint64(self.raw.env, self.raw.value, &mut val, &mut lossless)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok((val, loss))
|
Ok((val, lossless))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i64(&self) -> Result<(i64, bool)> {
|
pub fn get_i64(&self) -> Result<(i64, bool)> {
|
||||||
let mut val: i64 = 0;
|
let mut val: i64 = 0;
|
||||||
let mut loss: bool = false;
|
let mut lossless: bool = false;
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
sys::napi_get_value_bigint_int64(self.raw.env, self.raw.value, &mut val, &mut loss)
|
sys::napi_get_value_bigint_int64(self.raw.env, self.raw.value, &mut val, &mut lossless)
|
||||||
})?;
|
})?;
|
||||||
Ok((val, loss))
|
Ok((val, lossless))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i128(&mut self) -> Result<(i128, bool)> {
|
pub fn get_i128(&mut self) -> Result<(i128, bool)> {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use serde::de::Visitor;
|
||||||
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess};
|
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess};
|
||||||
|
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
use crate::JsBigint;
|
use crate::JsBigInt;
|
||||||
use crate::{type_of, NapiValue, Value, ValueType};
|
use crate::{type_of, NapiValue, Value, ValueType};
|
||||||
use crate::{
|
use crate::{
|
||||||
Error, JsBoolean, JsBufferValue, JsNumber, JsObject, JsString, JsUnknown, Result, Status,
|
Error, JsBoolean, JsBufferValue, JsNumber, JsObject, JsString, JsUnknown, Result, Status,
|
||||||
|
@ -54,8 +54,8 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
ValueType::Bigint => {
|
ValueType::BigInt => {
|
||||||
let mut js_bigint = unsafe { JsBigint::from_raw(self.0.env, self.0.value)? };
|
let mut js_bigint = unsafe { JsBigInt::from_raw(self.0.env, self.0.value)? };
|
||||||
let (signed, v, _loss) = js_bigint.get_u128()?;
|
let (signed, v, _loss) = js_bigint.get_u128()?;
|
||||||
if signed {
|
if signed {
|
||||||
visitor.visit_i128(-(v as i128))
|
visitor.visit_i128(-(v as i128))
|
||||||
|
|
|
@ -33,7 +33,7 @@ mod value_ref;
|
||||||
|
|
||||||
pub use arraybuffer::*;
|
pub use arraybuffer::*;
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
pub use bigint::JsBigint;
|
pub use bigint::JsBigInt;
|
||||||
pub use boolean::JsBoolean;
|
pub use boolean::JsBoolean;
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub enum ValueType {
|
||||||
Function = 7,
|
Function = 7,
|
||||||
External = 8,
|
External = 8,
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
Bigint = 9,
|
BigInt = 9,
|
||||||
Unknown = 1024,
|
Unknown = 1024,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ impl From<i32> for ValueType {
|
||||||
fn from(value: i32) -> ValueType {
|
fn from(value: i32) -> ValueType {
|
||||||
match value {
|
match value {
|
||||||
#[cfg(feature = "napi6")]
|
#[cfg(feature = "napi6")]
|
||||||
sys::ValueType::napi_bigint => ValueType::Bigint,
|
sys::ValueType::napi_bigint => ValueType::BigInt,
|
||||||
sys::ValueType::napi_boolean => ValueType::Boolean,
|
sys::ValueType::napi_boolean => ValueType::Boolean,
|
||||||
sys::ValueType::napi_external => ValueType::External,
|
sys::ValueType::napi_external => ValueType::External,
|
||||||
sys::ValueType::napi_function => ValueType::Function,
|
sys::ValueType::napi_function => ValueType::Function,
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
use napi::{CallContext, JsBigint, JsNumber, JsObject, Result};
|
use napi::{CallContext, JsBigInt, JsNumber, JsObject, Result};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
#[js_function]
|
#[js_function]
|
||||||
pub fn test_create_bigint_from_i64(ctx: CallContext) -> Result<JsBigint> {
|
pub fn test_create_bigint_from_i64(ctx: CallContext) -> Result<JsBigInt> {
|
||||||
ctx.env.create_bigint_from_i64(i64::max_value())
|
ctx.env.create_bigint_from_i64(i64::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function]
|
#[js_function]
|
||||||
pub fn test_create_bigint_from_u64(ctx: CallContext) -> Result<JsBigint> {
|
pub fn test_create_bigint_from_u64(ctx: CallContext) -> Result<JsBigInt> {
|
||||||
ctx.env.create_bigint_from_u64(u64::max_value())
|
ctx.env.create_bigint_from_u64(u64::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function]
|
#[js_function]
|
||||||
pub fn test_create_bigint_from_i128(ctx: CallContext) -> Result<JsBigint> {
|
pub fn test_create_bigint_from_i128(ctx: CallContext) -> Result<JsBigInt> {
|
||||||
ctx.env.create_bigint_from_i128(i128::max_value())
|
ctx.env.create_bigint_from_i128(i128::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function]
|
#[js_function]
|
||||||
pub fn test_create_bigint_from_u128(ctx: CallContext) -> Result<JsBigint> {
|
pub fn test_create_bigint_from_u128(ctx: CallContext) -> Result<JsBigInt> {
|
||||||
ctx.env.create_bigint_from_u128(u128::max_value())
|
ctx.env.create_bigint_from_u128(u128::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function]
|
#[js_function]
|
||||||
pub fn test_create_bigint_from_words(ctx: CallContext) -> Result<JsBigint> {
|
pub fn test_create_bigint_from_words(ctx: CallContext) -> Result<JsBigInt> {
|
||||||
ctx
|
ctx
|
||||||
.env
|
.env
|
||||||
.create_bigint_from_words(true, vec![u64::max_value(), u64::max_value()])
|
.create_bigint_from_words(true, vec![u64::max_value(), u64::max_value()])
|
||||||
|
@ -30,14 +30,14 @@ pub fn test_create_bigint_from_words(ctx: CallContext) -> Result<JsBigint> {
|
||||||
|
|
||||||
#[js_function(1)]
|
#[js_function(1)]
|
||||||
pub fn test_get_bigint_i64(ctx: CallContext) -> Result<JsNumber> {
|
pub fn test_get_bigint_i64(ctx: CallContext) -> Result<JsNumber> {
|
||||||
let js_bigint = ctx.get::<JsBigint>(0)?;
|
let js_bigint = ctx.get::<JsBigInt>(0)?;
|
||||||
let val = i64::try_from(js_bigint)?;
|
let val = i64::try_from(js_bigint)?;
|
||||||
ctx.env.create_int32(val as i32)
|
ctx.env.create_int32(val as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function(1)]
|
#[js_function(1)]
|
||||||
pub fn test_get_bigint_u64(ctx: CallContext) -> Result<JsNumber> {
|
pub fn test_get_bigint_u64(ctx: CallContext) -> Result<JsNumber> {
|
||||||
let js_bigint = ctx.get::<JsBigint>(0)?;
|
let js_bigint = ctx.get::<JsBigInt>(0)?;
|
||||||
let val = u64::try_from(js_bigint)?;
|
let val = u64::try_from(js_bigint)?;
|
||||||
ctx.env.create_int32(val as i32)
|
ctx.env.create_int32(val as i32)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ Generated by [AVA](https://avajs.dev).
|
||||||
export function sumNums(nums: Array<number>): number␊
|
export function sumNums(nums: Array<number>): number␊
|
||||||
export function readFileAsync(path: string): Promise<Buffer>␊
|
export function readFileAsync(path: string): Promise<Buffer>␊
|
||||||
export function asyncMultiTwo(arg: number): Promise<number>␊
|
export function asyncMultiTwo(arg: number): Promise<number>␊
|
||||||
|
export function bigintAdd(a: BigInt, b: BigInt): BigInt␊
|
||||||
|
export function createBigInt(): BigInt␊
|
||||||
|
export function createBigIntI64(): BigInt␊
|
||||||
export function getCwd(callback: (arg0: string) => void): void␊
|
export function getCwd(callback: (arg0: string) => void): void␊
|
||||||
export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void␊
|
export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void␊
|
||||||
export function eitherStringOrNumber(input: string | number): number␊
|
export function eitherStringOrNumber(input: string | number): number␊
|
||||||
|
|
Binary file not shown.
|
@ -35,6 +35,9 @@ import {
|
||||||
withoutAbortController,
|
withoutAbortController,
|
||||||
withAbortController,
|
withAbortController,
|
||||||
asyncMultiTwo,
|
asyncMultiTwo,
|
||||||
|
bigintAdd,
|
||||||
|
createBigInt,
|
||||||
|
createBigIntI64,
|
||||||
} from '../'
|
} from '../'
|
||||||
|
|
||||||
test('number', (t) => {
|
test('number', (t) => {
|
||||||
|
@ -217,3 +220,17 @@ MaybeTest('abort resolved task', async (t) => {
|
||||||
await withAbortController(1, 2, ctrl.signal).then(() => ctrl.abort())
|
await withAbortController(1, 2, ctrl.signal).then(() => ctrl.abort())
|
||||||
t.pass('should not throw')
|
t.pass('should not throw')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const BigIntTest = typeof BigInt !== 'undefined' ? test : test.skip
|
||||||
|
|
||||||
|
BigIntTest('BigInt add', (t) => {
|
||||||
|
t.is(bigintAdd(BigInt(1), BigInt(2)), BigInt(3))
|
||||||
|
})
|
||||||
|
|
||||||
|
BigIntTest('create BigInt', (t) => {
|
||||||
|
t.is(createBigInt(), BigInt('-3689348814741910323300'))
|
||||||
|
})
|
||||||
|
|
||||||
|
BigIntTest('create BigInt i64', (t) => {
|
||||||
|
t.is(createBigIntI64(), BigInt(100))
|
||||||
|
})
|
||||||
|
|
3
examples/napi/index.d.ts
vendored
3
examples/napi/index.d.ts
vendored
|
@ -3,6 +3,9 @@ export function getNums(): Array<number>
|
||||||
export function sumNums(nums: Array<number>): number
|
export function sumNums(nums: Array<number>): number
|
||||||
export function readFileAsync(path: string): Promise<Buffer>
|
export function readFileAsync(path: string): Promise<Buffer>
|
||||||
export function asyncMultiTwo(arg: number): Promise<number>
|
export function asyncMultiTwo(arg: number): Promise<number>
|
||||||
|
export function bigintAdd(a: BigInt, b: BigInt): BigInt
|
||||||
|
export function createBigInt(): BigInt
|
||||||
|
export function createBigIntI64(): BigInt
|
||||||
export function getCwd(callback: (arg0: string) => void): void
|
export function getCwd(callback: (arg0: string) => void): void
|
||||||
export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void
|
export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void
|
||||||
export function eitherStringOrNumber(input: string | number): number
|
export function eitherStringOrNumber(input: string | number): number
|
||||||
|
|
19
examples/napi/src/bigint.rs
Normal file
19
examples/napi/src/bigint.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use napi::bindgen_prelude::*;
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
fn bigint_add(a: BigInt, b: BigInt) -> u128 {
|
||||||
|
a.get_u128().1 + b.get_u128().1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
fn create_big_int() -> BigInt {
|
||||||
|
BigInt {
|
||||||
|
words: vec![100u64, 200u64],
|
||||||
|
sign_bit: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
fn create_big_int_i64() -> i64n {
|
||||||
|
i64n(100)
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ extern crate serde_derive;
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
mod r#async;
|
mod r#async;
|
||||||
|
mod bigint;
|
||||||
mod callback;
|
mod callback;
|
||||||
mod class;
|
mod class;
|
||||||
mod class_factory;
|
mod class_factory;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "__test__",
|
"rootDir": "__test__",
|
||||||
"target": "ES2015"
|
"target": "ES2018"
|
||||||
},
|
},
|
||||||
"exclude": ["dist", "index.d.ts"]
|
"exclude": ["dist", "index.d.ts"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue