fedimint_core/encoding/
as_hex.rs1use serde::Deserialize;
16
17use super::{Decodable, Encodable};
18use crate::module::registry::ModuleRegistry;
19
20pub fn serialize<T, S>(t: &T, ser: S) -> Result<S::Ok, S::Error>
21where
22 T: Encodable,
23 S: serde::Serializer,
24{
25 ser.serialize_str(&t.consensus_encode_to_hex())
26}
27
28pub fn deserialize<'de, T: Decodable, D>(de: D) -> Result<T, D::Error>
29where
30 D: serde::de::Deserializer<'de>,
31{
32 Decodable::consensus_decode_hex(&String::deserialize(de)?, &ModuleRegistry::default()).map_err(
33 |e| {
34 serde::de::Error::custom(format!(
35 "decodable deserialization failed: {}",
36 crate::util::FmtCompact::fmt_compact(&e)
37 ))
38 },
39 )
40}
41
42#[macro_export]
43macro_rules! serialize_as_encodable_hex {
44 ($name:ident) => {
45 impl Serialize for $name {
46 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47 where
48 S: serde::Serializer,
49 {
50 use $crate::Encodable;
51 serializer.serialize_str(&self.consensus_encode_to_hex().map_err(|e| {
52 serde::ser::Error::custom(format!("encodable serialization failed: {e:#}"))
53 })?)
54 }
55 }
56 };
57}
58
59#[macro_export]
60macro_rules! deserialize_as_encodable_hex {
61 ($name:ident) => {
62 impl<'de> Deserialize<'de> for $name {
63 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64 where
65 D: serde::Deserializer<'de>,
66 {
67 $crate::Decodable::consensus_decode_hex(
68 &String::deserialize(deserializer)?,
69 &Default::default(),
70 )
71 .map_err(|e| {
72 serde::de::Error::custom(format!(
73 "decodable deserialization failed: {}",
74 $crate::util::FmtCompact::fmt_compact(&e)
75 ))
76 })
77 }
78 }
79 };
80}
81
82#[macro_export]
83macro_rules! serde_as_encodable_hex {
84 ($name:ident) => {
85 $crate::serialize_as_encodable_hex!($name);
86 $crate::deserialize_as_encodable_hex!($name);
87 };
88}
89
90#[cfg(test)]
91mod tests {
92 use fedimint_derive::{Decodable, Encodable};
93
94 use crate::encoding::Decodable as _;
95 use crate::module::registry::ModuleRegistry;
96 use crate::util::FmtCompact as _;
97
98 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
99 struct TestStruct {
100 vec: Vec<u8>,
101 num: u32,
102 }
103
104 #[derive(Debug, serde::Deserialize)]
105 struct Wrapper {
106 #[serde(with = "crate::encoding::as_hex", rename = "inner")]
107 _inner: TestStruct,
108 }
109
110 #[test_log::test]
111 fn deserialize_reports_the_whole_decode_chain() {
112 let err = serde_json::from_str::<Wrapper>(r#"{"inner":"0107"}"#)
115 .expect_err("payload is truncated");
116
117 let expected = TestStruct::consensus_decode_hex("0107", &ModuleRegistry::default())
118 .expect_err("payload is truncated");
119
120 assert!(
121 err.to_string().starts_with(&format!(
122 "decodable deserialization failed: {}",
123 expected.fmt_compact()
124 )),
125 "{err}"
126 );
127 assert_ne!(
128 expected.fmt_compact().to_string(),
129 expected.to_string(),
130 "the decode error has more than one layer and the message shows all of them"
131 );
132 }
133}