diff options
| author | Luca Casonato <hello@lcas.dev> | 2023-03-16 17:59:47 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-16 16:59:47 +0000 |
| commit | b99c431ac78810034ea57cc778bf57d627998aa9 (patch) | |
| tree | 4398efcd8d3757e42a5cd4bdcee4ed9533103f43 /serde_v8/magic/bigint.rs | |
| parent | 1a3c2e2f1dc5add94b5b7ff4ba4c26df55c7a011 (diff) | |
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.
Diffstat (limited to 'serde_v8/magic/bigint.rs')
| -rw-r--r-- | serde_v8/magic/bigint.rs | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/serde_v8/magic/bigint.rs b/serde_v8/magic/bigint.rs new file mode 100644 index 000000000..69828747f --- /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<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 + } +} |
