Skip to main content

tycho_simulation/
serde_helpers.rs

1/// serde functions for handling bytes as hex strings, such as [bytes::Bytes]
2pub mod hex_bytes {
3    use serde::{Deserialize, Deserializer, Serializer};
4
5    /// Serialize a byte vec as a hex string with 0x prefix
6    pub fn serialize<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
7    where
8        S: Serializer,
9        T: AsRef<[u8]>,
10    {
11        s.serialize_str(&format!("0x{encoded}", encoded = hex::encode(x.as_ref())))
12    }
13
14    /// Deserialize a hex string into a byte vec
15    /// Accepts a hex string with optional 0x prefix
16    pub fn deserialize<'de, T, D>(d: D) -> Result<T, D::Error>
17    where
18        D: Deserializer<'de>,
19        T: From<Vec<u8>>,
20    {
21        let value = String::deserialize(d)?;
22        if let Some(value) = value.strip_prefix("0x") {
23            hex::decode(value)
24        } else {
25            hex::decode(&value)
26        }
27        .map(Into::into)
28        .map_err(|e| serde::de::Error::custom(e.to_string()))
29    }
30}
31
32/// serde functions for handling Option of bytes
33pub mod hex_bytes_option {
34    use serde::{Deserialize, Deserializer, Serializer};
35
36    /// Serialize a byte vec as a Some hex string with 0x prefix
37    pub fn serialize<S, T>(x: &Option<T>, s: S) -> Result<S::Ok, S::Error>
38    where
39        S: Serializer,
40        T: AsRef<[u8]>,
41    {
42        if let Some(x) = x {
43            s.serialize_str(&format!("0x{encoded}", encoded = hex::encode(x.as_ref())))
44        } else {
45            s.serialize_none()
46        }
47    }
48
49    /// Deserialize a hex string into a byte vec or None
50    /// Accepts a hex string with optional 0x prefix
51    pub fn deserialize<'de, T, D>(d: D) -> Result<Option<T>, D::Error>
52    where
53        D: Deserializer<'de>,
54        T: From<Vec<u8>>,
55    {
56        let value: Option<String> = Option::deserialize(d)?;
57
58        match value {
59            Some(val) => {
60                let val = if let Some(stripped) = val.strip_prefix("0x") { stripped } else { &val };
61                hex::decode(val)
62                    .map(Into::into)
63                    .map(Some)
64                    .map_err(|e| serde::de::Error::custom(e.to_string()))
65            }
66            None => Ok(None),
67        }
68    }
69}
70
71/// Macro to implement error-returning Serialize/Deserialize for protocols
72/// that cannot be serialized (e.g., due to VM state or external SDK dependencies).
73///
74/// # Examples
75/// ```ignore
76/// impl_non_serializable_protocol!(MyProtocolState, "error message");
77/// ```
78#[macro_export]
79macro_rules! impl_non_serializable_protocol {
80    ($type:ty, $msg:expr) => {
81        impl serde::Serialize for $type {
82            fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
83            where
84                S: serde::Serializer,
85            {
86                Err(serde::ser::Error::custom($msg))
87            }
88        }
89
90        impl<'de> serde::Deserialize<'de> for $type {
91            fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
92            where
93                D: serde::Deserializer<'de>,
94            {
95                Err(serde::de::Error::custom($msg))
96            }
97        }
98    };
99}
100
101#[cfg(test)]
102mod tests {
103    use serde::{Deserialize, Serialize};
104    use serde_json;
105
106    use super::*;
107
108    #[derive(Debug, Serialize, Deserialize)]
109    struct TestStruct {
110        #[serde(with = "hex_bytes")]
111        bytes: Vec<u8>,
112
113        #[serde(with = "hex_bytes_option")]
114        bytes_option: Option<Vec<u8>>,
115    }
116
117    #[test]
118    fn hex_bytes_serialize_deserialize() {
119        let test_struct = TestStruct { bytes: vec![0u8; 10], bytes_option: Some(vec![0u8; 10]) };
120
121        // Serialize to JSON
122        let serialized = serde_json::to_string(&test_struct).unwrap();
123        assert_eq!(
124            serialized,
125            "{\"bytes\":\"0x00000000000000000000\",\"bytes_option\":\"0x00000000000000000000\"}"
126        );
127
128        // Deserialize from JSON
129        let deserialized: TestStruct = serde_json::from_str(&serialized).unwrap();
130        assert_eq!(deserialized.bytes, vec![0u8; 10]);
131        assert_eq!(deserialized.bytes_option, Some(vec![0u8; 10]));
132    }
133
134    #[test]
135    fn hex_bytes_option_none() {
136        let test_struct = TestStruct { bytes: vec![0u8; 10], bytes_option: None };
137
138        // Serialize to JSON
139        let serialized = serde_json::to_string(&test_struct).unwrap();
140        assert_eq!(serialized, "{\"bytes\":\"0x00000000000000000000\",\"bytes_option\":null}");
141
142        // Deserialize from JSON
143        let deserialized: TestStruct = serde_json::from_str(&serialized).unwrap();
144        assert_eq!(deserialized.bytes, vec![0u8; 10]);
145        assert_eq!(deserialized.bytes_option, None);
146    }
147}