1use std::hash::{Hash, Hasher};
2
3use chrono::{DateTime, Utc};
4use ntex_bytes::{BytePages, ByteString, Bytes};
5use ordered_float::OrderedFloat;
6use uuid::Uuid;
7
8use crate::types::{Array, Descriptor, List, Str, Symbol};
9use crate::{AmqpParseError, Decode, Encode, HashMap, protocol::Annotations};
10
11#[derive(Debug, Eq, PartialEq, Hash, Clone, From)]
13pub enum Variant {
14 Null,
16
17 Boolean(bool),
19
20 Ubyte(u8),
22
23 Ushort(u16),
25
26 Uint(u32),
28
29 Ulong(u64),
31
32 Byte(i8),
34
35 Short(i16),
37
38 Int(i32),
40
41 Long(i64),
43
44 Float(OrderedFloat<f32>),
46
47 Double(OrderedFloat<f64>),
49
50 Decimal32([u8; 4]),
52
53 Decimal64([u8; 8]),
55
56 Decimal128([u8; 16]),
58
59 Char(char),
61
62 Timestamp(DateTime<Utc>),
67
68 Uuid(Uuid),
70
71 Binary(Bytes),
73
74 String(Str),
76
77 Symbol(Symbol),
79
80 List(List),
82
83 Map(VariantMap),
85
86 Array(Array),
88
89 Described((Descriptor, Box<Variant>)),
91
92 DescribedCompound(DescribedCompound),
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Hash)]
99pub struct DescribedCompound {
100 descriptor: Descriptor,
101 pub(crate) data: Bytes,
102}
103
104impl DescribedCompound {
105 pub fn create<T: Encode>(descriptor: Descriptor, value: T) -> Self {
116 let mut data = BytePages::default();
117 value.encode(&mut data);
118 DescribedCompound {
119 descriptor,
120 data: data.freeze(),
121 }
122 }
123
124 pub(crate) fn new(descriptor: Descriptor, data: Bytes) -> Self {
125 DescribedCompound { descriptor, data }
126 }
127
128 pub fn descriptor(&self) -> &Descriptor {
129 &self.descriptor
130 }
131
132 pub fn decode<T: Decode>(&self) -> Result<T, AmqpParseError> {
143 let mut buf = self.data.clone();
144 let result = T::decode(&mut buf)?;
145 if buf.is_empty() {
146 Ok(result)
147 } else {
148 Err(AmqpParseError::InvalidSize)
149 }
150 }
151}
152
153impl Encode for DescribedCompound {
154 fn encoded_size(&self) -> usize {
155 self.descriptor.encoded_size() + self.data.len()
156 }
157
158 fn encode(&self, buf: &mut BytePages) {
159 self.descriptor.encode(buf);
160 buf.append(self.data.clone());
161 }
162}
163
164impl From<HashMap<Variant, Variant>> for Variant {
165 fn from(data: HashMap<Variant, Variant>) -> Self {
166 Variant::Map(VariantMap { map: data })
167 }
168}
169
170impl From<ByteString> for Variant {
171 fn from(s: ByteString) -> Self {
172 Str::from(s).into()
173 }
174}
175
176impl From<String> for Variant {
177 fn from(s: String) -> Self {
178 Str::from(ByteString::from(s)).into()
179 }
180}
181
182impl From<&'static str> for Variant {
183 fn from(s: &'static str) -> Self {
184 Str::from(s).into()
185 }
186}
187
188impl PartialEq<str> for Variant {
189 fn eq(&self, other: &str) -> bool {
190 match self {
191 Variant::String(s) => s == other,
192 Variant::Symbol(s) => s == other,
193 _ => false,
194 }
195 }
196}
197
198impl Variant {
199 pub fn as_str(&self) -> Option<&str> {
200 match self {
201 Variant::String(s) => Some(s.as_str()),
202 Variant::Symbol(s) => Some(s.as_str()),
203 _ => None,
204 }
205 }
206
207 pub fn as_long(&self) -> Option<i64> {
210 match self {
211 Variant::Ubyte(v) => Some(*v as i64),
212 Variant::Ushort(v) => Some(*v as i64),
213 Variant::Uint(v) => Some(*v as i64),
214 Variant::Byte(v) => Some(*v as i64),
215 Variant::Short(v) => Some(*v as i64),
216 Variant::Int(v) => Some(*v as i64),
217 Variant::Long(v) => Some(*v),
218 _ => None,
219 }
220 }
221
222 pub fn as_ulong(&self) -> Option<u64> {
224 match self {
225 Variant::Ubyte(v) => Some(*v as u64),
226 Variant::Ushort(v) => Some(*v as u64),
227 Variant::Uint(v) => Some(*v as u64),
228 Variant::Ulong(v) => Some(*v),
229 _ => None,
230 }
231 }
232
233 pub fn to_bytes_str(&self) -> Option<ByteString> {
234 match self {
235 Variant::String(s) => Some(s.to_bytes_str()),
236 Variant::Symbol(s) => Some(s.to_bytes_str()),
237 _ => None,
238 }
239 }
240}
241
242#[derive(PartialEq, Eq, Clone, Debug)]
243pub struct VariantMap {
244 pub map: HashMap<Variant, Variant>,
245}
246
247impl VariantMap {
248 pub fn new(map: HashMap<Variant, Variant>) -> VariantMap {
249 VariantMap { map }
250 }
251}
252
253#[allow(clippy::derived_hash_with_manual_eq)]
254impl Hash for VariantMap {
255 fn hash<H: Hasher>(&self, _state: &mut H) {
256 unimplemented!()
257 }
258}
259
260#[derive(PartialEq, Eq, Clone, Debug)]
261pub struct VecSymbolMap(pub Vec<(Symbol, Variant)>);
262
263impl Default for VecSymbolMap {
264 fn default() -> Self {
265 VecSymbolMap(Vec::with_capacity(8))
266 }
267}
268
269impl From<Annotations> for VecSymbolMap {
270 fn from(anns: Annotations) -> VecSymbolMap {
271 VecSymbolMap(anns.into_iter().collect())
272 }
273}
274
275impl From<Vec<(Symbol, Variant)>> for VecSymbolMap {
276 fn from(data: Vec<(Symbol, Variant)>) -> VecSymbolMap {
277 VecSymbolMap(data)
278 }
279}
280
281impl std::ops::Deref for VecSymbolMap {
282 type Target = Vec<(Symbol, Variant)>;
283
284 fn deref(&self) -> &Self::Target {
285 &self.0
286 }
287}
288
289impl std::ops::DerefMut for VecSymbolMap {
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 &mut self.0
292 }
293}
294
295#[derive(PartialEq, Eq, Clone, Debug)]
296pub struct VecStringMap(pub Vec<(Str, Variant)>);
297
298impl Default for VecStringMap {
299 fn default() -> Self {
300 VecStringMap(Vec::with_capacity(8))
301 }
302}
303
304impl From<Vec<(Str, Variant)>> for VecStringMap {
305 fn from(data: Vec<(Str, Variant)>) -> VecStringMap {
306 VecStringMap(data)
307 }
308}
309
310impl From<HashMap<Str, Variant>> for VecStringMap {
311 fn from(map: HashMap<Str, Variant>) -> VecStringMap {
312 VecStringMap(map.into_iter().collect())
313 }
314}
315
316impl std::ops::Deref for VecStringMap {
317 type Target = Vec<(Str, Variant)>;
318
319 fn deref(&self) -> &Self::Target {
320 &self.0
321 }
322}
323
324impl std::ops::DerefMut for VecStringMap {
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 &mut self.0
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use ntex_bytes::{Buf, BufMut};
333
334 use crate::{codec::ListHeader, format_codes};
335
336 use super::*;
337
338 #[test]
339 fn bytes_eq() {
340 let bytes1 = Variant::Binary(Bytes::from(&b"hello"[..]));
341 let bytes2 = Variant::Binary(Bytes::from(&b"hello"[..]));
342 let bytes3 = Variant::Binary(Bytes::from(&b"world"[..]));
343
344 assert_eq!(bytes1, bytes2);
345 assert!(bytes1 != bytes3);
346 }
347
348 #[test]
349 fn string_eq() {
350 let a = Variant::String(ByteString::from("hello").into());
351 let b = Variant::String(ByteString::from("world!").into());
352
353 assert_eq!(Variant::String(ByteString::from("hello").into()), a);
354 assert!(a != b);
355 }
356
357 #[test]
358 fn symbol_eq() {
359 let a = Variant::Symbol(Symbol::from("hello"));
360 let b = Variant::Symbol(Symbol::from("world!"));
361
362 assert_eq!(Variant::Symbol(Symbol::from("hello")), a);
363 assert!(a != b);
364 }
365
366 #[derive(Debug, PartialEq, Eq, Clone)]
373 struct CustomList {
374 field1: ByteString,
375 field2: u8,
376 field3: Option<ByteString>,
377 }
378
379 impl CustomList {
380 fn encoded_data_size(&self) -> usize {
381 let mut size = self.field1.encoded_size() + self.field2.encoded_size();
382 if let Some(ref field3) = self.field3 {
383 size += field3.encoded_size();
384 }
385 size
386 }
387 }
388
389 impl crate::DecodeFormatted for CustomList {
390 fn decode_with_format(input: &mut Bytes, fmt: u8) -> Result<Self, AmqpParseError> {
391 let header = ListHeader::decode_with_format(input, fmt)?;
392 if header.count < 2 {
393 return Err(AmqpParseError::RequiredFieldOmitted("field2"));
394 }
395 let field1 = ByteString::decode(input)?;
396 let field2 = u8::decode(input)?;
397 let field3 = if header.count == 3 {
398 Some(ByteString::decode(input)?)
399 } else {
400 None
401 };
402 if input.has_remaining() {
403 return Err(AmqpParseError::InvalidSize);
404 }
405 Ok(CustomList {
406 field1,
407 field2,
408 field3,
409 })
410 }
411 }
412
413 impl crate::Encode for CustomList {
414 fn encoded_size(&self) -> usize {
415 let size = self.encoded_data_size();
416 if size + 1 > u8::MAX as usize {
417 size + 9 } else {
419 size + 3 }
421 }
422
423 fn encode(&self, buf: &mut BytePages) {
424 let count = if self.field3.is_some() { 3u8 } else { 2u8 };
425 let data_size = self.encoded_data_size();
426 if data_size + 1 > u8::MAX as usize {
427 buf.put_u8(format_codes::FORMATCODE_LIST32);
428 buf.put_u32((4 + data_size) as u32); buf.put_u32(count as u32); } else {
431 buf.put_u8(format_codes::FORMATCODE_LIST8);
432 buf.put_u8((1 + data_size) as u8); buf.put_u8(count); }
435 self.field1.encode(buf);
436 self.field2.encode(buf);
437 if let Some(ref field3) = self.field3 {
438 field3.encode(buf);
439 }
440 }
441 }
442
443 #[test]
444 fn described_custom_list_recoding() {
445 let custom_list = CustomList {
446 field1: ByteString::from("value1"),
447 field2: 115,
448 field3: Some(ByteString::from("value3")),
449 };
450 let value = Variant::DescribedCompound(DescribedCompound::create(
451 Descriptor::Symbol("contoso:test".into()),
452 custom_list.clone(),
453 ));
454 let mut buf = BytePages::default();
455 value.encode(&mut buf);
456 let data = buf.freeze();
457 assert_eq!(
458 data.as_ref(),
459 &b"\x00\xa3\x0ccontoso:test\xc0\x13\x03\xa1\x06value1\x50\x73\xa1\x06value3"[..]
460 );
461 let mut input = data.clone();
462 let decoded = Variant::decode(&mut input).unwrap();
463 assert_eq!(decoded, value);
464 let decoded_list = match decoded {
465 Variant::DescribedCompound(desc) => desc.decode::<CustomList>().unwrap(),
466 _ => panic!("Expected a described compound"),
467 };
468 assert_eq!(decoded_list, custom_list);
469 }
470}