1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use frame::*;
use protocol::*;
use types::parsing::*;

use nom::IResult;

named!(pub parse_channel<AMQPChannel>, map!(parse_id, From::from));

named!(pub parse_protocol_header, do_parse!(
    tag!(metadata::NAME.as_bytes())                                                        >>
    tag!(&[0])                                                                             >>
    version: tag!(&[metadata::MAJOR_VERSION, metadata::MINOR_VERSION, metadata::REVISION]) >>
    (version)
));

named!(pub parse_frame_type<AMQPFrameType>, switch!(parse_short_short_uint,
    constants::FRAME_METHOD    => value!(AMQPFrameType::Method) |
    constants::FRAME_HEADER    => value!(AMQPFrameType::Header) |
    constants::FRAME_BODY      => value!(AMQPFrameType::Body)   |
    constants::FRAME_HEARTBEAT => value!(AMQPFrameType::Heartbeat)
));

pub fn parse_frame(i: &[u8]) -> IResult<&[u8], AMQPFrame> {
    let (remaining, raw) = try_parse!(i, parse_raw_frame);
    let (_, frame)       = match raw.frame_type {
        AMQPFrameType::Method    => try_parse!(raw.payload, map!(parse_class,          |m: AMQPClass|         AMQPFrame::Method(raw.channel_id, m))),
        AMQPFrameType::Header    => try_parse!(raw.payload, map!(parse_content_header, |h: AMQPContentHeader| AMQPFrame::Header(raw.channel_id, h.class_id, h))),
        AMQPFrameType::Body      => (remaining, AMQPFrame::Body(raw.channel_id, Vec::from(raw.payload))),
        AMQPFrameType::Heartbeat => (remaining, AMQPFrame::Heartbeat(raw.channel_id)),
    };
    IResult::Done(remaining, frame)
}

named!(pub parse_raw_frame<AMQPRawFrame>, do_parse!(
    frame:   parse_frame_type     >>
    channel: parse_id             >>
    size:    parse_long_uint      >>
    payload: take!(size)          >>
    tag!(&[constants::FRAME_END]) >>
    (AMQPRawFrame {
        frame_type: frame,
        channel_id: channel,
        size:       size,
        payload:    payload,
    })
));

named!(pub parse_content_header<AMQPContentHeader>, do_parse!(
    class:  parse_id             >>
    weight: parse_short_uint     >>
    size:   parse_long_long_uint >>
    flags:  parse_short_uint     >>
    list:   parse_field_table    >>
    (AMQPContentHeader {
        class_id:       class,
        weight:         weight,
        body_size:      size,
        property_flags: flags,
        property_list:  list,
    })
));