kitsune_p2p_types/
codec.rs1pub fn rmp_encode<W, S>(write: &mut W, item: S) -> Result<(), std::io::Error>
6where
7 W: std::io::Write,
8 S: serde::Serialize,
9{
10 let mut se = rmp_serde::encode::Serializer::new(write).with_struct_map();
11 item.serialize(&mut se)
12 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
13 Ok(())
14}
15
16pub fn rmp_decode<R, D>(r: &mut R) -> Result<D, std::io::Error>
19where
20 R: std::io::Read,
21 for<'de> D: Sized + serde::Deserialize<'de>,
22{
23 let mut de = rmp_serde::decode::Deserializer::new(r);
24 D::deserialize(&mut de).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
25}
26
27pub trait Codec: Clone + Sized {
29 fn variant_type(&self) -> &'static str;
31
32 fn encode<W>(&self, w: &mut W) -> Result<(), std::io::Error>
35 where
36 W: std::io::Write;
37
38 fn encode_vec(&self) -> Result<Vec<u8>, std::io::Error> {
41 let mut data = Vec::new();
42 self.encode(&mut data)?;
43 Ok(data)
44 }
45
46 fn decode<R>(r: &mut R) -> Result<Self, std::io::Error>
49 where
50 R: std::io::Read;
51
52 fn decode_ref(r: &[u8]) -> Result<(u64, Self), std::io::Error> {
56 let mut r = std::io::Cursor::new(r);
57 let item = Self::decode(&mut r)?;
58 Ok((r.position(), item))
59 }
60}
61
62#[macro_export]
97macro_rules! write_codec_enum {
98 ($(#[doc = $codec_doc:expr])* codec $codec_name:ident {$(
99 $(#[doc = $var_doc:expr])* $var_name:ident($var_id:literal) {$(
100 $(#[doc = $type_doc:expr])* $type_name:ident.$type_idx:literal: $type_ty:ty,
101 )*},
102 )*}) => {
103 $crate::dependencies::paste::item! {
104 $(
105 $(#[doc = $var_doc])*
106 #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
107 #[cfg_attr(feature = "fuzzing", derive($crate::dependencies::proptest_derive::Arbitrary))]
109 pub struct [< $var_name:camel >] {
110 $(
111 $(#[doc = $type_doc])* pub [< $type_name:snake >]: $type_ty,
112 )*
113 }
114
115 impl $crate::codec::Codec for [< $var_name:camel >] {
116 fn variant_type(&self) -> &'static str {
117 concat!(
118 stringify!([< $codec_name:camel >]),
119 "::",
120 stringify!([< $var_name:camel >]),
121 )
122 }
123
124 fn encode<W>(&self, w: &mut W) -> ::std::io::Result<()>
125 where
126 W: ::std::io::Write
127 {
128 #[cfg(debug_assertions)]
129 #[allow(dead_code)]
130 {
131 const MSG: &str = "type index must begin at 0 and increment by exactly 1 per type - switching type order will break parsing compatibility";
132 let mut _idx = -1;
133 $(
134 _idx += 1;
135 assert_eq!(_idx, $type_idx, "{}", MSG);
136 )*
137 }
138 let t: (
139 $(&$type_ty,)*
140 ) = (
141 $(&self.[< $type_name:snake >],)*
142 );
143 $crate::codec::rmp_encode(w, &t)
144 }
145
146 fn decode<R>(r: &mut R) -> ::std::io::Result<Self>
147 where
148 R: ::std::io::Read
149 {
150 let (
151 $([< $type_name:snake >],)*
152 ): (
153 $($type_ty,)*
154 ) = $crate::codec::rmp_decode(r)?;
155 Ok([< $var_name:camel >] {
156 $(
157 [< $type_name:snake >],
158 )*
159 })
160 }
161 }
162 )*
163
164 $(#[doc = $codec_doc])*
165 #[derive(Clone, Debug, PartialEq, Eq)]
166 #[cfg_attr(feature = "fuzzing", derive($crate::dependencies::proptest_derive::Arbitrary))]
168 pub enum [< $codec_name:camel >] {
169 $(
170 $(#[doc = $var_doc])*
171 [< $var_name:camel >]([< $var_name:camel >]),
172 )*
173 }
174
175 impl [< $codec_name:camel >] {
176 $(
177 pub fn [< $var_name:snake >]($(
179 [< $type_name:snake >]: $type_ty,
180 )*) -> Self {
181 Self::[< $var_name:camel >]([< $var_name:camel >] {
182 $(
183 [< $type_name:snake >],
184 )*
185 })
186 }
187 )*
188 }
189
190 impl $crate::codec::Codec for [< $codec_name:camel >] {
191 fn variant_type(&self) -> &'static str {
192 match self {
193 $(
194 Self::[< $var_name:camel >](data) =>
195 $crate::codec::Codec::variant_type(data),
196 )*
197 }
198 }
199
200 fn encode<W>(&self, w: &mut W) -> ::std::io::Result<()>
201 where
202 W: ::std::io::Write
203 {
204 match self {
205 $(
206 Self::[< $var_name:camel >](data) => {
207 ::std::io::Write::write_all(w, &[$var_id])?;
208 $crate::codec::Codec::encode(data, w)
209 }
210 )*
211 }
212 }
213
214 fn decode<R>(r: &mut R) -> Result<Self, ::std::io::Error>
215 where
216 R: ::std::io::Read
217 {
218 let mut c = [0_u8; 1];
219 ::std::io::Read::read_exact(r, &mut c)?;
220 match c[0] {
221 $(
222 $var_id => {
223 Ok(Self::[< $var_name:camel >]($crate::codec::Codec::decode(r)?))
224 },
225 )*
226 _ => Err(::std::io::Error::new(::std::io::ErrorKind::Other, "invalid protocol byte")),
227 }
228 }
229 }
230 }
231 };
232}
233
234#[cfg(test)]
235mod tests {
236 #![allow(dead_code)]
237
238 use super::*;
239 use std::sync::Arc;
240
241 #[derive(
242 Clone,
243 Debug,
244 PartialEq,
245 Eq,
246 serde::Serialize,
247 serde::Deserialize,
248 proptest_derive::Arbitrary,
249 )]
250 pub struct Sub(pub Vec<u8>);
251
252 write_codec_enum! {
253 codec Bob {
255 BobOne(0x42) {
257 yay.0: bool,
259
260 age.1: u32,
262
263 sub.2: Arc<Sub>,
265 },
266 BobTwo(0x43) {
268 },
269 }
270 }
271
272 #[test]
273 fn test_encode_decode() {
274 let bob = Bob::bob_one(true, 42, Arc::new(Sub(b"test".to_vec())));
275 let data = bob.encode_vec().unwrap();
276 let res = Bob::decode_ref(&data).unwrap().1;
277 assert_eq!(bob, res);
278 }
279}