1 //! serializers working a sequence of objects (pairs, tuples, etc)
2 use crate::internal::{GenResult, SerializeFn, WriteContext};
3 use crate::lib::std::io::Write;
4 
5 /// Applies 2 serializers in sequence
6 ///
7 /// ```rust
8 /// use cookie_factory::{gen, sequence::pair, combinator::string};
9 ///
10 /// let mut buf = [0u8; 100];
11 ///
12 /// {
13 ///   let (buf, pos) = gen(pair(string("abcd"), string("efgh")), &mut buf[..]).unwrap();
14 ///   assert_eq!(pos, 8);
15 ///   assert_eq!(buf.len(), 100 - 8);
16 /// }
17 ///
18 /// assert_eq!(&buf[..8], &b"abcdefgh"[..]);
19 /// ```
pair<F, G, W: Write>(first: F, second: G) -> impl SerializeFn<W> where F: SerializeFn<W>, G: SerializeFn<W>,20 pub fn pair<F, G, W: Write>(first: F, second: G) -> impl SerializeFn<W>
21 where
22     F: SerializeFn<W>,
23     G: SerializeFn<W>,
24 {
25     move |out: WriteContext<W>| first(out).and_then(&second)
26 }
27 
28 /// Helper trait for the `tuple` combinator
29 pub trait Tuple<W> {
serialize(&self, w: WriteContext<W>) -> GenResult<W>30     fn serialize(&self, w: WriteContext<W>) -> GenResult<W>;
31 }
32 
33 impl<W: Write, A: SerializeFn<W>> Tuple<W> for (A,) {
serialize(&self, w: WriteContext<W>) -> GenResult<W>34     fn serialize(&self, w: WriteContext<W>) -> GenResult<W> {
35         self.0(w)
36     }
37 }
38 
39 // Generates all the Tuple impls for tuples of arbitrary sizes based on a list of type
40 // parameters like FnA FnB FnC. It would generate the impl then for (FnA, FnB)
41 // and (FnA, FnB, FnC).
42 macro_rules! tuple_trait(
43   ($name1:ident, $name2: ident, $($name:ident),*) => (
44     tuple_trait!(__impl $name1, $name2; $($name),*);
45   );
46   (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => (
47     tuple_trait_impl!($($name),+);
48     tuple_trait!(__impl $($name),+ , $name1; $($name2),*);
49   );
50   (__impl $($name:ident),+; $name1:ident) => (
51     tuple_trait_impl!($($name),+);
52     tuple_trait_impl!($($name),+, $name1);
53   );
54 );
55 
56 // Generates the impl block for Tuple on tuples or arbitrary sizes based on its
57 // arguments. Takes a list of type parameters as parameters, e.g. FnA FnB FnC
58 // and then implements the trait on (FnA, FnB, FnC).
59 macro_rules! tuple_trait_impl(
60   ($($name:ident),+) => (
61     impl<W: Write, $($name: SerializeFn<W>),+> Tuple<W> for ( $($name),+ ) {
62       fn serialize(&self, w: WriteContext<W>) -> GenResult<W> {
63         tuple_trait_inner!(0, self, w, $($name)+)
64       }
65     }
66   );
67 );
68 
69 // Generates the inner part of the Tuple::serialize() implementation, which will
70 // basically look as follows:
71 //
72 // let w = self.0(w)?;
73 // let w = self.1(w)?;
74 // [...]
75 // let w = self.N(w)?;
76 //
77 // Ok(w)
78 macro_rules! tuple_trait_inner(
79   ($it:tt, $self:expr, $w:ident, $head:ident $($id:ident)+) => ({
80     let w = $self.$it($w)?;
81 
82     succ!($it, tuple_trait_inner!($self, w, $($id)+))
83   });
84   ($it:tt, $self:expr, $w:ident, $head:ident) => ({
85     let w = $self.$it($w)?;
86 
87     Ok(w)
88   });
89 );
90 
91 // Takes an integer and a macro invocation, and changes the macro invocation
92 // to take the incremented integer as the first argument
93 //
94 // Works for integers between 0 and 19.
95 #[doc(hidden)]
96 macro_rules! succ (
97   (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
98   (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
99   (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
100   (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
101   (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
102   (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
103   (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
104   (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
105   (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
106   (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
107   (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
108   (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
109   (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
110   (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
111   (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
112   (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
113   (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
114   (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
115   (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
116   (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
117 );
118 
119 tuple_trait!(
120     FnA, FnB, FnC, FnD, FnE, FnF, FnG, FnH, FnI, FnJ, FnK, FnL, FnM, FnN, FnO, FnP, FnQ, FnR, FnS,
121     FnT, FnU
122 );
123 
124 /// Applies multiple serializers in sequence
125 ///
126 /// Currently tuples up to 20 elements are supported.
127 ///
128 /// ```rust
129 /// use cookie_factory::{gen, sequence::tuple, combinator::string, bytes::be_u16};
130 ///
131 /// let mut buf = [0u8; 100];
132 ///
133 /// {
134 ///   let (buf, pos) = gen(
135 ///     tuple((
136 ///       string("abcd"),
137 ///       be_u16(0x20),
138 ///       string("efgh"),
139 ///     )),
140 ///     &mut buf[..]
141 ///   ).unwrap();
142 ///   assert_eq!(pos, 10);
143 ///   assert_eq!(buf.len(), 100 - 10);
144 /// }
145 ///
146 /// assert_eq!(&buf[..10], &b"abcd\x00\x20efgh"[..]);
147 /// ```
tuple<W: Write, List: Tuple<W>>(l: List) -> impl SerializeFn<W>148 pub fn tuple<W: Write, List: Tuple<W>>(l: List) -> impl SerializeFn<W> {
149     move |w: WriteContext<W>| l.serialize(w)
150 }
151 
152 #[cfg(test)]
153 mod test {
154     use super::*;
155     use crate::combinator::string;
156     use crate::internal::gen_simple;
157 
158     #[test]
test_pair_with_cursor()159     fn test_pair_with_cursor() {
160         let mut buf = [0u8; 8];
161 
162         {
163             use crate::lib::std::io::Cursor;
164 
165             let cursor = Cursor::new(&mut buf[..]);
166             let serializer = pair(string("1234"), string("5678"));
167 
168             let cursor = gen_simple(serializer, cursor).unwrap();
169             assert_eq!(cursor.position(), 8);
170         }
171 
172         assert_eq!(&buf[..], b"12345678");
173     }
174 
175     #[test]
test_tuple()176     fn test_tuple() {
177         let mut buf = [0u8; 12];
178 
179         {
180             use crate::lib::std::io::Cursor;
181 
182             let cursor = Cursor::new(&mut buf[..]);
183             let serializer = tuple((string("1234"), string("5678"), tuple((string("0123"),))));
184 
185             let cursor = gen_simple(serializer, cursor).unwrap();
186             assert_eq!(cursor.position(), 12);
187         }
188 
189         assert_eq!(&buf[..], b"123456780123");
190     }
191 }
192