Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Docs
Browse files Browse the repository at this point in the history
kjvalencik committed Feb 7, 2023

Verified

This commit was signed with the committer’s verified signature.
targos Michaël Zasso
1 parent 57e9c32 commit 2467cfa
Showing 2 changed files with 119 additions and 3 deletions.
96 changes: 93 additions & 3 deletions crates/neon/src/types_impl/bigint.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Types for working with [`JsBigInt`].
use std::{error, fmt, mem::MaybeUninit};

use crate::prelude::NeonResult;
@@ -9,15 +11,26 @@ use crate::{
types::JsBigInt,
};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// Indicates if a `JsBigInt` is positive or negative
pub enum Sign {
Positive,
Negative,
}

#[derive(Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// Indicates a lossless conversion from a [`JsBigInt`] to a Rust integer
/// could not be performed.
///
/// Failures include:
/// * Negative sign on an unsigned int
/// * Overflow of an int
/// * Underflow of a signed int
pub struct Error<T>(T);

impl<T> Error<T> {
/// Get the lossy value read from a `BigInt`. It may be truncated,
/// sign extended or wrapped.
pub fn into_inner(self) -> T {
self.0
}
@@ -47,6 +60,17 @@ impl JsBigInt {
pub const POSITIVE: Sign = Sign::Positive;
pub const NEGATIVE: Sign = Sign::Negative;

/// Creates a `BigInt` from an [`i64`].
///
/// # Example
///
/// ```
/// # use neon::{prelude::*, types::JsBigInt};
/// # fn example(mut cx: FunctionContext) -> JsResult<JsBigInt> {
/// let value: Handle<JsBigInt> = JsBigInt::from_i64(&mut cx, 42);
/// # Ok(value)
/// # }
/// ```
pub fn from_i64<'cx, C>(cx: &mut C, n: i64) -> Handle<'cx, Self>
where
C: Context<'cx>,
@@ -64,6 +88,7 @@ impl JsBigInt {
Handle::new_internal(Self(v))
}

/// Creates a `BigInt` from a [`u64`].
pub fn from_u64<'cx, C>(cx: &mut C, n: u64) -> Handle<'cx, Self>
where
C: Context<'cx>,
@@ -81,6 +106,7 @@ impl JsBigInt {
Handle::new_internal(Self(v))
}

// Internal helper for creating a _signed_ `BigInt` from a [`u128`]
fn from_u128_sign<'cx, C>(cx: &mut C, sign: Sign, n: u128) -> Handle<'cx, Self>
where
C: Context<'cx>,
@@ -91,6 +117,7 @@ impl JsBigInt {
Self::from_digits_le(cx, sign, &digits)
}

/// Creates a `BigInt` from an [`i128`].
pub fn from_i128<'cx, C>(cx: &mut C, n: i128) -> Handle<'cx, Self>
where
C: Context<'cx>,
@@ -104,13 +131,31 @@ impl JsBigInt {
Self::from_u128_sign(cx, Self::NEGATIVE, n)
}

/// Creates a `BigInt` from a [`u128`].
pub fn from_u128<'cx, C>(cx: &mut C, n: u128) -> Handle<'cx, Self>
where
C: Context<'cx>,
{
Self::from_u128_sign(cx, Self::POSITIVE, n)
}

/// Creates a `BigInt` from a signed magnitude (i.e., _not_ two's complement).
/// Digits are little-endian.
///
/// # Example
///
/// ```
/// # use neon::{prelude::*, types::JsBigInt};
/// # fn example(mut cx: FunctionContext) -> JsResult<JsBigInt> {
/// // Creates a `BigInt` equal to `2n ** 128n`
/// let value: Handle<JsBigInt> = JsBigInt::from_digits_le(
/// &mut cx,
/// JsBigInt::POSITIVE,
/// &[0, 0, 1],
/// );
/// # Ok(value)
/// # }
/// ```
pub fn from_digits_le<'cx, C>(cx: &mut C, sign: Sign, digits: &[u64]) -> Handle<'cx, Self>
where
C: Context<'cx>,
@@ -139,6 +184,9 @@ impl JsBigInt {
Handle::new_internal(Self(v))
}

/// Reads an `i64` from a `BigInt`.
///
/// Fails on overflow and underflow.
pub fn to_i64<'cx, C>(&self, cx: &mut C) -> Result<i64, Error<i64>>
where
C: Context<'cx>,
@@ -160,6 +208,9 @@ impl JsBigInt {
}
}

/// Reads a `u64` from a `BigInt`.
///
/// Fails on overflow or a negative sign.
pub fn to_u64<'cx, C>(&self, cx: &mut C) -> Result<u64, Error<u64>>
where
C: Context<'cx>,
@@ -181,6 +232,9 @@ impl JsBigInt {
}
}

