Skip to main content

alloy_eip8141/
serde_utils.rs

1//! Serde helpers following Alloy's quantity and byte-string conventions.
2
3use alloy_primitives::{FixedBytes, U8, U64};
4use core::fmt;
5use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
6
7pub(crate) mod quantity {
8    use super::*;
9
10    pub(crate) fn serialize<S: Serializer>(value: &u64, serializer: S) -> Result<S::Ok, S::Error> {
11        U64::from(*value).serialize(serializer)
12    }
13
14    pub(crate) fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
15        U64::deserialize(deserializer).map(|value| value.to())
16    }
17}
18
19pub(crate) mod quantity_u8 {
20    use super::*;
21
22    pub(crate) fn serialize<S: Serializer>(value: &u8, serializer: S) -> Result<S::Ok, S::Error> {
23        U8::from(*value).serialize(serializer)
24    }
25
26    pub(crate) fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u8, D::Error> {
27        U8::deserialize(deserializer).map(|value| value.to())
28    }
29}
30
31pub(crate) fn serialize_optional_bytes<const N: usize, S: Serializer>(
32    value: Option<FixedBytes<N>>,
33    serializer: S,
34) -> Result<S::Ok, S::Error> {
35    match value {
36        Some(value) => value.serialize(serializer),
37        None => FixedBytes::<0>::ZERO.serialize(serializer),
38    }
39}
40
41/// Deserializes an optional fixed-size byte string.
42///
43/// Empty byte strings, `"0x"`, and `null` all yield `None`.
44pub(crate) fn deserialize_optional_bytes<'de, const N: usize, D: Deserializer<'de>>(
45    deserializer: D,
46) -> Result<Option<FixedBytes<N>>, D::Error> {
47    struct OptionalBytesVisitor<const N: usize>;
48
49    impl<'de, const N: usize> de::Visitor<'de> for OptionalBytesVisitor<N> {
50        type Value = Option<FixedBytes<N>>;
51
52        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53            write!(formatter, "an empty byte string or exactly {N} bytes")
54        }
55
56        fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
57            Ok(None)
58        }
59
60        fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
61            Ok(None)
62        }
63
64        fn visit_bytes<E: de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
65            if bytes.is_empty() {
66                Ok(None)
67            } else {
68                FixedBytes::try_from(bytes).map(Some).map_err(E::custom)
69            }
70        }
71
72        fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
73            if value == "0x" || value.is_empty() {
74                Ok(None)
75            } else {
76                value.parse().map(Some).map_err(E::custom)
77            }
78        }
79
80        fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
81            let mut bytes = [0u8; N];
82            let mut len = 0;
83            while len < N {
84                match seq.next_element()? {
85                    Some(byte) => {
86                        bytes[len] = byte;
87                        len += 1;
88                    }
89                    None => break,
90                }
91            }
92            if len == 0 {
93                return Ok(None);
94            }
95            if len < N {
96                return Err(de::Error::invalid_length(len, &self));
97            }
98            if seq.next_element::<u8>()?.is_some() {
99                return Err(de::Error::invalid_length(N + 1, &self));
100            }
101            Ok(Some(bytes.into()))
102        }
103    }
104
105    if deserializer.is_human_readable() {
106        deserializer.deserialize_any(OptionalBytesVisitor::<N>)
107    } else {
108        deserializer.deserialize_bytes(OptionalBytesVisitor::<N>)
109    }
110}