diff --git a/crates/napi/src/bindgen_runtime/js_values/bigint.rs b/crates/napi/src/bindgen_runtime/js_values/bigint.rs index 4daca7da..0d031649 100644 --- a/crates/napi/src/bindgen_runtime/js_values/bigint.rs +++ b/crates/napi/src/bindgen_runtime/js_values/bigint.rs @@ -169,15 +169,19 @@ pub(crate) unsafe fn u128_with_sign_to_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) - })?; + check_status!( + unsafe { sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) }, + "Failed to create BigInt from u128" + )?; 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) })?; + check_status!( + unsafe { sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) }, + "Failed to create BigInt from u128" + )?; Ok(raw_value) } @@ -242,7 +246,10 @@ impl ToNapiValue for &mut i64n { impl ToNapiValue for u64 { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result { let mut raw_value = ptr::null_mut(); - check_status!(unsafe { sys::napi_create_bigint_uint64(env, val, &mut raw_value) })?; + check_status!( + unsafe { sys::napi_create_bigint_uint64(env, val, &mut raw_value) }, + "Failed to create BigInt from u64" + )?; Ok(raw_value) } } diff --git a/crates/napi/src/bindgen_runtime/js_values/serde.rs b/crates/napi/src/bindgen_runtime/js_values/serde.rs index d36e8e97..82e8456a 100644 --- a/crates/napi/src/bindgen_runtime/js_values/serde.rs +++ b/crates/napi/src/bindgen_runtime/js_values/serde.rs @@ -1,4 +1,5 @@ use std::marker::PhantomData; +use std::ptr; use serde_json::{Map, Number, Value}; @@ -51,7 +52,25 @@ impl FromNapiValue for Value { } } #[cfg(feature = "napi6")] - ValueType::BigInt => todo!(), + ValueType::BigInt => { + let n = unsafe { BigInt::from_napi_value(env, napi_val)? }; + // negative + if n.sign_bit { + let (v, lossless) = n.get_i64(); + if lossless { + Value::Number(v.into()) + } else { + Value::String(to_string(env, napi_val)?) + } + } else { + let (_, v, lossless) = n.get_u64(); + if lossless { + Value::Number(v.into()) + } else { + Value::String(to_string(env, napi_val)?) + } + } + } ValueType::Null => Value::Null, ValueType::Function => { return Err(Error::new( @@ -89,6 +108,13 @@ impl FromNapiValue for Value { } } +fn to_string(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let mut string = ptr::null_mut(); + check_status!(unsafe { sys::napi_coerce_to_string(env, napi_val, &mut string) })?; + let s = unsafe { String::from_napi_value(env, string) }?; + Ok(s) +} + impl ToNapiValue for &Map { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { let mut obj = Object::new(&Env::from(env))?; diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.md b/examples/napi/__tests__/__snapshots__/values.spec.ts.md index f600d17e..f9e50d8a 100644 --- a/examples/napi/__tests__/__snapshots__/values.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/values.spec.ts.md @@ -572,6 +572,8 @@ Generated by [AVA](https://avajs.dev). ␊ export declare function generateFunctionAndCallIt(): FunctionData␊ ␊ + export declare function getBigintJsonValue(value: bigint): void␊ + ␊ export declare function getBtreeMapping(): Record␊ ␊ export declare function getBuffer(): Buffer␊ diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap index 50d7f1ad..68de0be9 100644 Binary files a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap and b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap differ diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index fd7ab7ed..4198666a 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -137,6 +137,7 @@ import { testSerdeRoundtrip, testSerdeBigNumberPrecision, testSerdeBufferBytes, + getBigintJsonValue, createObjWithProperty, receiveObjectOnlyFromJs, dateToNumber, @@ -883,6 +884,14 @@ test('serde-buffer-bytes', (t) => { t.is(testSerdeBufferBytes({ code: new ArrayBuffer(0) }), 0n) }) +test('get bigint json value', (t) => { + t.notThrows(() => { + getBigintJsonValue(-1n) + getBigintJsonValue(1n) + getBigintJsonValue(18446744073709551620n) + }) +}) + test('buffer', (t) => { let buf = getBuffer() t.is(buf.toString('utf-8'), 'Hello world') diff --git a/examples/napi/example.wasi-browser.js b/examples/napi/example.wasi-browser.js index 2e9960f2..e83ca1ad 100644 --- a/examples/napi/example.wasi-browser.js +++ b/examples/napi/example.wasi-browser.js @@ -210,6 +210,7 @@ export const f64ArrayToArray = __napiModule.exports.f64ArrayToArray export const fibonacci = __napiModule.exports.fibonacci export const fnReceivedAliased = __napiModule.exports.fnReceivedAliased export const generateFunctionAndCallIt = __napiModule.exports.generateFunctionAndCallIt +export const getBigintJsonValue = __napiModule.exports.getBigintJsonValue export const getBtreeMapping = __napiModule.exports.getBtreeMapping export const getBuffer = __napiModule.exports.getBuffer export const getBufferSlice = __napiModule.exports.getBufferSlice diff --git a/examples/napi/example.wasi.cjs b/examples/napi/example.wasi.cjs index c5ea81a0..91f2f6ee 100644 --- a/examples/napi/example.wasi.cjs +++ b/examples/napi/example.wasi.cjs @@ -234,6 +234,7 @@ module.exports.f64ArrayToArray = __napiModule.exports.f64ArrayToArray module.exports.fibonacci = __napiModule.exports.fibonacci module.exports.fnReceivedAliased = __napiModule.exports.fnReceivedAliased module.exports.generateFunctionAndCallIt = __napiModule.exports.generateFunctionAndCallIt +module.exports.getBigintJsonValue = __napiModule.exports.getBigintJsonValue module.exports.getBtreeMapping = __napiModule.exports.getBtreeMapping module.exports.getBuffer = __napiModule.exports.getBuffer module.exports.getBufferSlice = __napiModule.exports.getBufferSlice diff --git a/examples/napi/index.cjs b/examples/napi/index.cjs index e2213cda..b0f021c7 100644 --- a/examples/napi/index.cjs +++ b/examples/napi/index.cjs @@ -524,6 +524,7 @@ module.exports.f64ArrayToArray = nativeBinding.f64ArrayToArray module.exports.fibonacci = nativeBinding.fibonacci module.exports.fnReceivedAliased = nativeBinding.fnReceivedAliased module.exports.generateFunctionAndCallIt = nativeBinding.generateFunctionAndCallIt +module.exports.getBigintJsonValue = nativeBinding.getBigintJsonValue module.exports.getBtreeMapping = nativeBinding.getBtreeMapping module.exports.getBuffer = nativeBinding.getBuffer module.exports.getBufferSlice = nativeBinding.getBufferSlice diff --git a/examples/napi/index.d.cts b/examples/napi/index.d.cts index 5d019c78..f0dbced6 100644 --- a/examples/napi/index.d.cts +++ b/examples/napi/index.d.cts @@ -534,6 +534,8 @@ export interface FunctionData { export declare function generateFunctionAndCallIt(): FunctionData +export declare function getBigintJsonValue(value: bigint): void + export declare function getBtreeMapping(): Record export declare function getBuffer(): Buffer diff --git a/examples/napi/src/serde.rs b/examples/napi/src/serde.rs index bad10a3e..e7a46353 100644 --- a/examples/napi/src/serde.rs +++ b/examples/napi/src/serde.rs @@ -69,3 +69,27 @@ impl PackageJsonReader { &self.i } } + +#[napi(catch_unwind, ts_args_type = "value: bigint")] +pub fn get_bigint_json_value(bigint_json_value: Value) { + match bigint_json_value { + Value::Number(n) => { + if let Some(u) = n.as_u64() { + assert_eq!(u, 1); + return; + } + if let Some(i) = n.as_i64() { + assert_eq!(i, -1); + return; + } + unreachable!("should not happen"); + } + Value::String(s) => { + assert_eq!(s, "18446744073709551620"); + return; + } + _ => { + unreachable!("should not happen"); + } + } +}