cardano_serialization_lib/serialization/
serialization_macros.rs

1// JsError can't be used by non-wasm targets so we use this macro to expose
2// either a DeserializeError or a JsError error depending on if we're on a
3// wasm or a non-wasm target where JsError is not available (it panics!).
4// Note: wasm-bindgen doesn't support macros inside impls, so we have to wrap these
5//       in their own impl and invoke the invoke the macro from global scope.
6// TODO: possibly write s generic version of this for other usages (e.g. PrivateKey, etc)
7#[macro_export]
8macro_rules! from_bytes {
9    // Custom from_bytes() code
10    ($name:ident, $data: ident, $body:block) => {
11        // wasm-exposed JsError return - JsError panics when used outside wasm
12        #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "dont-expose-wasm")))]
13        #[wasm_bindgen]
14        impl $name {
15            pub fn from_bytes($data: Vec<u8>) -> Result<$name, JsError> {
16                Ok($body?)
17            }
18        }
19        // non-wasm exposed DeserializeError return
20        #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "dont-expose-wasm"))))]
21        impl $name {
22            pub fn from_bytes($data: Vec<u8>) -> Result<$name, DeserializeError> $body
23        }
24    };
25    // Uses Deserialize trait to auto-generate one
26    ($name:ident) => {
27        from_bytes!($name, bytes, {
28            let mut raw = Deserializer::from(std::io::Cursor::new(bytes));
29            Self::deserialize(&mut raw)
30        });
31    };
32}
33
34// There's no need to do wasm vs non-wasm as this call can't fail but
35// this is here just to provide a default Serialize-based impl
36// Note: Once again you can't use macros in impls with wasm-bindgen
37//       so make sure you invoke this outside of one
38#[macro_export]
39macro_rules! to_bytes {
40    ($name:ident) => {
41        #[wasm_bindgen]
42        impl $name {
43            pub fn to_bytes(&self) -> Vec<u8> {
44                let mut buf = Serializer::new_vec();
45                self.serialize(&mut buf).unwrap();
46                buf.finalize()
47            }
48        }
49    };
50}
51
52#[macro_export]
53macro_rules! from_hex {
54    // Custom from_bytes() code
55    ($name:ident, $data: ident, $body:block) => {
56        // wasm-exposed JsError return - JsError panics when used outside wasm
57        #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "dont-expose-wasm")))]
58        #[wasm_bindgen]
59        impl $name {
60            pub fn from_hex($data: &str) -> Result<$name, JsError> {
61                match hex::decode($data) {
62                    Ok(_) => Ok($body?),
63                    Err(e) => Err(JsError::from_str(&e.to_string()))
64                }
65
66            }
67        }
68        // non-wasm exposed DeserializeError return
69        #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "dont-expose-wasm"))))]
70        impl $name {
71            pub fn from_hex($data: &str) -> Result<$name, DeserializeError> $body
72        }
73    };
74    // Uses Deserialize trait to auto-generate one
75    ($name:ident) => {
76        from_hex!($name, hex_str, {
77            let mut raw = Deserializer::from(std::io::Cursor::new(hex::decode(hex_str).unwrap()));
78            Self::deserialize(&mut raw)
79        });
80    };
81}
82
83#[macro_export]
84macro_rules! to_hex {
85    ($name:ident) => {
86        #[wasm_bindgen]
87        impl $name {
88            pub fn to_hex(&self) -> String {
89                let mut buf = Serializer::new_vec();
90                self.serialize(&mut buf).unwrap();
91                hex::encode(buf.finalize())
92            }
93        }
94    };
95}
96
97#[macro_export]
98macro_rules! to_from_bytes {
99    ($name:ident) => {
100        to_bytes!($name);
101        from_bytes!($name);
102        to_hex!($name);
103        from_hex!($name);
104    };
105}
106
107#[macro_export]
108macro_rules! to_from_json {
109    ($name:ident) => {
110        #[wasm_bindgen]
111        impl $name {
112            pub fn to_json(&self) -> Result<String, JsError> {
113                serde_json::to_string_pretty(&self)
114                    .map_err(|e| JsError::from_str(&format!("to_json: {}", e)))
115            }
116
117            #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "dont-expose-wasm")))]
118            pub fn to_js_value(&self) -> Result<JsValue, JsError> {
119                let serializer = serde_wasm_bindgen::Serializer::json_compatible();
120                serde::Serialize::serialize(self, &serializer)
121                    .map_err(|e| JsError::from_str(&format!("to_js_value: {}", e)))
122            }
123
124            pub fn from_json(json: &str) -> Result<$name, JsError> {
125                serde_json::from_str(json)
126                    .map_err(|e| JsError::from_str(&format!("from_json: {}", e)))
127            }
128        }
129    };
130}
131
132#[macro_export]
133macro_rules! impl_to_from {
134    ($name:ident) => {
135        to_from_bytes!($name);
136        to_from_json!($name);
137    };
138}
139
140#[macro_export]
141macro_rules! impl_deserialize_for_wrapped_tuple {
142    ($type:ty) => {
143        impl Deserialize for $type {
144            fn deserialize<R: BufRead + Seek>(
145                raw: &mut Deserializer<R>,
146            ) -> Result<Self, DeserializeError> {
147                (|| -> Result<_, DeserializeError> {
148                    use crate::serialization::utils::check_len_indefinite;
149                    let len = raw.array()?;
150
151                    let inner_struct = Self::deserialize_as_embedded_group(raw, len)?;
152
153                    check_len_indefinite(raw, len)?;
154
155                    Ok(inner_struct)
156                })()
157                .map_err(|e| e.annotate(stringify!($type)))
158            }
159        }
160    };
161}