1use lapin::types::{AMQPValue, ByteArray, LongString, ShortString};
2
3pub const MIN_CONT_INT_F32: i32 = -16_777_216;
5pub const MAX_CONT_INT_F32: i32 = 16_777_216;
7
8pub const MIN_CONT_INT_F64: i64 = -9_007_199_254_740_992;
10pub const MAX_CONT_INT_F64: i64 = 9_007_199_254_740_992;
12
13pub trait Coerce<'a, T> {
17 fn coerce(&'a self) -> Option<T>;
19}
20
21const _: () = {
23 impl<'a> Coerce<'a, &'a str> for AMQPValue {
24 fn coerce(&'a self) -> Option<&'a str> {
25 match self {
26 Self::ShortString(s) => s.coerce(),
27 _ => None,
28 }
29 }
30 }
31
32 impl Coerce<'_, String> for AMQPValue {
33 fn coerce(&self) -> Option<String> {
34 match self {
35 Self::Boolean(value) => Some((*value).to_string()),
36 Self::ShortShortUInt(u) => Some((*u).to_string()),
37 Self::ShortUInt(u) => Some((*u).to_string()),
38 Self::LongUInt(u) => Some((*u).to_string()),
39 Self::Timestamp(u) => Some((*u).to_string()),
40 Self::ShortShortInt(i) => Some((*i).to_string()),
41 Self::ShortInt(i) => Some((*i).to_string()),
42 Self::LongInt(i) => Some((*i).to_string()),
43 Self::LongLongInt(i) => Some((*i).to_string()),
44 Self::ShortString(s) => s.coerce(),
45 Self::LongString(s) => s.coerce(),
46 Self::ByteArray(s) => s.coerce(),
47 _ => None,
48 }
49 }
50 }
51
52 impl Coerce<'_, bool> for AMQPValue {
53 fn coerce(&self) -> Option<bool> {
54 match self {
55 Self::Boolean(value) => Some(*value),
56 Self::ShortShortUInt(u) => Some(*u != 0),
57 Self::ShortUInt(u) => Some(*u != 0),
58 Self::LongUInt(u) => Some(*u != 0),
59 Self::Timestamp(u) => Some(*u != 0),
60 Self::ShortShortInt(i) => Some(*i != 0),
61 Self::ShortInt(i) => Some(*i != 0),
62 Self::LongInt(i) => Some(*i != 0),
63 Self::LongLongInt(i) => Some(*i != 0),
64 Self::ShortString(s) => s.coerce(),
65 Self::LongString(s) => s.coerce(),
66 Self::ByteArray(s) => s.coerce(),
67 _ => None,
68 }
69 }
70 }
71
72 impl Coerce<'_, i8> for AMQPValue {
73 fn coerce(&self) -> Option<i8> {
74 match self {
75 Self::ShortShortUInt(u) => (*u).try_into().ok(),
76 Self::ShortUInt(u) => (*u).try_into().ok(),
77 Self::LongUInt(u) => (*u).try_into().ok(),
78 Self::Timestamp(u) => (*u).try_into().ok(),
79 Self::ShortShortInt(i) => Some(*i),
80 Self::ShortInt(i) => (*i).try_into().ok(),
81 Self::LongInt(i) => (*i).try_into().ok(),
82 Self::LongLongInt(i) => (*i).try_into().ok(),
83 Self::ShortString(s) => s.coerce(),
84 Self::LongString(s) => s.coerce(),
85 Self::ByteArray(s) => s.coerce(),
86 _ => None,
87 }
88 }
89 }
90
91 impl Coerce<'_, i16> for AMQPValue {
92 fn coerce(&self) -> Option<i16> {
93 match self {
94 Self::ShortShortUInt(u) => Some(*u as i16),
95 Self::ShortUInt(u) => (*u).try_into().ok(),
96 Self::LongUInt(u) => (*u).try_into().ok(),
97 Self::Timestamp(u) => (*u).try_into().ok(),
98 Self::ShortShortInt(i) => Some(*i as i16),
99 Self::ShortInt(i) => Some(*i),
100 Self::LongInt(i) => (*i).try_into().ok(),
101 Self::LongLongInt(i) => (*i).try_into().ok(),
102 Self::ShortString(s) => s.coerce(),
103 Self::LongString(s) => s.coerce(),
104 Self::ByteArray(s) => s.coerce(),
105 _ => None,
106 }
107 }
108 }
109
110 impl Coerce<'_, i32> for AMQPValue {
111 fn coerce(&self) -> Option<i32> {
112 match self {
113 Self::ShortShortUInt(u) => Some(*u as i32),
114 Self::ShortUInt(u) => Some(*u as i32),
115 Self::LongUInt(u) => (*u).try_into().ok(),
116 Self::Timestamp(u) => (*u).try_into().ok(),
117 Self::ShortShortInt(i) => Some(*i as i32),
118 Self::ShortInt(i) => Some(*i as i32),
119 Self::LongInt(i) => Some(*i),
120 Self::LongLongInt(i) => (*i).try_into().ok(),
121 Self::ShortString(s) => s.coerce(),
122 Self::LongString(s) => s.coerce(),
123 Self::ByteArray(s) => s.coerce(),
124 _ => None,
125 }
126 }
127 }
128
129 impl Coerce<'_, i64> for AMQPValue {
130 fn coerce(&self) -> Option<i64> {
131 match self {
132 Self::ShortShortUInt(u) => Some(*u as i64),
133 Self::ShortUInt(u) => Some(*u as i64),
134 Self::LongUInt(u) => Some(*u as i64),
135 Self::Timestamp(u) => (*u).try_into().ok(),
136 Self::ShortShortInt(i) => Some(*i as i64),
137 Self::ShortInt(i) => Some(*i as i64),
138 Self::LongInt(i) => Some(*i as i64),
139 Self::LongLongInt(i) => Some(*i),
140 Self::ShortString(s) => s.coerce(),
141 Self::LongString(s) => s.coerce(),
142 Self::ByteArray(s) => s.coerce(),
143 _ => None,
144 }
145 }
146 }
147
148 impl Coerce<'_, isize> for AMQPValue {
149 fn coerce(&self) -> Option<isize> {
150 match self {
151 Self::ShortShortUInt(u) => Some(*u as isize),
152 Self::ShortUInt(u) => (*u).try_into().ok(),
153 Self::LongUInt(u) => (*u).try_into().ok(),
154 Self::Timestamp(u) => (*u).try_into().ok(),
155 Self::ShortShortInt(i) => Some(*i as isize),
156 Self::ShortInt(i) => Some(*i as isize),
157 Self::LongInt(i) => Some(*i as isize),
158 Self::LongLongInt(i) => (*i).try_into().ok(),
159 Self::ShortString(s) => s.coerce(),
160 Self::LongString(s) => s.coerce(),
161 Self::ByteArray(s) => s.coerce(),
162 _ => None,
163 }
164 }
165 }
166
167 impl Coerce<'_, u8> for AMQPValue {
168 fn coerce(&self) -> Option<u8> {
169 match self {
170 Self::ShortShortUInt(u) => Some(*u),
171 Self::ShortUInt(u) => (*u).try_into().ok(),
172 Self::LongUInt(u) => (*u).try_into().ok(),
173 Self::Timestamp(u) => (*u).try_into().ok(),
174 Self::ShortShortInt(i) => (*i).try_into().ok(),
175 Self::ShortInt(i) => (*i).try_into().ok(),
176 Self::LongInt(i) => (*i).try_into().ok(),
177 Self::LongLongInt(i) => (*i).try_into().ok(),
178 Self::ShortString(s) => s.coerce(),
179 Self::LongString(s) => s.coerce(),
180 Self::ByteArray(s) => s.coerce(),
181 _ => None,
182 }
183 }
184 }
185
186 impl Coerce<'_, u16> for AMQPValue {
187 fn coerce(&self) -> Option<u16> {
188 match self {
189 Self::ShortShortUInt(u) => Some(*u as u16),
190 Self::ShortUInt(u) => Some(*u),
191 Self::LongUInt(u) => (*u).try_into().ok(),
192 Self::Timestamp(u) => (*u).try_into().ok(),
193 Self::ShortShortInt(i) => (*i).try_into().ok(),
194 Self::ShortInt(i) => (*i).try_into().ok(),
195 Self::LongInt(i) => (*i).try_into().ok(),
196 Self::LongLongInt(i) => (*i).try_into().ok(),
197 Self::ShortString(s) => s.coerce(),
198 Self::LongString(s) => s.coerce(),
199 Self::ByteArray(s) => s.coerce(),
200 _ => None,
201 }
202 }
203 }
204
205 impl Coerce<'_, u32> for AMQPValue {
206 fn coerce(&self) -> Option<u32> {
207 match self {
208 Self::ShortShortUInt(u) => Some(*u as u32),
209 Self::ShortUInt(u) => Some(*u as u32),
210 Self::LongUInt(u) => Some(*u),
211 Self::Timestamp(u) => (*u).try_into().ok(),
212 Self::ShortShortInt(i) => (*i).try_into().ok(),
213 Self::ShortInt(i) => (*i).try_into().ok(),
214 Self::LongInt(i) => (*i).try_into().ok(),
215 Self::LongLongInt(i) => (*i).try_into().ok(),
216 Self::ShortString(s) => s.coerce(),
217 Self::LongString(s) => s.coerce(),
218 Self::ByteArray(s) => s.coerce(),
219 _ => None,
220 }
221 }
222 }
223
224 impl Coerce<'_, u64> for AMQPValue {
225 fn coerce(&self) -> Option<u64> {
226 match self {
227 Self::ShortShortUInt(u) => Some(*u as u64),
228 Self::ShortUInt(u) => Some(*u as u64),
229 Self::LongUInt(u) => Some(*u as u64),
230 Self::Timestamp(u) => Some(*u),
231 Self::ShortShortInt(i) => (*i).try_into().ok(),
232 Self::ShortInt(i) => (*i).try_into().ok(),
233 Self::LongInt(i) => (*i).try_into().ok(),
234 Self::LongLongInt(i) => (*i).try_into().ok(),
235 Self::ShortString(s) => s.coerce(),
236 Self::LongString(s) => s.coerce(),
237 Self::ByteArray(s) => s.coerce(),
238 _ => None,
239 }
240 }
241 }
242
243 impl Coerce<'_, usize> for AMQPValue {
244 fn coerce(&self) -> Option<usize> {
245 match self {
246 Self::ShortShortUInt(u) => Some(*u as usize),
247 Self::ShortUInt(u) => Some(*u as usize),
248 Self::LongUInt(u) => Some(*u as usize),
249 Self::Timestamp(u) => (*u).try_into().ok(),
250 Self::ShortShortInt(i) => (*i).try_into().ok(),
251 Self::ShortInt(i) => (*i).try_into().ok(),
252 Self::LongInt(i) => (*i).try_into().ok(),
253 Self::LongLongInt(i) => (*i).try_into().ok(),
254 Self::ShortString(s) => s.coerce(),
255 Self::LongString(s) => s.coerce(),
256 Self::ByteArray(s) => s.coerce(),
257 _ => None,
258 }
259 }
260 }
261
262 impl Coerce<'_, f32> for AMQPValue {
263 fn coerce(&'_ self) -> Option<f32> {
264 match self {
265 Self::ShortShortUInt(u) => Some(*u as f32),
266 Self::ShortUInt(u) => Some(*u as f32),
267 Self::LongUInt(u) => {
268 if (*u) <= (MAX_CONT_INT_F32 as u32) {
269 Some(*u as f32)
270 } else {
271 None
272 }
273 }
274 Self::Timestamp(u) => {
275 if (*u) <= (MAX_CONT_INT_F32 as u64) {
276 Some(*u as f32)
277 } else {
278 None
279 }
280 }
281 Self::ShortShortInt(i) => Some(*i as f32),
282 Self::ShortInt(i) => Some(*i as f32),
283 Self::LongInt(i) => {
284 if (*i) >= MIN_CONT_INT_F32 && (*i) <= MAX_CONT_INT_F32 {
285 Some(*i as f32)
286 } else {
287 None
288 }
289 }
290 Self::LongLongInt(i) => {
291 if (*i) >= (MIN_CONT_INT_F32 as i64) && (*i) <= (MAX_CONT_INT_F32 as i64) {
292 Some(*i as f32)
293 } else {
294 None
295 }
296 }
297 Self::ShortString(s) => s.coerce(),
298 Self::LongString(s) => s.coerce(),
299 Self::ByteArray(s) => s.coerce(),
300 _ => None,
301 }
302 }
303 }
304
305 impl Coerce<'_, f64> for AMQPValue {
306 fn coerce(&'_ self) -> Option<f64> {
307 match self {
308 Self::ShortShortUInt(u) => Some(*u as f64),
309 Self::ShortUInt(u) => Some(*u as f64),
310 Self::LongUInt(u) => Some(*u as f64),
311 Self::Timestamp(u) => {
312 if (*u) <= (MAX_CONT_INT_F64 as u64) {
313 Some(*u as f64)
314 } else {
315 None
316 }
317 }
318 Self::ShortShortInt(i) => Some(*i as f64),
319 Self::ShortInt(i) => Some(*i as f64),
320 Self::LongInt(i) => Some(*i as f64),
321 Self::LongLongInt(i) => {
322 if (*i) >= MIN_CONT_INT_F64 && (*i) <= MAX_CONT_INT_F64 {
323 Some(*i as f64)
324 } else {
325 None
326 }
327 }
328 Self::ShortString(s) => s.coerce(),
329 Self::LongString(s) => s.coerce(),
330 Self::ByteArray(s) => s.coerce(),
331 _ => None,
332 }
333 }
334 }
335};
336
337const _: () = {
339 impl<'a> Coerce<'a, &'a str> for ShortString {
340 fn coerce(&'a self) -> Option<&'a str> {
341 Some(self.as_str())
342 }
343 }
344
345 impl Coerce<'_, String> for ShortString {
346 fn coerce(&self) -> Option<String> {
347 Some(self.to_string())
348 }
349 }
350
351 impl Coerce<'_, bool> for ShortString {
352 fn coerce(&self) -> Option<bool> {
353 parse_bool(self.as_str())
354 }
355 }
356
357 impl Coerce<'_, i8> for ShortString {
358 fn coerce(&self) -> Option<i8> {
359 self.as_str().parse::<i8>().ok()
360 }
361 }
362
363 impl Coerce<'_, i16> for ShortString {
364 fn coerce(&self) -> Option<i16> {
365 self.as_str().parse::<i16>().ok()
366 }
367 }
368
369 impl Coerce<'_, i32> for ShortString {
370 fn coerce(&self) -> Option<i32> {
371 self.as_str().parse::<i32>().ok()
372 }
373 }
374
375 impl Coerce<'_, i64> for ShortString {
376 fn coerce(&self) -> Option<i64> {
377 self.as_str().parse::<i64>().ok()
378 }
379 }
380
381 impl Coerce<'_, isize> for ShortString {
382 fn coerce(&self) -> Option<isize> {
383 self.as_str().parse::<isize>().ok()
384 }
385 }
386
387 impl Coerce<'_, u8> for ShortString {
388 fn coerce(&self) -> Option<u8> {
389 self.as_str().parse::<u8>().ok()
390 }
391 }
392
393 impl Coerce<'_, u16> for ShortString {
394 fn coerce(&self) -> Option<u16> {
395 self.as_str().parse::<u16>().ok()
396 }
397 }
398
399 impl Coerce<'_, u32> for ShortString {
400 fn coerce(&self) -> Option<u32> {
401 self.as_str().parse::<u32>().ok()
402 }
403 }
404
405 impl Coerce<'_, u64> for ShortString {
406 fn coerce(&self) -> Option<u64> {
407 self.as_str().parse::<u64>().ok()
408 }
409 }
410
411 impl Coerce<'_, usize> for ShortString {
412 fn coerce(&self) -> Option<usize> {
413 self.as_str().parse::<usize>().ok()
414 }
415 }
416
417 impl Coerce<'_, f32> for ShortString {
418 fn coerce(&self) -> Option<f32> {
419 self.as_str().parse::<f32>().ok()
420 }
421 }
422
423 impl Coerce<'_, f64> for ShortString {
424 fn coerce(&self) -> Option<f64> {
425 self.as_str().parse::<f64>().ok()
426 }
427 }
428};
429
430const _: () = {
432 impl Coerce<'_, String> for LongString {
433 fn coerce(&self) -> Option<String> {
434 Some(self.to_string())
435 }
436 }
437
438 impl Coerce<'_, bool> for LongString {
439 fn coerce(&self) -> Option<bool> {
440 parse_bool(&self.to_string())
441 }
442 }
443
444 impl Coerce<'_, i8> for LongString {
445 fn coerce(&self) -> Option<i8> {
446 self.to_string().parse::<i8>().ok()
447 }
448 }
449
450 impl Coerce<'_, i16> for LongString {
451 fn coerce(&self) -> Option<i16> {
452 self.to_string().parse::<i16>().ok()
453 }
454 }
455
456 impl Coerce<'_, i32> for LongString {
457 fn coerce(&self) -> Option<i32> {
458 self.to_string().parse::<i32>().ok()
459 }
460 }
461
462 impl Coerce<'_, i64> for LongString {
463 fn coerce(&self) -> Option<i64> {
464 self.to_string().parse::<i64>().ok()
465 }
466 }
467
468 impl Coerce<'_, isize> for LongString {
469 fn coerce(&self) -> Option<isize> {
470 self.to_string().parse::<isize>().ok()
471 }
472 }
473
474 impl Coerce<'_, u8> for LongString {
475 fn coerce(&self) -> Option<u8> {
476 self.to_string().parse::<u8>().ok()
477 }
478 }
479
480 impl Coerce<'_, u16> for LongString {
481 fn coerce(&self) -> Option<u16> {
482 self.to_string().parse::<u16>().ok()
483 }
484 }
485
486 impl Coerce<'_, u32> for LongString {
487 fn coerce(&self) -> Option<u32> {
488 self.to_string().parse::<u32>().ok()
489 }
490 }
491
492 impl Coerce<'_, u64> for LongString {
493 fn coerce(&self) -> Option<u64> {
494 self.to_string().parse::<u64>().ok()
495 }
496 }
497
498 impl Coerce<'_, usize> for LongString {
499 fn coerce(&self) -> Option<usize> {
500 self.to_string().parse::<usize>().ok()
501 }
502 }
503
504 impl Coerce<'_, f32> for LongString {
505 fn coerce(&self) -> Option<f32> {
506 self.to_string().parse::<f32>().ok()
507 }
508 }
509
510 impl Coerce<'_, f64> for LongString {
511 fn coerce(&self) -> Option<f64> {
512 self.to_string().parse::<f64>().ok()
513 }
514 }
515};
516
517const _: () = {
519 impl Coerce<'_, String> for ByteArray {
520 fn coerce(&self) -> Option<String> {
521 Some(String::from_utf8_lossy(self.as_slice()).to_string())
522 }
523 }
524
525 impl Coerce<'_, bool> for ByteArray {
526 fn coerce(&self) -> Option<bool> {
527 parse_bool(&String::from_utf8_lossy(self.as_slice()))
528 }
529 }
530
531 impl Coerce<'_, i8> for ByteArray {
532 fn coerce(&self) -> Option<i8> {
533 String::from_utf8_lossy(self.as_slice()).parse::<i8>().ok()
534 }
535 }
536
537 impl Coerce<'_, i16> for ByteArray {
538 fn coerce(&self) -> Option<i16> {
539 String::from_utf8_lossy(self.as_slice()).parse::<i16>().ok()
540 }
541 }
542
543 impl Coerce<'_, i32> for ByteArray {
544 fn coerce(&self) -> Option<i32> {
545 String::from_utf8_lossy(self.as_slice()).parse::<i32>().ok()
546 }
547 }
548
549 impl Coerce<'_, i64> for ByteArray {
550 fn coerce(&self) -> Option<i64> {
551 String::from_utf8_lossy(self.as_slice()).parse::<i64>().ok()
552 }
553 }
554
555 impl Coerce<'_, isize> for ByteArray {
556 fn coerce(&self) -> Option<isize> {
557 String::from_utf8_lossy(self.as_slice())
558 .parse::<isize>()
559 .ok()
560 }
561 }
562
563 impl Coerce<'_, u8> for ByteArray {
564 fn coerce(&self) -> Option<u8> {
565 String::from_utf8_lossy(self.as_slice()).parse::<u8>().ok()
566 }
567 }
568
569 impl Coerce<'_, u16> for ByteArray {
570 fn coerce(&self) -> Option<u16> {
571 String::from_utf8_lossy(self.as_slice()).parse::<u16>().ok()
572 }
573 }
574
575 impl Coerce<'_, u32> for ByteArray {
576 fn coerce(&self) -> Option<u32> {
577 String::from_utf8_lossy(self.as_slice()).parse::<u32>().ok()
578 }
579 }
580
581 impl Coerce<'_, u64> for ByteArray {
582 fn coerce(&self) -> Option<u64> {
583 String::from_utf8_lossy(self.as_slice()).parse::<u64>().ok()
584 }
585 }
586
587 impl Coerce<'_, usize> for ByteArray {
588 fn coerce(&self) -> Option<usize> {
589 String::from_utf8_lossy(self.as_slice())
590 .parse::<usize>()
591 .ok()
592 }
593 }
594
595 impl Coerce<'_, f32> for ByteArray {
596 fn coerce(&self) -> Option<f32> {
597 String::from_utf8_lossy(self.as_slice()).parse::<f32>().ok()
598 }
599 }
600
601 impl Coerce<'_, f64> for ByteArray {
602 fn coerce(&self) -> Option<f64> {
603 String::from_utf8_lossy(self.as_slice()).parse::<f64>().ok()
604 }
605 }
606};
607
608fn parse_bool(input: &str) -> Option<bool> {
610 match input.len() {
611 0 => Some(false), 1 => {
614 let b = input.as_bytes()[0];
616 match b {
617 b'1' => Some(true),
618 b'0' => Some(false),
619 _ => match b.to_ascii_lowercase() {
620 b't' | b'y' => Some(true),
621 b'f' | b'n' => Some(false),
622 _ => None,
623 },
624 }
625 }
626
627 2 if input.eq_ignore_ascii_case("on") => Some(true),
628 2 if input.eq_ignore_ascii_case("no") => Some(false),
629
630 3 if input.eq_ignore_ascii_case("yes") => Some(true),
631 3 if input.eq_ignore_ascii_case("off") => Some(false),
632
633 4 if input.eq_ignore_ascii_case("true") => Some(true),
634 5 if input.eq_ignore_ascii_case("false") => Some(false),
635
636 _ => None,
637 }
638}
639
640#[cfg(test)]
641mod tests {
642 use super::parse_bool;
643
644 #[test]
645 fn true_variants() {
646 let trues = [
647 "", "true", "TRUE", "True", "t", "T", "1", "yes", "YES", "Yes", "y", "Y", "on", "ON", "On",
649 ];
650 for &s in &trues[1..] {
651 assert_eq!(parse_bool(s), Some(true), "should parse {:?} as true", s);
652 }
653 }
654
655 #[test]
656 fn false_variants() {
657 let falses = [
658 "", "false", "FALSE", "False", "f", "F", "0", "no", "NO", "No", "n", "N", "off", "OFF",
660 "Off",
661 ];
662 for &s in &falses {
663 assert_eq!(parse_bool(s), Some(false), "should parse {:?} as false", s);
664 }
665 }
666
667 #[test]
668 fn rejects_invalid() {
669 let bad = [
670 "2", "on?", "off!", "tru", "fals", "yep", "nah", "ye", "nOpe", "yes!", " false ",
671 ];
672 for &s in &bad {
673 assert_eq!(parse_bool(s), None, "should reject {:?}", s);
674 }
675 }
676}