mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
feat(serde_v8): support BigInt serialization (#18225)
This commit enables serializing `v8::BigInt` to `num_bigint::BigInt` in Rust. Pre-requisite for sub upcoming feature work.
This commit is contained in:
parent
1a3c2e2f1d
commit
b99c431ac7
12 changed files with 218 additions and 0 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4104,6 +4104,7 @@ dependencies = [
|
|||
"bencher",
|
||||
"bytes",
|
||||
"derive_more",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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)?)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ pub enum Error {
|
|||
ExpectedBuffer,
|
||||
ExpectedDetachable,
|
||||
ExpectedExternal,
|
||||
ExpectedBigInt,
|
||||
|
||||
ExpectedUtf8,
|
||||
ExpectedLatin1,
|
||||
|
|
|
@ -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;
|
||||
|
|
76
serde_v8/magic/bigint.rs
Normal file
76
serde_v8/magic/bigint.rs
Normal file
|
@ -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<v8::Local<'a, v8::Value>, 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<v8::Value>,
|
||||
) -> Result<Self, crate::Error> {
|
||||
let v8bigint = v8::Local::<v8::BigInt>::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::<u32>() };
|
||||
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<num_bigint::BigInt> for BigInt {
|
||||
fn from(big_int: num_bigint::BigInt) -> Self {
|
||||
Self(big_int)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BigInt> for num_bigint::BigInt {
|
||||
fn from(big_int: BigInt) -> Self {
|
||||
big_int.0
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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::<StringOrBuffer>::new(self.scope);
|
||||
Ok(StructSerializers::MagicStringOrBuffer(m))
|
||||
}
|
||||
BigInt::MAGIC_NAME => {
|
||||
let m = MagicalSerializer::<BigInt>::new(self.scope);
|
||||
Ok(StructSerializers::MagicBigInt(m))
|
||||
}
|
||||
magic::Value::MAGIC_NAME => {
|
||||
let m = MagicalSerializer::<magic::Value<'a>>::new(self.scope);
|
||||
Ok(StructSerializers::Magic(m))
|
||||
|
|
|
@ -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<T: serde::Serialize + 'static> From<T> for SerializablePkg {
|
|||
Self::Primitive(Primitive::ByteString(tc(x)))
|
||||
} else if tid == TypeId::of::<U16String>() {
|
||||
Self::Primitive(Primitive::U16String(tc(x)))
|
||||
} else if tid == TypeId::of::<BigInt>() {
|
||||
Self::Primitive(Primitive::BigInt(tc(x)))
|
||||
} else {
|
||||
Self::Serializable(Box::new(x))
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue