1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
macro_rules! data_structure {
    (
        $(#[$outer:meta])*
        pub struct $name:ident {
            $(
                $(#[$field_meta:meta])*
                pub $field:ident : $ty:ty,
            )*
        }
    ) => {
        $(#[$outer])*
        pub struct $name {
            $(
                $(#[$field_meta])*
                pub $field: $ty,
            )*
        }

        impl $name {
            /// Convert this struct to a byte array.
            pub fn to_bytes(&self) -> ::Result<Vec<u8>> {
                use convert::Convertable;
                use failure::ResultExt;

                let mut result = Vec::new();
                $(
                    self.$field.into_buffer(&mut result)
                        .context(concat!("Could not serialize field ", stringify!($name), "::", stringify!($field)))?;
                )*;
                Ok(result)
            }

            /// Convert a byte array to an instance of this struct.
            pub fn from(data: &[u8]) -> ::Result<$name> {
                use convert::Convertable;
                use failure::ResultExt;

                let mut cursor = ::std::io::Cursor::new(data);
                $(
                    let $field: $ty = Convertable::from_cursor(&mut cursor)
                        .context(concat!("Could not deserialize field ", stringify!($name), "::", stringify!($field)))?;
                )*
                Ok($name {
                    $($field, )*
                })
            }
        }


        #[test]
        fn test_encode_decode() {
            let start = $name {
                $(
                    $field: ::convert::Convertable::get_test_value(),
                )*
            };
            let bytes = start.to_bytes().expect("Could not serialize");
            let end = $name::from(&bytes).expect("Could not deserialize");
            $(
                assert!(::convert::Convertable::is_equal(&start.$field, &end.$field));
            )*
        }
    };
}