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