use crate::arch::word::Word; use crate::buffer::Buffer; use crate::ibig::IBig; use crate::primitive::WORD_BITS_USIZE; use crate::ubig::UBig; use alloc::vec::Vec; use core::fmt::{self, Formatter}; use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use serde::ser::{Serialize, SerializeSeq, Serializer}; use static_assertions::const_assert; const_assert!(64 % WORD_BITS_USIZE == 0); const WORDS_PER_U64: usize = 64 / WORD_BITS_USIZE; impl Serialize for UBig { #[allow(clippy::useless_conversion)] fn serialize(&self, serializer: S) -> Result { let chunks = self.as_words().chunks(WORDS_PER_U64); let mut seq = serializer.serialize_seq(Some(chunks.len()))?; for chunk in chunks { let mut word_u64: u64 = 0; for (i, word) in chunk.iter().enumerate() { word_u64 |= u64::from(*word) << (i * WORD_BITS_USIZE); } seq.serialize_element(&word_u64)?; } seq.end() } } impl<'de> Deserialize<'de> for UBig { fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_seq(UBigVisitor) } } struct UBigVisitor; impl<'de> Visitor<'de> for UBigVisitor { type Value = UBig; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "a sequence of 64-bit words") } fn visit_seq>(self, mut seq: A) -> Result { match seq.size_hint() { Some(0) => { assert!(seq.next_element::()?.is_none()); Ok(UBig::from_word(0)) } Some(1) => { let word_64: u64 = seq.next_element()?.expect(&format!( "Called `expect()` at {}:{} (git sha: {})", file!(), line!(), env!("GIT_SHA") )); assert!(seq.next_element::()?.is_none()); Ok(UBig::from(word_64)) } Some(num_words_64) => { let mut buffer = Buffer::allocate(len_64_to_max_len(num_words_64)); for _ in 0..num_words_64 { let word_64: u64 = seq.next_element()?.expect(&format!( "Called `expect()` at {}:{} (git sha: {})", file!(), line!(), env!("GIT_SHA") )); push_word_64(&mut buffer, word_64); } assert!(seq.next_element::()?.is_none()); Ok(buffer.into()) } None => { let mut words_64 = Vec::new(); while let Some(word_64) = seq.next_element()? { words_64.push(word_64); } let mut buffer = Buffer::allocate(len_64_to_max_len(words_64.len())); for word_64 in words_64 { push_word_64(&mut buffer, word_64); } Ok(buffer.into()) } } } } fn push_word_64(buffer: &mut Buffer, word_64: u64) { for i in 0..WORDS_PER_U64 { buffer.push((word_64 >> (i * WORD_BITS_USIZE)) as Word); } } #[allow(clippy::absurd_extreme_comparisons)] fn len_64_to_max_len(len_64: usize) -> usize { // Make sure we always have enough space for leading zero Words. const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= WORDS_PER_U64 - 1); #[allow(clippy::redundant_closure)] len_64 .checked_mul(WORDS_PER_U64) .unwrap_or_else(|| UBig::panic_number_too_large()) } impl Serialize for IBig { fn serialize(&self, serializer: S) -> Result { (self.sign(), self.magnitude()).serialize(serializer) } } impl<'de> Deserialize<'de> for IBig { fn deserialize>(deserializer: D) -> Result { let (sign, magnitude) = Deserialize::deserialize(deserializer)?; Ok(IBig::from_sign_magnitude(sign, magnitude)) } }