cookie_factory/
combinator.rs

1//! basic serializers
2use crate::internal::*;
3use crate::lib::std::io::Write;
4
5macro_rules! try_write(($out:ident, $len:ident, $data:expr) => (
6    match $out.write($data) {
7        Err(io)           => Err(GenError::IoError(io)),
8        Ok(n) if n < $len => Err(GenError::BufferTooSmall($len - n)),
9        Ok(_)             => Ok($out)
10    }
11));
12
13/// Writes a byte slice to the output
14///
15/// ```rust
16/// use cookie_factory::{gen, combinator::slice};
17///
18/// let mut buf = [0u8; 100];
19///
20/// {
21///   let (buf, pos) = gen(slice(&b"abcd"[..]), &mut buf[..]).unwrap();
22///   assert_eq!(pos, 4);
23///   assert_eq!(buf.len(), 100 - 4);
24/// }
25///
26/// assert_eq!(&buf[..4], &b"abcd"[..]);
27/// ```
28pub fn slice<S: AsRef<[u8]>, W: Write>(data: S) -> impl SerializeFn<W> {
29    let len = data.as_ref().len();
30
31    move |mut out: WriteContext<W>| try_write!(out, len, data.as_ref())
32}
33
34/// Writes a string slice to the output
35///
36/// ```rust
37/// use cookie_factory::{gen, combinator::string};
38///
39/// let mut buf = [0u8; 100];
40///
41/// {
42///   let (buf, pos) = gen(string("abcd"), &mut buf[..]).unwrap();
43///   assert_eq!(pos, 4);
44///   assert_eq!(buf.len(), 100 - 4);
45/// }
46///
47/// assert_eq!(&buf[..4], &b"abcd"[..]);
48/// ```
49pub fn string<S: AsRef<str>, W: Write>(data: S) -> impl SerializeFn<W> {
50    let len = data.as_ref().len();
51
52    move |mut out: WriteContext<W>| try_write!(out, len, data.as_ref().as_bytes())
53}
54
55/// Writes an hex string to the output
56#[cfg(feature = "std")]
57/// ```rust
58/// use cookie_factory::{gen, combinator::hex};
59///
60/// let mut buf = [0u8; 100];
61///
62/// {
63///   let (buf, pos) = gen(hex(0x2A), &mut buf[..]).unwrap();
64///   assert_eq!(pos, 2);
65///   assert_eq!(buf.len(), 100 - 2);
66/// }
67///
68/// assert_eq!(&buf[..2], &b"2A"[..]);
69/// ```
70pub fn hex<S: crate::lib::std::fmt::UpperHex, W: Write>(data: S) -> impl SerializeFn<W> {
71    move |mut out: WriteContext<W>| match write!(out, "{:X}", data) {
72        Err(io) => Err(GenError::IoError(io)),
73        Ok(()) => Ok(out),
74    }
75}
76
77/// Skips over some input bytes without writing anything
78///
79/// ```rust
80/// use cookie_factory::{gen, combinator::skip};
81///
82/// let mut buf = [0u8; 100];
83///
84/// let (out, pos) = gen(skip(2), &mut buf[..]).unwrap();
85///
86/// assert_eq!(pos, 2);
87/// assert_eq!(out.len(), 98);
88/// ```
89pub fn skip<W: Write + Skip>(len: usize) -> impl SerializeFn<W> {
90    move |out: WriteContext<W>| W::skip(out, len)
91}
92
93/// Applies a serializer if the condition is true
94///
95/// ```rust
96/// use cookie_factory::{gen, combinator::{cond, string}};
97///
98/// let mut buf = [0u8; 100];
99///
100/// {
101///   let (buf, pos) = gen(cond(true, string("abcd")), &mut buf[..]).unwrap();
102///   assert_eq!(pos, 4);
103///   assert_eq!(buf.len(), 100 - 4);
104/// }
105///
106/// assert_eq!(&buf[..4], &b"abcd"[..]);
107/// ```
108pub fn cond<F, W: Write>(condition: bool, f: F) -> impl SerializeFn<W>
109where
110    F: SerializeFn<W>,
111{
112    move |out: WriteContext<W>| {
113        if condition {
114            f(out)
115        } else {
116            Ok(out)
117        }
118    }
119}
120
121/// Reserves space for the `Before` combinator, applies the `Gen` combinator,
122/// then applies the `Before` combinator with the output from `Gen` onto the
123/// reserved space.
124///
125/// ```rust
126/// use cookie_factory::{gen, gen_simple, sequence::tuple, combinator::{back_to_the_buffer, string}, bytes::be_u8, bytes::be_u32};
127///
128/// let mut buf = [0; 9];
129/// gen_simple(tuple((
130///     back_to_the_buffer(
131///         4,
132///         move |buf| gen(string("test"), buf),
133///         move |buf, len| gen_simple(be_u32(len as u32), buf)
134///     ),
135///     be_u8(42)
136/// )), &mut buf[..]).unwrap();
137/// assert_eq!(&buf, &[0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8, 42]);
138/// ```
139pub fn back_to_the_buffer<W: BackToTheBuffer, Tmp, Gen, Before>(
140    reserved: usize,
141    gen: Gen,
142    before: Before,
143) -> impl SerializeFn<W>
144where
145    Gen: Fn(WriteContext<W>) -> Result<(WriteContext<W>, Tmp), GenError>,
146    Before: Fn(WriteContext<W>, Tmp) -> GenResult<W>,
147{
148    move |w: WriteContext<W>| W::reserve_write_use(w, reserved, &gen, &before)
149}
150
151//missing combinators:
152//or
153//empty
154//then
155//stream
156//length_value
157//text print
158//text upperhex
159//text lowerhex
160
161#[cfg(test)]
162mod test {
163    use super::*;
164    use crate::bytes::{be_u32, be_u8};
165    use crate::sequence::tuple;
166
167    #[test]
168    fn test_gen_with_length() {
169        let mut buf = [0; 8];
170        {
171            let (len_buf, buf) = buf.split_at_mut(4);
172            let (_, pos) = gen(string("test"), buf).unwrap();
173            gen(be_u32(pos as u32), len_buf).unwrap();
174        }
175        assert_eq!(&buf, &[0, 0, 0, 4, b't', b'e', b's', b't']);
176    }
177
178    #[test]
179    fn test_back_to_the_buffer() {
180        let mut buf = [0; 9];
181
182        let new_buf = gen_simple(
183            tuple((
184                back_to_the_buffer(
185                    4,
186                    move |buf| gen(string("test"), buf),
187                    move |buf, len| gen_simple(be_u32(len as u32), buf),
188                ),
189                be_u8(42),
190            )),
191            &mut buf[..],
192        )
193        .unwrap();
194
195        assert!(new_buf.is_empty());
196        assert_eq!(&buf, &[0, 0, 0, 4, b't', b'e', b's', b't', 42]);
197    }
198
199    #[cfg(feature = "std")]
200    #[test]
201    fn test_back_to_the_buffer_vec() {
202        let buf = Vec::new();
203
204        let buf = gen_simple(
205            tuple((
206                back_to_the_buffer(
207                    4,
208                    move |buf| gen(string("test"), buf),
209                    move |buf, len| gen_simple(be_u32(len as u32), buf),
210                ),
211                be_u8(42),
212            )),
213            buf,
214        )
215        .unwrap();
216
217        assert_eq!(&buf[..], &[0, 0, 0, 4, b't', b'e', b's', b't', 42]);
218    }
219
220    #[test]
221    fn test_back_to_the_buffer_cursor() {
222        let mut buf = [0; 9];
223        {
224            let cursor = crate::lib::std::io::Cursor::new(&mut buf[..]);
225            let cursor = gen_simple(
226                tuple((
227                    back_to_the_buffer(
228                        4,
229                        move |buf| gen(string("test"), buf),
230                        move |buf, len| gen_simple(be_u32(len as u32), buf),
231                    ),
232                    be_u8(42),
233                )),
234                cursor,
235            )
236            .unwrap();
237            assert_eq!(cursor.position(), 9);
238        }
239        assert_eq!(&buf, &[0, 0, 0, 4, b't', b'e', b's', b't', 42]);
240    }
241
242    #[test]
243    fn test_back_to_the_buffer_cursor_counter() {
244        let mut buf = [0; 10];
245        {
246            let cursor = crate::lib::std::io::Cursor::new(&mut buf[..]);
247            let (cursor, pos) = gen(
248                tuple((
249                    be_u8(64),
250                    back_to_the_buffer(
251                        4,
252                        &move |buf| gen(string("test"), buf),
253                        &move |buf, len| gen_simple(be_u32(len as u32), buf),
254                    ),
255                    be_u8(42),
256                )),
257                cursor,
258            )
259            .unwrap();
260            assert_eq!(pos, 10);
261            assert_eq!(cursor.position(), 10);
262        }
263        assert_eq!(&buf, &[64, 0, 0, 0, 4, b't', b'e', b's', b't', 42]);
264    }
265}