diff --git a/crates/napi/src/bindgen_runtime/js_values/serde.rs b/crates/napi/src/bindgen_runtime/js_values/serde.rs index edff26da..52983850 100644 --- a/crates/napi/src/bindgen_runtime/js_values/serde.rs +++ b/crates/napi/src/bindgen_runtime/js_values/serde.rs @@ -4,6 +4,8 @@ use crate::{ bindgen_runtime::Null, check_status, sys, type_of, Error, JsObject, Result, Status, ValueType, }; +#[cfg(feature = "napi6")] +use super::BigInt; use super::{FromNapiValue, Object, ToNapiValue}; impl ToNapiValue for Value { @@ -111,14 +113,30 @@ impl FromNapiValue for Map { impl ToNapiValue for Number { unsafe fn to_napi_value(env: sys::napi_env, n: Self) -> Result { + #[cfg(feature = "napi6")] + const MAX_SAFE_INT: i64 = 9007199254740991i64; // 2 ^ 53 - 1 if n.is_i64() { - unsafe { i64::to_napi_value(env, n.as_i64().unwrap()) } + let n = n.as_i64().unwrap(); + #[cfg(feature = "napi6")] + { + if !(-MAX_SAFE_INT..=MAX_SAFE_INT).contains(&n) { + return unsafe { BigInt::to_napi_value(env, BigInt::from(n)) }; + } + } + + unsafe { i64::to_napi_value(env, n) } } else if n.is_f64() { unsafe { f64::to_napi_value(env, n.as_f64().unwrap()) } } else { let n = n.as_u64().unwrap(); if n > u32::MAX as u64 { - todo!("impl BigInt") + #[cfg(feature = "napi6")] + { + return unsafe { BigInt::to_napi_value(env, BigInt::from(n)) }; + } + + #[cfg(not(feature = "napi6"))] + return unsafe { String::to_napi_value(env, n.to_string()) }; } else { unsafe { u32::to_napi_value(env, n as u32) } } diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index dcb71156..a907c780 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -195,6 +195,7 @@ Generated by [AVA](https://avajs.dev). export function readPackageJson(): PackageJson␊ export function getPackageJsonName(packageJson: PackageJson): string␊ export function testSerdeRoundtrip(data: any): any␊ + export function testSerdeBigNumberPrecision(number: string): any␊ export function returnFromSharedCrate(): Shared␊ export function contains(source: string, target: string): boolean␊ export function concatStr(s: string): string␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 51bfd98d..14120495 100644 Binary files a/examples/napi/__test__/typegen.spec.ts.snap and b/examples/napi/__test__/typegen.spec.ts.snap differ diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 12cf64e8..2a87c012 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -90,6 +90,7 @@ import { getStrFromObject, returnJsFunction, testSerdeRoundtrip, + testSerdeBigNumberPrecision, createObjWithProperty, receiveObjectOnlyFromJs, dateToNumber, @@ -495,6 +496,23 @@ test('serde-roundtrip', (t) => { t.is(err!.message, 'JS symbols cannot be represented as a serde_json::Value') }) +test('serde-large-number-precision', (t) => { + t.is(testSerdeBigNumberPrecision('12345').number, 12345) + t.is( + testSerdeBigNumberPrecision('123456789012345678901234567890').number, + 1.2345678901234568e29, + ) + t.is( + testSerdeBigNumberPrecision('123456789012345678901234567890.123456789') + .number, + 1.2345678901234568e29, + ) + t.is( + testSerdeBigNumberPrecision('109775245175819965').number.toString(), + '109775245175819965', + ) +}) + test('buffer', (t) => { let buf = getBuffer() t.is(buf.toString('utf-8'), 'Hello world') diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 1d04fd43..0abc1042 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -185,6 +185,7 @@ export interface PackageJson { export function readPackageJson(): PackageJson export function getPackageJsonName(packageJson: PackageJson): string export function testSerdeRoundtrip(data: any): any +export function testSerdeBigNumberPrecision(number: string): any export function returnFromSharedCrate(): Shared export function contains(source: string, target: string): boolean export function concatStr(s: string): string diff --git a/examples/napi/src/serde.rs b/examples/napi/src/serde.rs index b7a76177..13a52196 100644 --- a/examples/napi/src/serde.rs +++ b/examples/napi/src/serde.rs @@ -30,3 +30,9 @@ fn get_package_json_name(package_json: PackageJson) -> String { fn test_serde_roundtrip(data: Value) -> Value { data } + +#[napi] +fn test_serde_big_number_precision(number: String) -> Value { + let data = format!("{{\"number\":{}}}", number); + serde_json::from_str(&data).unwrap() +}