Skip to main content

amq_protocol_types/
generation.rs

1/// Serialization types and traits
2pub use cookie_factory::{BackToTheBuffer, GenError, GenResult, SerializeFn};
3
4use crate::{flags::*, types::*, value::*};
5use cookie_factory::{
6    bytes::{be_f32, be_f64, be_i8, be_i16, be_i32, be_i64, be_u8, be_u16, be_u32, be_u64},
7    combinator::{back_to_the_buffer, slice},
8    multi::many_ref,
9    sequence::pair,
10};
11use std::io::Write;
12
13/// Apply a generator and serialize its length at the beginning of buffer
14pub fn gen_with_len<W: Write + BackToTheBuffer, F: SerializeFn<W>>(f: F) -> impl SerializeFn<W> {
15    back_to_the_buffer(
16        4,
17        move |x| {
18            let start = x.position;
19            let x = f(x)?;
20            let len = x.position - start;
21            Ok((x, len))
22        },
23        move |x, len| gen_long_uint(len as LongUInt)(x),
24    )
25}
26
27/// Generate the [AMQPValue](../type.AMQPValue.html) in the given buffer (x)
28#[must_use]
29pub fn gen_raw_value<'a, W: Write + BackToTheBuffer + 'a>(
30    v: &'a AMQPValue,
31) -> impl SerializeFn<W> + 'a {
32    move |x| match *v {
33        AMQPValue::Boolean(b) => gen_boolean(b)(x),
34        AMQPValue::ShortShortInt(i) => gen_short_short_int(i)(x),
35        AMQPValue::ShortShortUInt(u) => gen_short_short_uint(u)(x),
36        AMQPValue::ShortInt(i) => gen_short_int(i)(x),
37        AMQPValue::ShortUInt(u) => gen_short_uint(u)(x),
38        AMQPValue::LongInt(i) => gen_long_int(i)(x),
39        AMQPValue::LongUInt(u) => gen_long_uint(u)(x),
40        AMQPValue::LongLongInt(i) => gen_long_long_int(i)(x),
41        AMQPValue::Float(f) => gen_float(f)(x),
42        AMQPValue::Double(d) => gen_double(d)(x),
43        AMQPValue::DecimalValue(d) => gen_decimal_value(d)(x),
44        AMQPValue::ShortString(ref s) => gen_short_string(s.as_str())(x),
45        AMQPValue::LongString(ref s) => gen_long_string(s.as_bytes())(x),
46        AMQPValue::FieldArray(ref a) => gen_field_array(a)(x),
47        AMQPValue::Timestamp(t) => gen_timestamp(t)(x),
48        AMQPValue::FieldTable(ref t) => gen_field_table(t)(x),
49        AMQPValue::ByteArray(ref a) => gen_byte_array(a)(x),
50        AMQPValue::Void => Ok(x),
51    }
52}
53
54/// Generate the [AMQPValue](../type.AMQPValue.html) preceded with its [AMQPType](../type.AMQPType.html) in the given buffer (x)
55#[must_use]
56pub fn gen_value<'a, W: Write + BackToTheBuffer + 'a>(
57    v: &'a AMQPValue,
58) -> impl SerializeFn<W> + 'a {
59    pair(gen_type(v.get_type()), gen_raw_value(v))
60}
61
62/// Generate the [AMQPType](../type.AMQPType.html) in the given buffer (x)
63#[must_use]
64pub fn gen_type<W: Write>(t: AMQPType) -> impl SerializeFn<W> {
65    gen_short_short_uint(t.get_id() as ShortShortUInt)
66}
67
68/// Generate the id ([ShortUInt](../type.ShortUInt.html)) in the given buffer (x)
69#[must_use]
70pub fn gen_id<W: Write>(id: ShortUInt) -> impl SerializeFn<W> {
71    gen_short_uint(id)
72}
73
74/// Generate the [Boolean](../type.Boolean.html) in the given buffer (x)
75#[must_use]
76pub fn gen_boolean<W: Write>(b: Boolean) -> impl SerializeFn<W> {
77    gen_short_short_uint(if b { 1 } else { 0 })
78}
79
80/// Generate the [ShortShortInt](../type.ShortShortInt.html) in the given buffer (x)
81#[must_use]
82pub fn gen_short_short_int<W: Write>(i: ShortShortInt) -> impl SerializeFn<W> {
83    be_i8(i)
84}
85
86/// Generate the [ShortShortUInt](../type.ShortShortUInt.html) in the given buffer (x)
87#[must_use]
88pub fn gen_short_short_uint<W: Write>(u: ShortShortUInt) -> impl SerializeFn<W> {
89    be_u8(u)
90}
91
92/// Generate the [ShortInt](../type.ShortInt.html) in the given buffer (x)
93#[must_use]
94pub fn gen_short_int<W: Write>(i: ShortInt) -> impl SerializeFn<W> {
95    be_i16(i)
96}
97
98/// Generate the [ShortUInt](../type.ShortUInt.html) in the given buffer (x)
99#[must_use]
100pub fn gen_short_uint<W: Write>(u: ShortUInt) -> impl SerializeFn<W> {
101    be_u16(u)
102}
103
104/// Generate the [LongInt](../type.LongInt.html) in the given buffer (x)
105#[must_use]
106pub fn gen_long_int<W: Write>(i: LongInt) -> impl SerializeFn<W> {
107    be_i32(i)
108}
109
110/// Generate the [LongUInt](../type.LongUInt.html) in the given buffer (x)
111#[must_use]
112pub fn gen_long_uint<W: Write>(u: LongUInt) -> impl SerializeFn<W> {
113    be_u32(u)
114}
115
116/// Generate the [LongLongInt](../type.LongLongInt.html) in the given buffer (x)
117#[must_use]
118pub fn gen_long_long_int<W: Write>(i: LongLongInt) -> impl SerializeFn<W> {
119    be_i64(i)
120}
121
122/// Generate the [LongLongUInt](../type.LongLongUInt.html) in the given buffer (x)
123#[must_use]
124pub fn gen_long_long_uint<W: Write>(u: LongLongUInt) -> impl SerializeFn<W> {
125    be_u64(u)
126}
127
128/// Generate the [Float](../type.Float.html) in the given buffer (x)
129#[must_use]
130pub fn gen_float<W: Write>(f: Float) -> impl SerializeFn<W> {
131    be_f32(f)
132}
133
134/// Generate the [Double](../type.Double.html) in the given buffer (x)
135#[must_use]
136pub fn gen_double<W: Write>(d: Double) -> impl SerializeFn<W> {
137    be_f64(d)
138}
139
140/// Generate the [DecimalValue](../type.DecimalValue.html) in the given buffer (x)
141#[must_use]
142pub fn gen_decimal_value<W: Write>(d: DecimalValue) -> impl SerializeFn<W> {
143    pair(gen_short_short_uint(d.scale), gen_long_uint(d.value))
144}
145
146/// Generate the [ShortString](../type.ShortString.html) in the given buffer (x)
147#[must_use]
148pub fn gen_short_string<'a, W: Write + 'a>(s: &'a str) -> impl SerializeFn<W> + 'a {
149    debug_assert!(
150        s.len() <= ShortShortUInt::MAX as usize,
151        "short string exceeds 255 bytes"
152    );
153    pair(
154        gen_short_short_uint(s.len() as ShortShortUInt),
155        slice(s.as_bytes()),
156    )
157}
158
159/// Generate the [LongString](../type.LongString.html) in the given buffer (x)
160#[must_use]
161pub fn gen_long_string<'a, W: Write + 'a>(s: &'a [u8]) -> impl SerializeFn<W> + 'a {
162    debug_assert!(
163        s.len() <= LongUInt::MAX as usize,
164        "long string exceeds 4 GiB"
165    );
166    pair(gen_long_uint(s.len() as LongUInt), slice(s))
167}
168
169/// Generate the [FieldArray](../type.FieldArray.html) in the given buffer (x)
170#[must_use]
171pub fn gen_field_array<'a, W: Write + BackToTheBuffer + 'a>(
172    a: &'a FieldArray,
173) -> impl SerializeFn<W> + 'a {
174    gen_with_len(many_ref(a.as_slice(), move |field| gen_value(field)))
175}
176
177/// Generate the [Timestamp](../type.Timestamp.html) in the given buffer (x)
178#[must_use]
179pub fn gen_timestamp<W: Write>(t: Timestamp) -> impl SerializeFn<W> {
180    gen_long_long_uint(t)
181}
182
183/// Generate the [FieldTable](../type.FieldTable.html) in the given buffer (x)
184pub fn gen_field_table<'a, W: Write + BackToTheBuffer + 'a>(
185    t: &'a FieldTable,
186) -> impl SerializeFn<W> + 'a {
187    gen_with_len(many_ref(t, gen_field_entry))
188}
189
190fn gen_field_entry<'a, W: Write + BackToTheBuffer + 'a>(
191    e: (&'a ShortString, &'a AMQPValue),
192) -> impl SerializeFn<W> + 'a {
193    pair(gen_short_string(e.0.as_str()), gen_value(e.1))
194}
195
196/// Generate the [ByteArray](../type.ByteArray.html) in the given buffer (x)
197#[must_use]
198pub fn gen_byte_array<'a, W: Write + 'a>(a: &'a ByteArray) -> impl SerializeFn<W> + 'a {
199    debug_assert!(
200        a.len() <= LongUInt::MAX as usize,
201        "byte array exceeds 4 GiB"
202    );
203    pair(gen_long_uint(a.len() as LongUInt), slice(a.as_slice()))
204}
205
206/// Generate the [AMQPFlags](../type.AMQPFlags.html) in the given buffer (x)
207#[must_use]
208pub fn gen_flags<'a, W: Write + 'a>(f: &'a AMQPFlags) -> impl SerializeFn<W> + 'a {
209    move |x| {
210        f.get_bytes()
211            .iter()
212            .try_fold(x, |acc, b| gen_short_short_uint(*b)(acc))
213    }
214}
215
216#[cfg(test)]
217mod test {
218    use super::*;
219
220    use cookie_factory::r#gen as cf_gen;
221
222    macro_rules! test_gen (
223        ($buf: expr, $gen: ident, $val: expr) => ({
224            let buf = $buf;
225            let len = cf_gen($gen($val), &mut buf[..]).map(|t| t.1);
226            match len {
227                Err(e)  => Err(format!("{:?}", e)),
228                Ok(len) => Ok((buf.to_vec(), len)),
229            }
230        });
231    );
232
233    #[test]
234    fn test_gen_raw_value() {
235        assert_eq!(
236            test_gen!(
237                &mut [0, 0, 0, 0][..],
238                gen_raw_value,
239                &AMQPValue::LongInt(42)
240            ),
241            Ok((vec![0, 0, 0, 42], 4))
242        );
243        assert_eq!(
244            test_gen!(&mut [0][..], gen_raw_value, &AMQPValue::Boolean(true)),
245            Ok((vec![1], 1))
246        );
247    }
248
249    #[test]
250    fn test_gen_value() {
251        assert_eq!(
252            test_gen!(&mut [0, 0, 0, 0, 0][..], gen_value, &AMQPValue::LongInt(42)),
253            Ok((vec![73, 0, 0, 0, 42], 5))
254        );
255        assert_eq!(
256            test_gen!(&mut [0, 0][..], gen_value, &AMQPValue::Boolean(true)),
257            Ok((vec![116, 1], 2))
258        );
259    }
260
261    #[test]
262    fn test_gen_type() {
263        assert_eq!(
264            test_gen!(&mut [0][..], gen_type, AMQPType::ShortShortInt),
265            Ok((vec![98], 1))
266        );
267        assert_eq!(
268            test_gen!(&mut [0][..], gen_type, AMQPType::ShortInt),
269            Ok((vec![115], 1))
270        );
271    }
272
273    #[test]
274    fn test_gen_id() {
275        assert_eq!(test_gen!(&mut [0, 0][..], gen_id, 0), Ok((vec![0, 0], 2)));
276        assert_eq!(
277            test_gen!(&mut [0, 0][..], gen_id, 65535),
278            Ok((vec![255, 255], 2))
279        );
280    }
281
282    #[test]
283    fn test_gen_boolean() {
284        assert_eq!(
285            test_gen!(&mut [0][..], gen_boolean, false),
286            Ok((vec![0], 1))
287        );
288        assert_eq!(test_gen!(&mut [0][..], gen_boolean, true), Ok((vec![1], 1)));
289    }
290
291    #[test]
292    fn test_gen_short_short_int() {
293        assert_eq!(
294            test_gen!(&mut [0][..], gen_short_short_int, 0),
295            Ok((vec![0], 1))
296        );
297        assert_eq!(
298            test_gen!(&mut [0][..], gen_short_short_int, -1),
299            Ok((vec![255], 1))
300        );
301    }
302
303    #[test]
304    fn test_gen_short_short_uint() {
305        assert_eq!(
306            test_gen!(&mut [0][..], gen_short_short_uint, 0),
307            Ok((vec![0], 1))
308        );
309        assert_eq!(
310            test_gen!(&mut [0][..], gen_short_short_uint, 255),
311            Ok((vec![255], 1))
312        );
313    }
314
315    #[test]
316    fn test_gen_short_int() {
317        assert_eq!(
318            test_gen!(&mut [0, 0][..], gen_short_int, 0),
319            Ok((vec![0, 0], 2))
320        );
321        assert_eq!(
322            test_gen!(&mut [0, 0][..], gen_short_int, -1),
323            Ok((vec![255, 255], 2))
324        );
325    }
326
327    #[test]
328    fn test_gen_short_uint() {
329        assert_eq!(
330            test_gen!(&mut [0, 0][..], gen_short_uint, 0),
331            Ok((vec![0, 0], 2))
332        );
333        assert_eq!(
334            test_gen!(&mut [0, 0][..], gen_short_uint, 65535),
335            Ok((vec![255, 255], 2))
336        );
337    }
338
339    #[test]
340    fn test_gen_long_int() {
341        assert_eq!(
342            test_gen!(&mut [0, 0, 0, 0][..], gen_long_int, 0),
343            Ok((vec![0, 0, 0, 0], 4))
344        );
345        assert_eq!(
346            test_gen!(&mut [0, 0, 0, 0][..], gen_long_int, -1),
347            Ok((vec![255, 255, 255, 255], 4))
348        );
349    }
350
351    #[test]
352    fn test_gen_long_uint() {
353        assert_eq!(
354            test_gen!(&mut [0, 0, 0, 0][..], gen_long_uint, 0),
355            Ok((vec![0, 0, 0, 0], 4))
356        );
357        assert_eq!(
358            test_gen!(&mut [0, 0, 0, 0][..], gen_long_uint, 4294967295),
359            Ok((vec![255, 255, 255, 255], 4))
360        );
361    }
362
363    #[test]
364    fn test_gen_long_long_int() {
365        assert_eq!(
366            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_long_long_int, 0),
367            Ok((vec![0, 0, 0, 0, 0, 0, 0, 0], 8))
368        );
369        assert_eq!(
370            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_long_long_int, -1),
371            Ok((vec![255, 255, 255, 255, 255, 255, 255, 255], 8))
372        );
373    }
374
375    #[test]
376    fn test_gen_long_long_uint() {
377        assert_eq!(
378            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_long_long_uint, 0),
379            Ok((vec![0, 0, 0, 0, 0, 0, 0, 0], 8))
380        );
381        assert_eq!(
382            test_gen!(
383                &mut [0, 0, 0, 0, 0, 0, 0, 0][..],
384                gen_long_long_uint,
385                18446744073709551615
386            ),
387            Ok((vec![255, 255, 255, 255, 255, 255, 255, 255], 8))
388        );
389    }
390
391    #[test]
392    fn test_gen_float() {
393        assert_eq!(
394            test_gen!(&mut [0, 0, 0, 0][..], gen_float, 0.),
395            Ok((vec![0, 0, 0, 0], 4))
396        );
397        assert_eq!(
398            test_gen!(&mut [0, 0, 0, 0][..], gen_float, 42.42),
399            Ok((vec![66, 41, 174, 20], 4))
400        );
401    }
402
403    #[test]
404    fn test_gen_double() {
405        assert_eq!(
406            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_double, 0.),
407            Ok((vec![0, 0, 0, 0, 0, 0, 0, 0], 8))
408        );
409        assert_eq!(
410            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_double, 42.42),
411            Ok((vec![64, 69, 53, 194, 143, 92, 40, 246], 8))
412        );
413    }
414
415    #[test]
416    fn test_gen_decimal_value() {
417        assert_eq!(
418            test_gen!(
419                &mut [0, 0, 0, 0, 0][..],
420                gen_decimal_value,
421                DecimalValue { scale: 0, value: 0 }
422            ),
423            Ok((vec![0, 0, 0, 0, 0], 5))
424        );
425        assert_eq!(
426            test_gen!(
427                &mut [0, 0, 0, 0, 0][..],
428                gen_decimal_value,
429                DecimalValue {
430                    scale: 2,
431                    value: 42
432                }
433            ),
434            Ok((vec![2, 0, 0, 0, 42], 5))
435        );
436    }
437
438    #[test]
439    fn test_gen_short_string() {
440        assert_eq!(
441            test_gen!(&mut [0][..], gen_short_string, ""),
442            Ok((vec![0], 1))
443        );
444        assert_eq!(
445            test_gen!(&mut [0, 0, 0, 0, 0][..], gen_short_string, "test"),
446            Ok((vec![4, 116, 101, 115, 116], 5))
447        );
448    }
449
450    #[test]
451    fn test_gen_long_string() {
452        assert_eq!(
453            test_gen!(&mut [0, 0, 0, 0][..], gen_long_string, &[]),
454            Ok((vec![0, 0, 0, 0], 4))
455        );
456        assert_eq!(
457            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_long_string, b"test"),
458            Ok((vec![0, 0, 0, 4, 116, 101, 115, 116], 8))
459        );
460    }
461
462    #[test]
463    fn test_gen_field_array() {
464        assert_eq!(
465            test_gen!(
466                &mut [0, 0, 0, 0][..],
467                gen_field_array,
468                &FieldArray::default()
469            ),
470            Ok((vec![0, 0, 0, 0], 4))
471        );
472        assert_eq!(
473            test_gen!(
474                &mut [0, 0, 0, 0, 0, 0][..],
475                gen_field_array,
476                &vec![AMQPValue::Boolean(true)].into()
477            ),
478            Ok((vec![0, 0, 0, 2, 116, 1], 6))
479        );
480    }
481
482    #[test]
483    fn test_gen_timestamp() {
484        assert_eq!(
485            test_gen!(&mut [0, 0, 0, 0, 0, 0, 0, 0][..], gen_timestamp, 0),
486            Ok((vec![0, 0, 0, 0, 0, 0, 0, 0], 8))
487        );
488        assert_eq!(
489            test_gen!(
490                &mut [0, 0, 0, 0, 0, 0, 0, 0][..],
491                gen_timestamp,
492                18446744073709551615
493            ),
494            Ok((vec![255, 255, 255, 255, 255, 255, 255, 255], 8))
495        );
496    }
497
498    #[test]
499    fn test_gen_field_table() {
500        let mut table = FieldTable::default();
501        table.insert("test".into(), AMQPValue::Float(42.42));
502        table.insert("test2".into(), AMQPValue::Boolean(false));
503        assert_eq!(
504            test_gen!(
505                &mut [0, 0, 0, 0][..],
506                gen_field_table,
507                &FieldTable::default()
508            ),
509            Ok((vec![0, 0, 0, 0], 4))
510        );
511        assert_eq!(
512            test_gen!(
513                &mut [
514                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
515                ][..],
516                gen_field_table,
517                &table
518            ),
519            Ok((
520                vec![
521                    0, 0, 0, 18, 4, 116, 101, 115, 116, 102, 66, 41, 174, 20, 5, 116, 101, 115,
522                    116, 50, 116, 0
523                ],
524                22
525            ))
526        );
527    }
528
529    #[test]
530    fn test_gen_byte_array() {
531        assert_eq!(
532            test_gen!(&mut [0, 0, 0, 0][..], gen_byte_array, &ByteArray::default()),
533            Ok((vec![0, 0, 0, 0], 4))
534        );
535        assert_eq!(
536            test_gen!(
537                &mut [0, 0, 0, 0, 0, 0, 0, 0][..],
538                gen_byte_array,
539                &vec![42, 1, 2, 3].into()
540            ),
541            Ok((vec![0, 0, 0, 4, 42, 1, 2, 3], 8))
542        );
543    }
544
545    #[test]
546    fn test_gen_flags() {
547        let mut flags = AMQPFlags::default();
548        flags.add_flag("a".to_string(), true);
549        flags.add_flag("b".to_string(), false);
550        flags.add_flag("c".to_string(), true);
551        flags.add_flag("d".to_string(), true);
552        assert_eq!(
553            test_gen!(&mut [0][..], gen_flags, &flags),
554            Ok((vec![0b00001101], 1))
555        );
556        flags.add_flag("e".to_string(), true);
557        flags.add_flag("f".to_string(), false);
558        flags.add_flag("g".to_string(), true);
559        flags.add_flag("h".to_string(), true);
560        flags.add_flag("i".to_string(), false);
561        flags.add_flag("j".to_string(), true);
562        assert_eq!(
563            test_gen!(&mut [0, 0][..], gen_flags, &flags),
564            Ok((vec![0b11011101, 0b00000010], 2))
565        );
566    }
567}