Skip to main content

dashu_int/third_party/
serde.rs

1//! Implement serde traits.
2
3use crate::{convert::words_to_le_bytes, ibig::IBig, ubig::UBig, Sign};
4use core::fmt::{self, Formatter};
5use serde::{
6    de::{self, Deserialize, Deserializer, Visitor},
7    ser::{Serialize, Serializer},
8};
9
10impl Serialize for UBig {
11    #[inline]
12    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
13        if serializer.is_human_readable() {
14            serializer.collect_str(self)
15        } else if self.is_zero() {
16            serializer.serialize_bytes(&[])
17        } else {
18            let bytes = words_to_le_bytes::<false>(self.as_words());
19            serializer.serialize_bytes(&bytes)
20        }
21    }
22}
23
24impl<'de> Deserialize<'de> for UBig {
25    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
26        if deserializer.is_human_readable() {
27            deserializer.deserialize_str(UBigVisitor)
28        } else {
29            deserializer.deserialize_bytes(UBigVisitor)
30        }
31    }
32}
33
34/// UBig is serialized as little-endian bytes.
35struct UBigVisitor;
36
37impl<'de> Visitor<'de> for UBigVisitor {
38    type Value = UBig;
39
40    fn expecting(&self, f: &mut Formatter) -> fmt::Result {
41        write!(f, "a string or a sequence of bytes")
42    }
43
44    fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
45        match UBig::from_str_with_radix_prefix(v) {
46            Ok((n, _)) => Ok(n),
47            Err(e) => Err(de::Error::custom(e)),
48        }
49    }
50
51    fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
52        Ok(UBig::from_le_bytes(v))
53    }
54}
55
56impl Serialize for IBig {
57    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
58        if serializer.is_human_readable() {
59            serializer.collect_str(self)
60        } else if self.is_zero() {
61            serializer.serialize_bytes(&[])
62        } else {
63            // TODO(v0.5): Change to IBig::to_le_bytes(), which provides better interop robustness
64            let (sign, words) = self.as_sign_words();
65            let mut bytes = words_to_le_bytes::<false>(words);
66
67            // use the length to encode the sign, postive <=> even, negative <=> odd.
68            // pad zeros when necessary
69            if (sign == Sign::Positive && bytes.len() & 1 == 1)
70                || (sign == Sign::Negative && bytes.len() & 1 == 0)
71            {
72                bytes.push(0);
73            }
74            serializer.serialize_bytes(&bytes)
75        }
76    }
77}
78
79impl<'de> Deserialize<'de> for IBig {
80    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
81        if deserializer.is_human_readable() {
82            deserializer.deserialize_str(IBigVisitor)
83        } else {
84            deserializer.deserialize_bytes(IBigVisitor)
85        }
86    }
87}
88
89/// IBig is serialized as little-endian bytes, where the sign is encoded in the byte length
90struct IBigVisitor;
91
92impl<'de> Visitor<'de> for IBigVisitor {
93    type Value = IBig;
94
95    fn expecting(&self, f: &mut Formatter) -> fmt::Result {
96        write!(f, "a string or a sequence of 64-bit words")
97    }
98
99    fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
100        match IBig::from_str_with_radix_prefix(v) {
101            Ok((n, _)) => Ok(n),
102            Err(e) => Err(de::Error::custom(e)),
103        }
104    }
105
106    fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
107        let sign = Sign::from(v.len() & 1 == 1);
108        Ok(IBig::from_parts(sign, UBig::from_le_bytes(v)))
109    }
110}