zero_formatter/
union.rs

1/// `union_formatter` define struct type and provide formatter.
2///
3/// ```
4/// # #[macro_use] extern crate zero_formatter;
5/// # extern crate byteorder;
6/// # use zero_formatter::*;
7/// # use std::io::{Seek, SeekFrom, Read, Write, Cursor, Result};
8/// # use byteorder::{ReadBytesExt, WriteBytesExt};
9/// #
10/// # declare_buffer! { Buffer }
11/// #
12/// object_formatter! {
13///     #[target(Buffer<Cursor<Vec<u8>>>)]
14///     AObject {
15///         0; a: i32,
16///         1; b: i64
17///     }
18/// }
19///
20/// object_formatter! {
21///     #[target(Buffer<Cursor<Vec<u8>>>)]
22///     OtherObject {
23///         0; c: i32,
24///         1; d: i64
25///     }
26/// }
27///
28/// union_formatter! {
29///     #[target(Buffer<Cursor<Vec<u8>>>)]
30///     enum UnionSample: i32 {
31///         0; A(AObject),
32///         1; Other(OtherObject)
33///     }
34/// }
35///
36/// # fn example() -> Result<()> {
37/// # let mut writer = Buffer::new(Cursor::new(Vec::new()));
38/// let a: UnionSample = UnionSample::A(AObject { a: 1, b: 2 });
39/// try!(writer.serialize(0, a));
40/// let other: UnionSample = UnionSample::Other(OtherObject { c: 3, d: 4 });
41/// try!(writer.serialize(0, other));
42/// # Ok(())
43/// # }
44/// #
45/// # fn main() {
46/// # example();
47/// # }
48/// ```
49
50#[macro_export]
51macro_rules! union_formatter {
52    (#[target($buffer:ty)]
53    enum $name:ident : $key_type:ty {
54        $($key_value:expr; $case_name:ident($field_type:ty)),*
55    }) => {
56        #[derive(Debug, PartialEq, Eq, Copy, Clone)]
57        pub enum $name {
58            $($case_name($field_type)),*
59        }
60
61        impl Formatter<$name> for $buffer {
62
63            fn serialize(&mut self, offset: u64, value: $name) -> ZeroFormatterResult<i32> {
64                let mut byte_size: i32 = 4;
65
66                match value {
67                    $(
68                    $name::$case_name(v) => {
69                        byte_size += try!(self.serialize(offset + (byte_size as u64), $key_value));
70                        byte_size += try!(self.serialize(offset + (byte_size as u64), v))
71                    }
72                    ),*
73                }
74
75                try!(self.serialize(offset, byte_size));
76
77                Ok(byte_size)
78            }
79
80            fn deserialize(&mut self, offset: &mut u64) -> ZeroFormatterResult<$name> {
81
82                try!(util::check_non_null(self, offset));
83
84                let key: $key_type = try!(self.deserialize(offset));
85                match key {
86                    $(
87                    $key_value => {
88                        let v: $field_type = try!(self.deserialize(offset));
89                        Ok( $name::$case_name (v) )
90                    }
91                    ),*,
92                    _ => ZeroFormatterError::invalid_binary(*offset)
93                }
94            }
95        }
96
97        option_formatter! {
98            #[target($buffer)]
99            $name
100        }
101    }
102}
103
104#[cfg(test)]
105mod tests {
106
107    use std::io::Cursor;
108    use std::io::{Seek, SeekFrom};
109    use error::*;
110    use formatter::*;
111    use util;
112
113    object_formatter! {
114        #[target(Cursor<Vec<u8>>)]
115        O {
116            0; a: i32
117        }
118    }
119
120    struct_formatter! {
121        #[target(Cursor<Vec<u8>>)]
122        S {
123            b: i64
124        }
125    }
126
127    union_formatter! {
128        #[target(Cursor<Vec<u8>>)]
129        enum U: i32 {
130            1; A(O),
131            2; B(S)
132        }
133    }
134
135    #[test]
136    fn serialize_deserialize_union_a() {
137        let mut c = Cursor::new(Vec::new());
138        let input: U = U::A(O{ a: 1 });
139        assert_eq!(c.serialize(0, input).unwrap(), 24);
140        let mut offset = 0;
141        assert_eq!(input, c.deserialize(&mut offset).unwrap());
142    }
143
144    #[test]
145    fn serialize_deserialize_union_b() {
146        let mut c = Cursor::new(Vec::new());
147        let input: U = U::B(S{ b: 2 });
148        assert_eq!(c.serialize(0, input).unwrap(), 16);
149        let mut offset = 0;
150        assert_eq!(input, c.deserialize(&mut offset).unwrap());
151    }
152}