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