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
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::types::*;

use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Enumeration referencing the possible AMQP values depending on the types
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPValue {
    /// A bool
    Boolean(Boolean),
    /// An i8
    ShortShortInt(ShortShortInt),
    /// A u8
    ShortShortUInt(ShortShortUInt),
    /// An i16
    ShortInt(ShortInt),
    /// A u16
    ShortUInt(ShortUInt),
    /// An i32
    LongInt(LongInt),
    /// A u32
    LongUInt(LongUInt),
    /// An i64
    LongLongInt(LongLongInt),
    /// An f32
    Float(Float),
    /// An f64
    Double(Double),
    /// A decimal value
    DecimalValue(DecimalValue),
    /// A String (deprecated)
    ShortString(ShortString),
    /// A String
    LongString(LongString),
    /// An array of AMQPValue
    FieldArray(FieldArray),
    /// A timestamp (u32)
    Timestamp(Timestamp),
    /// A Map<String, AMQPValue>
    FieldTable(FieldTable),
    /// An array of bytes (RabbitMQ speicific)
    ByteArray(ByteArray),
    /// No value
    Void,
}

impl AMQPValue {
    /// Get the AMQPType of an AMQPValue
    pub fn get_type(&self) -> AMQPType {
        match *self {
            AMQPValue::Boolean(_)        => AMQPType::Boolean,
            AMQPValue::ShortShortInt(_)  => AMQPType::ShortShortInt,
            AMQPValue::ShortShortUInt(_) => AMQPType::ShortShortUInt,
            AMQPValue::ShortInt(_)       => AMQPType::ShortInt,
            AMQPValue::ShortUInt(_)      => AMQPType::ShortUInt,
            AMQPValue::LongInt(_)        => AMQPType::LongInt,
            AMQPValue::LongUInt(_)       => AMQPType::LongUInt,
            AMQPValue::LongLongInt(_)    => AMQPType::LongLongInt,
            AMQPValue::Float(_)          => AMQPType::Float,
            AMQPValue::Double(_)         => AMQPType::Double,
            AMQPValue::DecimalValue(_)   => AMQPType::DecimalValue,
            AMQPValue::ShortString(_)    => AMQPType::ShortString,
            AMQPValue::LongString(_)     => AMQPType::LongString,
            AMQPValue::FieldArray(_)     => AMQPType::FieldArray,
            AMQPValue::Timestamp(_)      => AMQPType::Timestamp,
            AMQPValue::FieldTable(_)     => AMQPType::FieldTable,
            AMQPValue::ByteArray(_)      => AMQPType::ByteArray,
            AMQPValue::Void              => AMQPType::Void,
        }
    }

    /// Convert a serde_json::Value into an AMQPValue
    pub fn try_from(value: &Value, amqp_type: AMQPType) -> Option<AMQPValue> {
        match amqp_type {
            AMQPType::Boolean        => value.as_bool().map(AMQPValue::Boolean),
            AMQPType::ShortShortInt  => value.as_i64().map(|i| AMQPValue::ShortShortInt(i as ShortShortInt)),
            AMQPType::ShortShortUInt => value.as_u64().map(|u| AMQPValue::ShortShortUInt(u as ShortShortUInt)),
            AMQPType::ShortInt       => value.as_i64().map(|i| AMQPValue::ShortInt(i as ShortInt)),
            AMQPType::ShortUInt      => value.as_u64().map(|u| AMQPValue::ShortUInt(u as ShortUInt)),
            AMQPType::LongInt        => value.as_i64().map(|i| AMQPValue::LongInt(i as LongInt)),
            AMQPType::LongUInt       => value.as_u64().map(|u| AMQPValue::LongUInt(u as LongUInt)),
            AMQPType::LongLongInt    => value.as_i64().map(|i| AMQPValue::LongLongInt(i as LongLongInt)),
            AMQPType::LongLongUInt   => value.as_i64().map(|i| AMQPValue::LongLongInt(i as LongLongInt)), /* Not a typo; AMQPValue::LongLongUInt doesn't exist */
            AMQPType::Float          => value.as_f64().map(|i| AMQPValue::Float(i as Float)),
            AMQPType::Double         => value.as_f64().map(|i| AMQPValue::Double(i as Double)),
            AMQPType::DecimalValue   => None,
            AMQPType::ShortString    => value.as_str().map(ShortString::from).map(AMQPValue::ShortString),
            AMQPType::LongString     => value.as_str().map(LongString::from).map(AMQPValue::LongString),
            AMQPType::FieldArray     => None,
            AMQPType::Timestamp      => value.as_u64().map(|t| AMQPValue::Timestamp(t as Timestamp)),
            AMQPType::FieldTable     => None,
            AMQPType::ByteArray      => None,
            AMQPType::Void           => value.as_null().map(|_| AMQPValue::Void),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    use serde_json::Number;

    #[test]
    fn test_from_bool_value() {
        assert_eq!(AMQPValue::try_from(&Value::Bool(false), AMQPType::Boolean), Some(AMQPValue::Boolean(false)));
        assert_eq!(AMQPValue::try_from(&Value::Bool(true),  AMQPType::Boolean), Some(AMQPValue::Boolean(true)));
    }

    #[test]
    fn test_from_number_value() {
        assert_eq!(AMQPValue::try_from(&Value::Number(Number::from(42)),                 AMQPType::LongLongUInt), Some(AMQPValue::LongLongInt(42)));
        assert_eq!(AMQPValue::try_from(&Value::Number(Number::from(-42)),                AMQPType::LongLongInt),  Some(AMQPValue::LongLongInt(-42)));
        assert_eq!(AMQPValue::try_from(&Value::Number(Number::from_f64(42.42).unwrap()), AMQPType::Double),       Some(AMQPValue::Double(42.42)));
    }

    #[test]
    fn test_from_string_value() {
        assert_eq!(AMQPValue::try_from(&Value::String(String::new()),      AMQPType::LongString), Some(AMQPValue::LongString(LongString::default())));
        assert_eq!(AMQPValue::try_from(&Value::String("test".to_string()), AMQPType::LongString), Some(AMQPValue::LongString("test".into())));
    }

    #[test]
    fn test_from_null_value() {
        assert_eq!(AMQPValue::try_from(&Value::Null, AMQPType::Void), Some(AMQPValue::Void));
    }
}