diff --git a/Cargo.lock b/Cargo.lock index 81c5cb70db..1fca2a9f76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4104,6 +4104,7 @@ dependencies = [ "bencher", "bytes", "derive_more", + "num-bigint", "serde", "serde_bytes", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index b7da8f78c0..6dff03d4d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,7 @@ log = "=0.4.17" lsp-types = "=0.93.2" # used by tower-lsp and "proposed" feature is unstable in patch releases lzzzz = "1.0" notify = "=5.0.0" +num-bigint = "0.4" once_cell = "1.17.1" os_pipe = "=1.0.1" parking_lot = "0.12.0" diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml index 4e518e71d9..a146d5ada0 100644 --- a/serde_v8/Cargo.toml +++ b/serde_v8/Cargo.toml @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] bytes.workspace = true derive_more = "0.99.17" +num-bigint.workspace = true serde.workspace = true serde_bytes.workspace = true smallvec = { workspace = true, features = ["union"] } diff --git a/serde_v8/de.rs b/serde_v8/de.rs index 15a90a13de..6708daa4d1 100644 --- a/serde_v8/de.rs +++ b/serde_v8/de.rs @@ -13,6 +13,7 @@ use crate::magic::transl8::visit_magic; use crate::magic::transl8::FromV8; use crate::magic::transl8::MagicType; use crate::payload::ValueType; +use crate::BigInt; use crate::ByteString; use crate::DetachedBuffer; use crate::StringOrBuffer; @@ -348,6 +349,9 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> StringOrBuffer::MAGIC_NAME => { visit_magic(visitor, StringOrBuffer::from_v8(self.scope, self.input)?) } + BigInt::MAGIC_NAME => { + visit_magic(visitor, BigInt::from_v8(self.scope, self.input)?) + } magic::Value::MAGIC_NAME => { visit_magic(visitor, magic::Value::from_v8(self.scope, self.input)?) } diff --git a/serde_v8/error.rs b/serde_v8/error.rs index 145524abbe..72d3cc9259 100644 --- a/serde_v8/error.rs +++ b/serde_v8/error.rs @@ -23,6 +23,7 @@ pub enum Error { ExpectedBuffer, ExpectedDetachable, ExpectedExternal, + ExpectedBigInt, ExpectedUtf8, ExpectedLatin1, diff --git a/serde_v8/lib.rs b/serde_v8/lib.rs index b857acbe81..1d17914bbe 100644 --- a/serde_v8/lib.rs +++ b/serde_v8/lib.rs @@ -15,6 +15,7 @@ pub use de::Deserializer; pub use error::Error; pub use error::Result; pub use keys::KeyCache; +pub use magic::bigint::BigInt; pub use magic::buffer::ZeroCopyBuf; pub use magic::bytestring::ByteString; pub use magic::detached_buffer::DetachedBuffer; diff --git a/serde_v8/magic/bigint.rs b/serde_v8/magic/bigint.rs new file mode 100644 index 0000000000..69828747ff --- /dev/null +++ b/serde_v8/magic/bigint.rs @@ -0,0 +1,76 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +use smallvec::smallvec; +use smallvec::SmallVec; + +use super::transl8::FromV8; +use super::transl8::ToV8; +use crate::magic::transl8::impl_magic; +use crate::Error; + +#[derive( + PartialEq, + Eq, + Clone, + Debug, + Default, + derive_more::Deref, + derive_more::DerefMut, + derive_more::AsRef, + derive_more::AsMut, +)] +#[as_mut(forward)] +#[as_ref(forward)] +pub struct BigInt(num_bigint::BigInt); +impl_magic!(BigInt); + +impl ToV8 for BigInt { + fn to_v8<'a>( + &mut self, + scope: &mut v8::HandleScope<'a>, + ) -> Result, crate::Error> { + let (sign, words) = self.0.to_u64_digits(); + let sign_bit = sign == num_bigint::Sign::Minus; + let v = v8::BigInt::new_from_words(scope, sign_bit, &words).unwrap(); + Ok(v.into()) + } +} + +impl FromV8 for BigInt { + fn from_v8( + _scope: &mut v8::HandleScope, + value: v8::Local, + ) -> Result { + let v8bigint = v8::Local::::try_from(value) + .map_err(|_| Error::ExpectedBigInt)?; + let word_count = v8bigint.word_count(); + let mut words: SmallVec<[u64; 1]> = smallvec![0u64; word_count]; + let (sign_bit, _words) = v8bigint.to_words_array(&mut words); + let sign = match sign_bit { + true => num_bigint::Sign::Minus, + false => num_bigint::Sign::Plus, + }; + // SAFETY: Because the alignment of u64 is 8, the alignment of u32 is 4, and + // the size of u64 is 8, the size of u32 is 4, the alignment of u32 is a + // factor of the alignment of u64, and the size of u32 is a factor of the + // size of u64, we can safely transmute the slice of u64 to a slice of u32. + let (prefix, slice, suffix) = unsafe { words.align_to::() }; + assert!(prefix.is_empty()); + assert!(suffix.is_empty()); + assert_eq!(slice.len(), words.len() * 2); + let big_int = num_bigint::BigInt::from_slice(sign, slice); + Ok(Self(big_int)) + } +} + +impl From for BigInt { + fn from(big_int: num_bigint::BigInt) -> Self { + Self(big_int) + } +} + +impl From for num_bigint::BigInt { + fn from(big_int: BigInt) -> Self { + big_int.0 + } +} diff --git a/serde_v8/magic/mod.rs b/serde_v8/magic/mod.rs index f96e422b16..9e5064867f 100644 --- a/serde_v8/magic/mod.rs +++ b/serde_v8/magic/mod.rs @@ -1,4 +1,5 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +pub mod bigint; pub mod buffer; pub mod bytestring; pub mod detached_buffer; diff --git a/serde_v8/ser.rs b/serde_v8/ser.rs index fa4cfecde7..6c10f3fb4c 100644 --- a/serde_v8/ser.rs +++ b/serde_v8/ser.rs @@ -14,6 +14,7 @@ use crate::magic::transl8::opaque_recv; use crate::magic::transl8::MagicType; use crate::magic::transl8::ToV8; use crate::magic::transl8::MAGIC_FIELD; +use crate::BigInt; use crate::ByteString; use crate::DetachedBuffer; use crate::ExternalPointer; @@ -277,6 +278,7 @@ pub enum StructSerializers<'a, 'b, 'c> { MagicByteString(MagicalSerializer<'a, 'b, 'c, ByteString>), MagicU16String(MagicalSerializer<'a, 'b, 'c, U16String>), MagicStringOrBuffer(MagicalSerializer<'a, 'b, 'c, StringOrBuffer>), + MagicBigInt(MagicalSerializer<'a, 'b, 'c, BigInt>), Regular(ObjectSerializer<'a, 'b, 'c>), } @@ -299,6 +301,7 @@ impl<'a, 'b, 'c> ser::SerializeStruct for StructSerializers<'a, 'b, 'c> { StructSerializers::MagicStringOrBuffer(s) => { s.serialize_field(key, value) } + StructSerializers::MagicBigInt(s) => s.serialize_field(key, value), StructSerializers::Regular(s) => s.serialize_field(key, value), } } @@ -312,6 +315,7 @@ impl<'a, 'b, 'c> ser::SerializeStruct for StructSerializers<'a, 'b, 'c> { StructSerializers::MagicByteString(s) => s.end(), StructSerializers::MagicU16String(s) => s.end(), StructSerializers::MagicStringOrBuffer(s) => s.end(), + StructSerializers::MagicBigInt(s) => s.end(), StructSerializers::Regular(s) => s.end(), } } @@ -592,6 +596,10 @@ impl<'a, 'b, 'c> ser::Serializer for Serializer<'a, 'b, 'c> { let m = MagicalSerializer::::new(self.scope); Ok(StructSerializers::MagicStringOrBuffer(m)) } + BigInt::MAGIC_NAME => { + let m = MagicalSerializer::::new(self.scope); + Ok(StructSerializers::MagicBigInt(m)) + } magic::Value::MAGIC_NAME => { let m = MagicalSerializer::>::new(self.scope); Ok(StructSerializers::Magic(m)) diff --git a/serde_v8/serializable.rs b/serde_v8/serializable.rs index 21c7bb7523..b02aa0629e 100644 --- a/serde_v8/serializable.rs +++ b/serde_v8/serializable.rs @@ -2,6 +2,7 @@ use std::any::TypeId; use std::mem::transmute_copy; +use crate::BigInt; use crate::ByteString; use crate::U16String; use crate::ZeroCopyBuf; @@ -65,6 +66,7 @@ pub enum Primitive { ZeroCopyBuf(ZeroCopyBuf), ByteString(ByteString), U16String(U16String), + BigInt(BigInt), } impl serde::Serialize for Primitive { @@ -89,6 +91,7 @@ impl serde::Serialize for Primitive { Self::ZeroCopyBuf(x) => x.serialize(s), Self::ByteString(x) => x.serialize(s), Self::U16String(x) => x.serialize(s), + Self::BigInt(x) => x.serialize(s), } } } @@ -137,6 +140,8 @@ impl From for SerializablePkg { Self::Primitive(Primitive::ByteString(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::U16String(tc(x))) + } else if tid == TypeId::of::() { + Self::Primitive(Primitive::BigInt(tc(x))) } else { Self::Serializable(Box::new(x)) } diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs index 5f3e262e75..a77089babb 100644 --- a/serde_v8/tests/de.rs +++ b/serde_v8/tests/de.rs @@ -4,6 +4,7 @@ use serde::Deserializer; use serde_v8::utils::js_exec; use serde_v8::utils::v8_do; +use serde_v8::BigInt; use serde_v8::ByteString; use serde_v8::Error; use serde_v8::U16String; @@ -566,3 +567,65 @@ detest!( "BigInt(-1.7976931348623157e+308)", f32::NEG_INFINITY ); + +// BigInt to BigInt +detest!( + de_bigint_var_u8, + BigInt, + "255n", + num_bigint::BigInt::from(255u8).into() +); +detest!( + de_bigint_var_i8, + BigInt, + "-128n", + num_bigint::BigInt::from(-128i8).into() +); +detest!( + de_bigint_var_u16, + BigInt, + "65535n", + num_bigint::BigInt::from(65535u16).into() +); +detest!( + de_bigint_var_i16, + BigInt, + "-32768n", + num_bigint::BigInt::from(-32768i16).into() +); +detest!( + de_bigint_var_u32, + BigInt, + "4294967295n", + num_bigint::BigInt::from(4294967295u32).into() +); +detest!( + de_bigint_var_i32, + BigInt, + "-2147483648n", + num_bigint::BigInt::from(-2147483648i32).into() +); +detest!( + de_bigint_var_u64, + BigInt, + "18446744073709551615n", + num_bigint::BigInt::from(18446744073709551615u64).into() +); +detest!( + de_bigint_var_i64, + BigInt, + "-9223372036854775808n", + num_bigint::BigInt::from(-9223372036854775808i64).into() +); +detest!( + de_bigint_var_u128, + BigInt, + "340282366920938463463374607431768211455n", + num_bigint::BigInt::from(340282366920938463463374607431768211455u128).into() +); +detest!( + de_bigint_var_i128, + BigInt, + "-170141183460469231731687303715884105728n", + num_bigint::BigInt::from(-170141183460469231731687303715884105728i128).into() +); diff --git a/serde_v8/tests/ser.rs b/serde_v8/tests/ser.rs index d6de3a62a2..b61a758f91 100644 --- a/serde_v8/tests/ser.rs +++ b/serde_v8/tests/ser.rs @@ -3,6 +3,7 @@ use serde::Serialize; use serde_json::json; use serde_v8::utils::js_exec; use serde_v8::utils::v8_do; +use serde_v8::BigInt; #[derive(Debug, Serialize, PartialEq)] struct MathOp { @@ -137,6 +138,61 @@ sertest!( "objEqual(x, {a: 1, b: 3, operator: null})" ); +sertest!( + ser_bigint_u8, + BigInt::from(num_bigint::BigInt::from(255_u8)), + "x === 255n" +); +sertest!( + ser_bigint_i8, + BigInt::from(num_bigint::BigInt::from(-128_i8)), + "x === -128n" +); +sertest!( + ser_bigint_u16, + BigInt::from(num_bigint::BigInt::from(65535_u16)), + "x === 65535n" +); +sertest!( + ser_bigint_i16, + BigInt::from(num_bigint::BigInt::from(-32768_i16)), + "x === -32768n" +); +sertest!( + ser_bigint_u32, + BigInt::from(num_bigint::BigInt::from(4294967295_u32)), + "x === 4294967295n" +); +sertest!( + ser_bigint_i32, + BigInt::from(num_bigint::BigInt::from(-2147483648_i32)), + "x === -2147483648n" +); +sertest!( + ser_bigint_u64, + BigInt::from(num_bigint::BigInt::from(9007199254740991_u64)), + "x === 9007199254740991n" +); +sertest!( + ser_bigint_i64, + BigInt::from(num_bigint::BigInt::from(-9007199254740991_i64)), + "x === -9007199254740991n" +); +sertest!( + ser_bigint_u128, + BigInt::from(num_bigint::BigInt::from( + 340282366920938463463374607431768211455_u128 + )), + "x === 340282366920938463463374607431768211455n" +); +sertest!( + ser_bigint_i128, + BigInt::from(num_bigint::BigInt::from( + -170141183460469231731687303715884105728_i128 + )), + "x === -170141183460469231731687303715884105728n" +); + sertest!( ser_map, {