Skip to content

Commit

Permalink
Port napi_get_value_bigint_{int64,uint64} from #14501
Browse files Browse the repository at this point in the history
  • Loading branch information
190n committed Dec 16, 2024
1 parent 7633f3c commit 0e5430c
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 20 deletions.
76 changes: 76 additions & 0 deletions src/bun.js/bindings/napi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,82 @@ extern "C" napi_status napi_typeof(napi_env env, napi_value val,
return napi_generic_failure;
}

static_assert(std::is_same_v<JSBigInt::Digit, uint64_t>, "All NAPI bigint functions assume that bigint words are 64 bits");
#if USE(BIGINT32)
#error All NAPI bigint functions assume that BIGINT32 is disabled
#endif

extern "C" napi_status napi_get_value_bigint_int64(napi_env env, napi_value value, int64_t* result, bool* lossless)
{
NAPI_PREMABLE
JSValue jsValue = toJS(value);
if (jsValue.isEmpty() || !result) {
return napi_invalid_arg;
}
if (!jsValue.isHeapBigInt()) {
return napi_bigint_expected;
}

JSBigInt* bigint = jsValue.asHeapBigInt();

if (bigint->isZero()) {
*result = 0;
if (lossless != nullptr) *lossless = true;
} else {
uint64_t digit = bigint->digit(0);
uint64_t signed_digit = digit;
if (bigint->sign()) {
// negate, while keeping it unsigned because i don't trust signed overflow
signed_digit = ~signed_digit + 1;
}
memcpy(result, &signed_digit, sizeof(signed_digit));

if (lossless != nullptr) {
if (bigint->length() > 1) {
*lossless = false;
} else if (bigint->sign()) {
// negative
// lossless if numeric value is >= -2^63,
// for which digit will be <= 2^63
*lossless = (digit <= (1ull << 63));
} else {
// positive
// lossless if numeric value is <= 2^63 - 1
*lossless = (digit <= static_cast<uint64_t>(INT64_MAX));
}
}
}

return napi_ok;
}

extern "C" napi_status napi_get_value_bigint_uint64(napi_env env, napi_value value, uint64_t* result, bool* lossless)
{
NAPI_PREMABLE
JSValue jsValue = toJS(value);
if (jsValue.isEmpty() || !result) {
return napi_invalid_arg;
}
if (!jsValue.isHeapBigInt()) {
return napi_bigint_expected;
}

JSBigInt* bigint = jsValue.asHeapBigInt();

if (bigint->isZero()) {
*result = 0;
if (lossless != nullptr) *lossless = true;
} else {
*result = bigint->digit(0);
if (lossless != nullptr) {
// lossless if and only if only one digit and positive
*lossless = (bigint->length() == 1 && bigint->sign() == false);
}
}

return napi_ok;
}

extern "C" napi_status napi_get_value_bigint_words(napi_env env,
napi_value value,
int* sign_bit,
Expand Down
22 changes: 2 additions & 20 deletions src/napi/napi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1032,26 +1032,8 @@ pub export fn napi_create_bigint_uint64(env: napi_env, value: u64, result_: ?*na
return .ok;
}
pub extern fn napi_create_bigint_words(env: napi_env, sign_bit: c_int, word_count: usize, words: [*c]const u64, result: *napi_value) napi_status;
// TODO: lossless
pub export fn napi_get_value_bigint_int64(_: napi_env, value_: napi_value, result_: ?*i64, _: *bool) napi_status {
log("napi_get_value_bigint_int64", .{});
const result = result_ orelse {
return invalidArg();
};
const value = value_.get();
result.* = value.toInt64();
return .ok;
}
// TODO: lossless
pub export fn napi_get_value_bigint_uint64(_: napi_env, value_: napi_value, result_: ?*u64, _: *bool) napi_status {
log("napi_get_value_bigint_uint64", .{});
const result = result_ orelse {
return invalidArg();
};
const value = value_.get();
result.* = value.toUInt64NoTruncate();
return .ok;
}
pub extern fn napi_get_value_bigint_int64(env: napi_env, value: napi_value, result: ?*i64, lossless: ?*bool) napi_status;
pub extern fn napi_get_value_bigint_uint64(env: napi_env, value: napi_value, result: ?*u64, lossless: ?*bool) napi_status;

pub extern fn napi_get_value_bigint_words(env: napi_env, value: napi_value, sign_bit: [*c]c_int, word_count: [*c]usize, words: [*c]u64) napi_status;
pub extern fn napi_get_all_property_names(env: napi_env, object: napi_value, key_mode: napi_key_collection_mode, key_filter: napi_key_filter, key_conversion: napi_key_conversion, result: *napi_value) napi_status;
Expand Down

0 comments on commit 0e5430c

Please sign in to comment.