ironmq_codec/
lib.rs

1//! Data structures and converter functions for dealing with AMQP frames.
2//!
3//! All the data types are in the `frame` module, the `codec` implements
4//! the encoding and the decoding.
5pub mod codec;
6pub mod frame;
7
8#[macro_use]
9extern crate bitflags;
10
11use std::fmt;
12
13/// Type alias for a sync and send error.
14pub type Error = Box<dyn std::error::Error + Send + Sync>;
15/// Type alias for a simplified Result with Error.
16pub type Result<T> = std::result::Result<T, Error>;
17
18/// Error struct used by the crate.
19#[derive(Debug)]
20pub struct FrameError {
21    pub code: u16,
22    pub message: String,
23}
24
25impl fmt::Display for FrameError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        write!(f, "{:?}", &self)
28    }
29}
30
31impl std::error::Error for FrameError {}
32
33/// Shorthand for making errors with error code and error message.
34///
35/// ```no_run
36/// use ironmq_codec::frame_error;
37/// use ironmq_codec::FrameError;
38/// use ironmq_codec::frame::AMQPValue;
39///
40/// fn as_string(val: AMQPValue) -> Result<String, Box<dyn std::error::Error>> {
41///     if let AMQPValue::SimpleString(s) = val {
42///         return Ok(s.clone())
43///     }
44///
45///     frame_error!(10, "Value cannot be converted to string")
46/// }
47/// ```
48#[macro_export]
49macro_rules! frame_error {
50    ($code:expr, $message:expr) => {
51        ::std::result::Result::Err(Box::new($crate::FrameError {
52            code: $code,
53            message: ::std::string::String::from($message),
54        }))
55    };
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61    use bytes::{Buf, BufMut, BytesMut};
62    use codec::AMQPCodec;
63    use frame::{AMQPFrame, MethodFrameArgs};
64    use tokio_util::codec::Encoder;
65
66    #[test]
67    fn encode_header_frame() {
68        let mut encoder = AMQPCodec {};
69        let mut buf = BytesMut::with_capacity(1024);
70
71        let res = encoder.encode(AMQPFrame::Header, &mut buf);
72
73        assert!(res.is_ok());
74
75        let expected = b"AMQP\x00\x00\x09\x01";
76        let mut current = [0u8; 8];
77
78        buf.copy_to_slice(&mut current[..]);
79
80        assert_eq!(expected, &current);
81    }
82
83    #[test]
84    fn encode_method_frame() {
85        let mut encoder = AMQPCodec {};
86        let mut buf = BytesMut::with_capacity(1024);
87
88        let args = frame::QueueBindArgs {
89            queue_name: "queue".into(),
90            exchange_name: "exchg".into(),
91            routing_key: "key".into(),
92            no_wait: false,
93            args: None
94        };
95
96        let res = encoder.encode(
97            AMQPFrame::Method(0x0205, frame::QUEUE_BIND, MethodFrameArgs::QueueBind(args)),
98            &mut buf,
99        );
100
101        assert!(res.is_ok());
102
103        let frame_header = b"\x01\x02\x05";
104        let class_method = b"\x00\x32\x00\x14";
105
106        let mut argbuf = BytesMut::with_capacity(256);
107        argbuf.put(&class_method[..]);
108        argbuf.put(&b"\x00\x00"[..]);
109        argbuf.put(&b"\x05queue"[..]);
110        argbuf.put(&b"\x05exchg"[..]);
111        argbuf.put(&b"\x03key"[..]);
112        argbuf.put(&b"\x00"[..]);
113        argbuf.put(&b"\x00\x00\x00\x00"[..]);
114
115        let mut expected = BytesMut::with_capacity(256);
116        expected.put(&frame_header[..]);
117        expected.put_u32(argbuf.len() as u32);
118        expected.put(argbuf);
119        expected.put_u8(0xCE);
120
121        assert_eq!(expected, buf);
122    }
123}