/// Reads an `i128` from a `BigInt`.
///
/// Fails on overflow and underflow.
pub fn to_i128<'cx, C>(&self, cx: &mut C) -> Result<i128, Error<i128>>
where
C: Context<'cx>,
@@ -214,6 +268,9 @@ impl JsBigInt {
}
}

/// Reads a `u128` from a `BigInt`.
///
/// Fails on overflow or a negative sign.
pub fn to_u128<'cx, C>(&self, cx: &mut C) -> Result<u128, Error<u128>>
where
C: Context<'cx>,
@@ -230,19 +287,44 @@ impl JsBigInt {
}
}

/// Gets a signed magnitude pair from a `BigInt`. Digits are little-endian.
pub fn to_digits_le<'cx, C>(&self, cx: &mut C) -> (Sign, Vec<u64>)
where
C: Context<'cx>,
{
let (_, len) = self.read_digits_le(cx, &mut []);
let mut v = vec![0; len];
let mut v = vec![0; self.len(cx)];
let (sign, len) = self.read_digits_le(cx, &mut v);

debug_assert_eq!(v.len(), len);

(sign, v)
}

/// Gets the sign from a `BigInt` and reads little-endian digits into a buffer.
/// The returned `usize` is the total number of digits in the `BigInt`.
///
/// # Example
///
/// Read a `u256` from a `BigInt`.
///
/// ```
/// # use std::error::Error;
/// # use neon::{prelude::*, types::JsBigInt};
/// fn bigint_to_u256(cx: &mut FunctionContext, n: Handle<JsBigInt>) -> NeonResult<[u64; 4]> {
/// let mut digits = [0; 4];
/// let (sign, num_digits) = n.read_digits_le(cx, &mut digits);
///
/// if sign == JsBigInt::NEGATIVE {
/// return cx.throw_error("Underflow reading u256 from BigInt");
/// }
///
/// if num_digits > digits.len() {
/// return cx.throw_error("Overflow reading u256 from BigInt");
/// }
///
/// Ok(digits)
/// }
/// ```
pub fn read_digits_le<'cx, C>(&self, cx: &mut C, digits: &mut [u64]) -> (Sign, usize)
where
C: Context<'cx>,
@@ -271,4 +353,12 @@ impl JsBigInt {

(sign, word_count)
}

/// Gets the number of `u64` digits in a `BigInt`
pub fn len<'cx, C>(&self, cx: &mut C) -> usize
where
C: Context<'cx>,
{
self.read_digits_le(cx, &mut []).1
}
}
26 changes: 26 additions & 0 deletions crates/neon/src/types_impl/mod.rs
Original file line number Diff line number Diff line change
@@ -1251,6 +1251,32 @@ impl<T: Object> private::ValueInternal for JsFunction<T> {
#[cfg_attr(docsrs, doc(cfg(feature = "napi-6")))]
#[derive(Debug)]
#[repr(transparent)]
/// The type of JavaScript
/// [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
/// values.
///
/// # Example
///
/// The following shows an example of adding two numbers that exceed
/// [`Number.MAX_SAFE_INTEGER`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER).
///
/// ```
/// # use neon::{prelude::*, types::JsBigInt};
///
/// fn add_bigint(mut cx: FunctionContext) -> JsResult<JsBigInt> {
/// // Get references to the `BigInt` arguments
/// let a = cx.argument::<JsBigInt>(0)?;
/// let b = cx.argument::<JsBigInt>(1)?;
///
/// // Convert the `BigInt` to `i64`
/// let a = a.to_i64(&mut cx).or_throw(&mut cx)?;
/// let b = b.to_i64(&mut cx).or_throw(&mut cx)?;
/// let sum = a + b;
///
/// // Create a `BigInt` from the `i64` sum
/// Ok(JsBigInt::from_i64(&mut cx, sum))
/// }
/// ```
pub struct JsBigInt(raw::Local);

#[cfg(feature = "napi-6")]

0 comments on commit 2467cfa

Please sign in to comment.