feat(napi): add BigInt related apis
This commit is contained in:
parent
468c98dea1
commit
14dd8b83e6
7 changed files with 229 additions and 4 deletions
|
@ -92,6 +92,45 @@ impl Env {
|
|||
Ok(JsNumber::from_raw_unchecked(self.0, raw_value))
|
||||
}
|
||||
|
||||
#[cfg(napi6)]
|
||||
#[inline]
|
||||
/// https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64
|
||||
pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigint> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
check_status(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
|
||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value))
|
||||
}
|
||||
|
||||
#[cfg(napi6)]
|
||||
#[inline]
|
||||
/// https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words
|
||||
pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigint> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
check_status(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
|
||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value))
|
||||
}
|
||||
|
||||
#[cfg(napi6)]
|
||||
#[inline]
|
||||
/// https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words
|
||||
/// The resulting BigInt will be negative when sign_bit is true.
|
||||
pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigint> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_create_bigint_words(
|
||||
self.0,
|
||||
match sign_bit {
|
||||
true => 1,
|
||||
false => 0,
|
||||
},
|
||||
words.len() as u64,
|
||||
words.as_ptr(),
|
||||
&mut raw_value,
|
||||
)
|
||||
})?;
|
||||
Ok(JsBigint::from_raw_unchecked(self.0, raw_value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn create_string(&self, s: &str) -> Result<JsString> {
|
||||
self.create_string_from_chars(s.as_ptr() as *const _, s.len() as u64)
|
||||
|
|
85
napi/src/js_values/bigint.rs
Normal file
85
napi/src/js_values/bigint.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::ptr;
|
||||
|
||||
use super::{Error, Value};
|
||||
use crate::error::check_status;
|
||||
use crate::{sys, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JsBigint(pub(crate) Value);
|
||||
|
||||
/// The BigInt will be converted losslessly when the value is over what an int64 could hold.
|
||||
impl TryFrom<JsBigint> for i64 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: JsBigint) -> Result<i64> {
|
||||
value.get_i64().map(|(v, _)| v)
|
||||
}
|
||||
}
|
||||
|
||||
/// The BigInt will be converted losslessly when the value is over what an uint64 could hold.
|
||||
impl TryFrom<JsBigint> for u64 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: JsBigint) -> Result<u64> {
|
||||
value.get_u64().map(|(v, _)| v)
|
||||
}
|
||||
}
|
||||
|
||||
impl JsBigint {
|
||||
/// https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words
|
||||
pub fn get_words(&self, sign_bit: bool) -> Result<Vec<u64>> {
|
||||
let mut word_count: u64 = 0;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_bigint_words(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
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 = match sign_bit {
|
||||
true => 1,
|
||||
false => 0,
|
||||
};
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_bigint_words(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
&mut sign_bit,
|
||||
&mut word_count,
|
||||
words.as_mut_ptr(),
|
||||
)
|
||||
})?;
|
||||
|
||||
unsafe {
|
||||
words.set_len(word_count as usize);
|
||||
};
|
||||
|
||||
Ok(words)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_u64(&self) -> Result<(u64, bool)> {
|
||||
let mut val: u64 = 0;
|
||||
let mut loss = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_bigint_uint64(self.0.env, self.0.value, &mut val, &mut loss)
|
||||
})?;
|
||||
|
||||
Ok((val, loss))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_i64(&self) -> Result<(i64, bool)> {
|
||||
let mut val: i64 = 0;
|
||||
let mut loss: bool = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_bigint_int64(self.0.env, self.0.value, &mut val, &mut loss)
|
||||
})?;
|
||||
Ok((val, loss))
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ use crate::error::check_status;
|
|||
use crate::{sys, Error, Result, Status};
|
||||
|
||||
mod arraybuffer;
|
||||
#[cfg(napi6)]
|
||||
mod bigint;
|
||||
mod boolean;
|
||||
mod buffer;
|
||||
mod class_property;
|
||||
|
@ -20,6 +22,8 @@ mod value_ref;
|
|||
mod value_type;
|
||||
|
||||
pub use arraybuffer::JsArrayBuffer;
|
||||
#[cfg(napi6)]
|
||||
pub use bigint::JsBigint;
|
||||
pub use boolean::JsBoolean;
|
||||
pub use buffer::JsBuffer;
|
||||
pub use class_property::Property;
|
||||
|
@ -41,10 +45,6 @@ pub struct JsUnknown(pub(crate) Value);
|
|||
#[derive(Debug)]
|
||||
pub struct JsNull(pub(crate) Value);
|
||||
|
||||
#[cfg(napi6)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsBigint(pub(crate) Value);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JsSymbol(pub(crate) Value);
|
||||
|
||||
|
|
30
test_module/__test__/napi6/bigint.spec.js
Normal file
30
test_module/__test__/napi6/bigint.spec.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
const test = require('ava')
|
||||
|
||||
const napiVersion = require('../napi-version')
|
||||
const bindings = require('../../index.node')
|
||||
|
||||
test('should create bigints', (t) => {
|
||||
if (napiVersion >= 6) {
|
||||
t.is(bindings.testCreateBigintFromI64(), BigInt('9223372036854775807'))
|
||||
t.is(bindings.testCreateBigintFromU64(), BigInt('18446744073709551615'))
|
||||
t.is(
|
||||
bindings.testCreateBigintFromWords(),
|
||||
BigInt('-340282366920938463463374607431768211455'),
|
||||
)
|
||||
} else {
|
||||
t.is(bindings.testCreateBigintFromI64, undefined)
|
||||
}
|
||||
})
|
||||
|
||||
test('should get integers from bigints', (t) => {
|
||||
if (napiVersion >= 6) {
|
||||
t.is(bindings.testGetBigintI64(BigInt('-123')), -123)
|
||||
t.is(bindings.testGetBigintU64(BigInt(123)), 123)
|
||||
t.deepEqual(bindings.testGetBigintWords(), [
|
||||
BigInt('9223372036854775807'),
|
||||
BigInt('9223372036854775807'),
|
||||
])
|
||||
} else {
|
||||
t.is(bindings.testGetBigintI64, undefined)
|
||||
}
|
||||
})
|
|
@ -13,6 +13,8 @@ mod napi4;
|
|||
mod napi5;
|
||||
#[cfg(napi4)]
|
||||
mod tokio_rt;
|
||||
#[cfg(napi6)]
|
||||
mod napi6;
|
||||
|
||||
mod buffer;
|
||||
mod class;
|
||||
|
@ -39,6 +41,15 @@ use symbol::{create_named_symbol, create_symbol_from_js_string, create_unnamed_s
|
|||
use task::test_spawn_thread;
|
||||
#[cfg(napi4)]
|
||||
use tokio_rt::{error_from_tokio_future, test_execute_tokio_readfile};
|
||||
#[cfg(napi6)]
|
||||
use napi6::bigint::{
|
||||
test_create_bigint_from_i64,
|
||||
test_create_bigint_from_u64,
|
||||
test_create_bigint_from_words,
|
||||
test_get_bigint_i64,
|
||||
test_get_bigint_u64,
|
||||
test_get_bigint_words,
|
||||
};
|
||||
|
||||
register_module!(test_module, init);
|
||||
|
||||
|
@ -74,6 +85,18 @@ fn init(module: &mut Module) -> Result<()> {
|
|||
module.create_named_method("uvReadFile", uv_read_file)?;
|
||||
#[cfg(napi5)]
|
||||
module.create_named_method("testObjectIsDate", test_object_is_date)?;
|
||||
#[cfg(napi6)]
|
||||
module.create_named_method("testCreateBigintFromI64", test_create_bigint_from_i64)?;
|
||||
#[cfg(napi6)]
|
||||
module.create_named_method("testCreateBigintFromU64", test_create_bigint_from_u64)?;
|
||||
#[cfg(napi6)]
|
||||
module.create_named_method("testCreateBigintFromWords", test_create_bigint_from_words)?;
|
||||
#[cfg(napi6)]
|
||||
module.create_named_method("testGetBigintI64", test_get_bigint_i64)?;
|
||||
#[cfg(napi6)]
|
||||
module.create_named_method("testGetBigintU64", test_get_bigint_u64)?;
|
||||
#[cfg(napi6)]
|
||||
module.create_named_method("testGetBigintWords", test_get_bigint_words)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
47
test_module/src/napi6/bigint.rs
Normal file
47
test_module/src/napi6/bigint.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use std::convert::TryFrom;
|
||||
use napi::{CallContext, JsBigint, Result, JsNumber, JsObject};
|
||||
|
||||
#[js_function(0)]
|
||||
pub fn test_create_bigint_from_i64(ctx: CallContext) -> Result<JsBigint> {
|
||||
ctx.env.create_bigint_from_i64(i64::max_value())
|
||||
}
|
||||
|
||||
#[js_function(0)]
|
||||
pub fn test_create_bigint_from_u64(ctx: CallContext) -> Result<JsBigint> {
|
||||
ctx.env.create_bigint_from_u64(u64::max_value())
|
||||
}
|
||||
|
||||
#[js_function(0)]
|
||||
pub fn test_create_bigint_from_words(ctx: CallContext) -> Result<JsBigint> {
|
||||
ctx.env.create_bigint_from_words(true, vec![u64::max_value(), u64::max_value()])
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
pub fn test_get_bigint_i64(ctx: CallContext) -> Result<JsNumber> {
|
||||
let js_bigint = ctx.get::<JsBigint>(0)?;
|
||||
let val = i64::try_from(js_bigint)?;
|
||||
ctx.env.create_int32(val as i32)
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
pub fn test_get_bigint_u64(ctx: CallContext) -> Result<JsNumber> {
|
||||
let js_bigint = ctx.get::<JsBigint>(0)?;
|
||||
let val = u64::try_from(js_bigint)?;
|
||||
ctx.env.create_int32(val as i32)
|
||||
}
|
||||
|
||||
#[js_function(0)]
|
||||
pub fn test_get_bigint_words(ctx: CallContext) -> Result<JsObject> {
|
||||
let js_bigint = ctx.env.create_bigint_from_words(true, vec![i64::max_value() as u64, i64::max_value() as u64])?;
|
||||
let mut js_arr = ctx.env.create_array_with_length(2)?;
|
||||
let words = js_bigint.get_words(true)?;
|
||||
js_arr.set_number_indexed_property(
|
||||
ctx.env.create_int64(0)?,
|
||||
ctx.env.create_bigint_from_u64(words[0])?
|
||||
)?;
|
||||
js_arr.set_number_indexed_property(
|
||||
ctx.env.create_int64(1)?,
|
||||
ctx.env.create_bigint_from_u64(words[1])?
|
||||
)?;
|
||||
Ok(js_arr)
|
||||
}
|
1
test_module/src/napi6/mod.rs
Normal file
1
test_module/src/napi6/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod bigint;
|
Loading…
Reference in a new issue