Skip to main content

amq_protocol_types/
value.rs

1use crate::types::*;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6/// Enumeration referencing the possible AMQP values depending on the types
7#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
8pub enum AMQPValue {
9    /// A bool
10    Boolean(Boolean),
11    /// An i8
12    ShortShortInt(ShortShortInt),
13    /// A u8
14    ShortShortUInt(ShortShortUInt),
15    /// An i16
16    ShortInt(ShortInt),
17    /// A u16
18    ShortUInt(ShortUInt),
19    /// An i32
20    LongInt(LongInt),
21    /// A u32
22    LongUInt(LongUInt),
23    /// An i64
24    LongLongInt(LongLongInt),
25    /// An f32
26    Float(Float),
27    /// An f64
28    Double(Double),
29    /// A decimal value
30    DecimalValue(DecimalValue),
31    /// A String (deprecated)
32    ShortString(ShortString),
33    /// A String
34    LongString(LongString),
35    /// An array of AMQPValue
36    FieldArray(FieldArray),
37    /// A timestamp (u64)
38    Timestamp(Timestamp),
39    /// A Map<String, AMQPValue>
40    FieldTable(FieldTable),
41    /// An array of bytes (RabbitMQ specific)
42    ByteArray(ByteArray),
43    /// No value
44    Void,
45}
46
47impl AMQPValue {
48    /// Get the AMQPType of an AMQPValue
49    pub fn get_type(&self) -> AMQPType {
50        match *self {
51            AMQPValue::Boolean(_) => AMQPType::Boolean,
52            AMQPValue::ShortShortInt(_) => AMQPType::ShortShortInt,
53            AMQPValue::ShortShortUInt(_) => AMQPType::ShortShortUInt,
54            AMQPValue::ShortInt(_) => AMQPType::ShortInt,
55            AMQPValue::ShortUInt(_) => AMQPType::ShortUInt,
56            AMQPValue::LongInt(_) => AMQPType::LongInt,
57            AMQPValue::LongUInt(_) => AMQPType::LongUInt,
58            AMQPValue::LongLongInt(_) => AMQPType::LongLongInt,
59            AMQPValue::Float(_) => AMQPType::Float,
60            AMQPValue::Double(_) => AMQPType::Double,
61            AMQPValue::DecimalValue(_) => AMQPType::DecimalValue,
62            AMQPValue::ShortString(_) => AMQPType::ShortString,
63            AMQPValue::LongString(_) => AMQPType::LongString,
64            AMQPValue::FieldArray(_) => AMQPType::FieldArray,
65            AMQPValue::Timestamp(_) => AMQPType::Timestamp,
66            AMQPValue::FieldTable(_) => AMQPType::FieldTable,
67            AMQPValue::ByteArray(_) => AMQPType::ByteArray,
68            AMQPValue::Void => AMQPType::Void,
69        }
70    }
71
72    /// Convert a serde_json::Value into an AMQPValue
73    pub fn try_from(value: &Value, amqp_type: AMQPType) -> Option<AMQPValue> {
74        match amqp_type {
75            AMQPType::Boolean => value.as_bool().map(AMQPValue::Boolean),
76            AMQPType::ShortShortInt => value
77                .as_i64()
78                .and_then(|i| ShortShortInt::try_from(i).ok())
79                .map(AMQPValue::ShortShortInt),
80            AMQPType::ShortShortUInt => value
81                .as_u64()
82                .and_then(|u| ShortShortUInt::try_from(u).ok())
83                .map(AMQPValue::ShortShortUInt),
84            AMQPType::ShortInt => value
85                .as_i64()
86                .and_then(|i| ShortInt::try_from(i).ok())
87                .map(AMQPValue::ShortInt),
88            AMQPType::ShortUInt => value
89                .as_u64()
90                .and_then(|u| ShortUInt::try_from(u).ok())
91                .map(AMQPValue::ShortUInt),
92            AMQPType::LongInt => value
93                .as_i64()
94                .and_then(|i| LongInt::try_from(i).ok())
95                .map(AMQPValue::LongInt),
96            AMQPType::LongUInt => value
97                .as_u64()
98                .and_then(|u| LongUInt::try_from(u).ok())
99                .map(AMQPValue::LongUInt),
100            AMQPType::LongLongInt => value
101                .as_i64()
102                .map(|i| AMQPValue::LongLongInt(i as LongLongInt)),
103            AMQPType::LongLongUInt => value
104                .as_u64()
105                .map(|u| AMQPValue::LongLongInt(u as LongLongInt)), /* Not a typo; AMQPValue::LongLongUInt doesn't exist; reinterpret bits as i64 */
106            AMQPType::Float => value.as_f64().map(|i| AMQPValue::Float(i as Float)),
107            AMQPType::Double => value.as_f64().map(|i| AMQPValue::Double(i as Double)),
108            AMQPType::DecimalValue => None,
109            AMQPType::ShortString => value
110                .as_str()
111                .map(ShortString::from)
112                .map(AMQPValue::ShortString),
113            AMQPType::LongString => value
114                .as_str()
115                .map(LongString::from)
116                .map(AMQPValue::LongString),
117            AMQPType::FieldArray => None,
118            AMQPType::Timestamp => value.as_u64().map(|t| AMQPValue::Timestamp(t as Timestamp)),
119            AMQPType::FieldTable => None,
120            AMQPType::ByteArray => None,
121            AMQPType::Void => value.as_null().map(|_| AMQPValue::Void),
122        }
123    }
124
125    /// Returns `Some(())` if this is the `Void` variant, `None` otherwise.
126    pub fn as_void(&self) -> Option<()> {
127        matches!(self, AMQPValue::Void).then_some(())
128    }
129}
130
131macro_rules! amqp_value_getter {
132    ($(#[$meta:meta])* copy $method:ident, $variant:ident, $ty:ty) => {
133        $(#[$meta])*
134        pub fn $method(&self) -> Option<$ty> {
135            match self {
136                AMQPValue::$variant(value) => Some(*value),
137                _ => None,
138            }
139        }
140    };
141    ($(#[$meta:meta])* ref $method:ident, $variant:ident, $ty:ty) => {
142        $(#[$meta])*
143        pub fn $method(&self) -> Option<&$ty> {
144            match self {
145                AMQPValue::$variant(value) => Some(value),
146                _ => None,
147            }
148        }
149    };
150}
151
152impl AMQPValue {
153    amqp_value_getter!(
154        /// If the value is bool, returns associated value. Returns None otherwise.
155        copy as_bool, Boolean, Boolean
156    );
157    amqp_value_getter!(
158        /// If the value is ShortShortInt, returns associated value. Returns None otherwise.
159        copy as_short_short_int, ShortShortInt, ShortShortInt
160    );
161    amqp_value_getter!(
162        /// If the value is ShortShortUInt, returns associated value. Returns None otherwise.
163        copy as_short_short_uint, ShortShortUInt, ShortShortUInt
164    );
165    amqp_value_getter!(
166        /// If the value is ShortInt, returns associated value. Returns None otherwise.
167        copy as_short_int, ShortInt, ShortInt
168    );
169    amqp_value_getter!(
170        /// If the value is ShortUInt, returns associated value. Returns None otherwise.
171        copy as_short_uint, ShortUInt, ShortUInt
172    );
173    amqp_value_getter!(
174        /// If the value is LongInt, returns associated value. Returns None otherwise.
175        copy as_long_int, LongInt, LongInt
176    );
177    amqp_value_getter!(
178        /// If the value is LongUInt, returns associated value. Returns None otherwise.
179        copy as_long_uint, LongUInt, LongUInt
180    );
181    amqp_value_getter!(
182        /// If the value is LongLongInt, returns associated value. Returns None otherwise.
183        copy as_long_long_int, LongLongInt, LongLongInt
184    );
185    amqp_value_getter!(
186        /// If the value is Float, returns associated value. Returns None otherwise.
187        copy as_float, Float, Float
188    );
189    amqp_value_getter!(
190        /// If the value is Double, returns associated value. Returns None otherwise.
191        copy as_double, Double, Double
192    );
193    amqp_value_getter!(
194        /// If the value is DecimalValue, returns associated value. Returns None otherwise.
195        copy as_decimal_value, DecimalValue, DecimalValue
196    );
197    amqp_value_getter!(
198        /// If the value is Timestamp, returns associated value. Returns None otherwise.
199        copy as_timestamp, Timestamp, Timestamp
200    );
201    amqp_value_getter!(
202        /// If the value is ShortString, returns associated value. Returns None otherwise.
203        ref as_short_string, ShortString, ShortString
204    );
205    amqp_value_getter!(
206        /// If the value is LongString, returns associated value. Returns None otherwise.
207        ref as_long_string, LongString, LongString
208    );
209    amqp_value_getter!(
210        /// If the value is FieldArray, returns associated value. Returns None otherwise.
211        ref as_array, FieldArray, FieldArray
212    );
213    amqp_value_getter!(
214        /// If the value is FieldTable, returns associated value. Returns None otherwise.
215        ref as_field_table, FieldTable, FieldTable
216    );
217    amqp_value_getter!(
218        /// If the value is ByteArray, returns associated value. Returns None otherwise.
219        ref as_byte_array, ByteArray, ByteArray
220    );
221}
222
223impl From<Boolean> for AMQPValue {
224    fn from(v: Boolean) -> Self {
225        AMQPValue::Boolean(v)
226    }
227}
228
229impl From<ShortShortInt> for AMQPValue {
230    fn from(v: ShortShortInt) -> Self {
231        AMQPValue::ShortShortInt(v)
232    }
233}
234
235impl From<ShortShortUInt> for AMQPValue {
236    fn from(v: ShortShortUInt) -> Self {
237        AMQPValue::ShortShortUInt(v)
238    }
239}
240
241impl From<ShortInt> for AMQPValue {
242    fn from(v: ShortInt) -> Self {
243        AMQPValue::ShortInt(v)
244    }
245}
246
247impl From<ShortUInt> for AMQPValue {
248    fn from(v: ShortUInt) -> Self {
249        AMQPValue::ShortUInt(v)
250    }
251}
252
253impl From<LongInt> for AMQPValue {
254    fn from(v: LongInt) -> Self {
255        AMQPValue::LongInt(v)
256    }
257}
258
259impl From<LongUInt> for AMQPValue {
260    fn from(v: LongUInt) -> Self {
261        AMQPValue::LongUInt(v)
262    }
263}
264
265impl From<LongLongInt> for AMQPValue {
266    fn from(v: LongLongInt) -> Self {
267        AMQPValue::LongLongInt(v)
268    }
269}
270
271impl From<Float> for AMQPValue {
272    fn from(v: Float) -> Self {
273        AMQPValue::Float(v)
274    }
275}
276
277impl From<Double> for AMQPValue {
278    fn from(v: Double) -> Self {
279        AMQPValue::Double(v)
280    }
281}
282
283impl From<DecimalValue> for AMQPValue {
284    fn from(v: DecimalValue) -> Self {
285        AMQPValue::DecimalValue(v)
286    }
287}
288
289impl From<ShortString> for AMQPValue {
290    fn from(v: ShortString) -> Self {
291        AMQPValue::ShortString(v)
292    }
293}
294
295impl From<LongString> for AMQPValue {
296    fn from(v: LongString) -> Self {
297        AMQPValue::LongString(v)
298    }
299}
300
301impl From<FieldArray> for AMQPValue {
302    fn from(v: FieldArray) -> Self {
303        AMQPValue::FieldArray(v)
304    }
305}
306
307impl From<Timestamp> for AMQPValue {
308    fn from(v: Timestamp) -> Self {
309        AMQPValue::Timestamp(v)
310    }
311}
312
313impl From<FieldTable> for AMQPValue {
314    fn from(v: FieldTable) -> Self {
315        AMQPValue::FieldTable(v)
316    }
317}
318
319impl From<ByteArray> for AMQPValue {
320    fn from(v: ByteArray) -> Self {
321        AMQPValue::ByteArray(v)
322    }
323}
324
325#[cfg(test)]
326mod test {
327    use super::*;
328
329    use serde_json::Number;
330
331    #[test]
332    fn test_from_bool_value() {
333        assert_eq!(
334            AMQPValue::try_from(&Value::Bool(false), AMQPType::Boolean),
335            Some(AMQPValue::Boolean(false))
336        );
337        assert_eq!(
338            AMQPValue::try_from(&Value::Bool(true), AMQPType::Boolean),
339            Some(AMQPValue::Boolean(true))
340        );
341    }
342
343    #[test]
344    fn test_from_number_value() {
345        assert_eq!(
346            AMQPValue::try_from(&Value::Number(Number::from(42)), AMQPType::LongLongUInt),
347            Some(AMQPValue::LongLongInt(42))
348        );
349        assert_eq!(
350            AMQPValue::try_from(&Value::Number(Number::from(-42)), AMQPType::LongLongInt),
351            Some(AMQPValue::LongLongInt(-42))
352        );
353        assert_eq!(
354            AMQPValue::try_from(
355                &Value::Number(Number::from_f64(42.42).unwrap()),
356                AMQPType::Double
357            ),
358            Some(AMQPValue::Double(42.42))
359        );
360    }
361
362    #[test]
363    fn test_from_string_value() {
364        assert_eq!(
365            AMQPValue::try_from(&Value::String(String::new()), AMQPType::LongString),
366            Some(AMQPValue::LongString(LongString::default()))
367        );
368        assert_eq!(
369            AMQPValue::try_from(&Value::String("test".to_string()), AMQPType::LongString),
370            Some(AMQPValue::LongString("test".into()))
371        );
372    }
373
374    #[test]
375    fn test_from_null_value() {
376        assert_eq!(
377            AMQPValue::try_from(&Value::Null, AMQPType::Void),
378            Some(AMQPValue::Void)
379        );
380    }
381}