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
use super::primitives::ULong;
use super::symbol::Symbol;
use crate::message::amqp::codec::constants::TypeCode;
use crate::message::amqp::codec::{AmqpDecoder, AmqpEncoder};
use crate::message::amqp::error::{AmqpDecodeError, AmqpEncodeError};
use crate::utils::TupleMapperSecond;

#[cfg(test)]
use fake::Fake;

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
#[cfg_attr(test, derive(fake::Dummy))]
pub enum Descriptor {
    Ulong(u64),
    Symbol(Symbol),
}

impl AmqpEncoder for Descriptor {
    fn encoded_size(&self) -> u32 {
        match *self {
            Descriptor::Ulong(v) => 1 + v.encoded_size(),
            Descriptor::Symbol(ref v) => 1 + v.encoded_size(),
        }
    }

    fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), AmqpEncodeError> {
        TypeCode::Described.encode(writer)?;
        match *self {
            Descriptor::Ulong(v) => v.encode(writer),
            Descriptor::Symbol(ref v) => v.encode(writer),
        }
    }
}

impl AmqpDecoder for Descriptor {
    fn decode(input: &[u8]) -> Result<(&[u8], Self), AmqpDecodeError> {
        match TypeCode::decode(input)? {
            (input, TypeCode::Described) => {
                let (remaining, code) = TypeCode::decode(input)?;
                match code {
                    TypeCode::ULong | TypeCode::ULongSmall => {
                        ULong::decode(input).map_second(Descriptor::Ulong)
                    }
                    TypeCode::ULong0 => Ok((remaining, Descriptor::Ulong(0))),
                    TypeCode::Symbol8 | TypeCode::Symbol32 => {
                        Symbol::decode(input).map_second(Descriptor::Symbol)
                    }
                    _ => Err(Self::invalid_type_code(code)),
                }
            }
            (_, code) => Err(Self::invalid_type_code(code)),
        }
    }
}