1use std::{
4 cmp::Ordering,
5 fmt,
6 num::ParseIntError,
7 ops::{Add, Div, Mul, Sub},
8 str::FromStr,
9};
10
11macro_rules! unaligned_integer {
12 (
13 Self = $Ty:ident,
14 Primitive = $Int:ident,
15
16 swap_op = $swap_op:literal,
18 swapped = $swapped:literal,
19 ) => {
20 #[doc = concat!("A ", stringify!($Int), " that has an alignment requirement of 1 byte, i.e. is unaligned")]
21 #[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`.")]
28 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31 #[repr(C, packed)]
32 pub struct $Ty($Int);
33
34 impl $Ty {
35 #[doc = concat!("Creates a ", stringify!($Int), " that has an alignment requirement of 1 byte, i.e. is unaligned.")]
36 #[inline]
37 pub const fn new(value: $Int) -> Self {
38 Self(value)
39 }
40
41 #[inline]
43 pub const fn get(self) -> $Int {
44 self.0
45 }
46
47 #[doc = concat!("# use vpp_plugin::vlibapi::num_unaligned::", stringify!($Ty), ";")]
53 #[doc = concat!("let n = ", stringify!($Ty), "::new(", $swap_op, stringify!($Int), ");")]
54 #[doc = concat!("assert_eq!(m, ", $swapped, ");")]
57 #[must_use = "this returns the result of the operation, \
59 without modifying the original"]
60 #[inline(always)]
61 pub const fn swap_bytes(self) -> Self {
62 Self(self.get().swap_bytes())
63 }
64
65 #[doc = concat!("# use vpp_plugin::vlibapi::num_unaligned::", stringify!($Ty), ";")]
74 #[doc = concat!("let n = ", stringify!($Ty), "::new(0x1A", stringify!($Int), ");")]
75 #[must_use = "this returns the result of the operation, \
83 without modifying the original"]
84 #[inline]
85 pub const fn to_be(self) -> Self {
86 Self(self.get().to_be())
87 }
88
89 #[doc = concat!("# use vpp_plugin::vlibapi::num_unaligned::", stringify!($Ty), ";")]
98 #[doc = concat!("let n = ", stringify!($Ty), "::new(0x1A", stringify!($Int), ");")]
99 #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n)")]
102 #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n.swap_bytes())")]
104 #[must_use = "this returns the result of the operation, \
107 without modifying the original"]
108 #[inline(always)]
109 pub const fn from_be(x: Self) -> Self {
110 Self::new($Int::from_be(x.get()))
111 }
112 }
113
114 impl fmt::Debug for $Ty {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 self.get().fmt(f)
117 }
118 }
119
120 impl fmt::Display for $Ty {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 self.get().fmt(f)
123 }
124 }
125
126 impl From<$Int> for $Ty {
127 #[inline]
128 fn from(value: $Int) -> Self {
129 Self::new(value)
130 }
131 }
132
133 impl From<$Ty> for $Int {
134 #[inline]
135 fn from(value: $Ty) -> Self {
136 value.get()
137 }
138 }
139
140 impl PartialEq<$Int> for $Ty {
141 #[inline]
142 fn eq(&self, other: &$Int) -> bool {
143 self.get() == *other
144 }
145 }
146
147 impl PartialOrd<$Int> for $Ty {
148 #[inline]
149 fn partial_cmp(&self, other: &$Int) -> Option<Ordering> {
150 self.get().partial_cmp(&other)
151 }
152 }
153
154 impl FromStr for $Ty {
155 type Err = ParseIntError;
156
157 #[inline]
158 fn from_str(src: &str) -> Result<Self, Self::Err> {
159 Ok(Self::new(src.parse::<$Int>()?))
160 }
161 }
162
163 impl Add for $Ty {
164 type Output = Self;
165
166 #[inline]
167 fn add(self, rhs: Self) -> Self {
168 Self::new(self.get() + rhs.get())
169 }
170 }
171
172 impl Add<$Int> for $Ty {
173 type Output = $Int;
174
175 #[inline]
176 fn add(self, rhs: $Int) -> $Int {
177 self.get() + rhs
178 }
179 }
180
181 impl Sub for $Ty {
182 type Output = Self;
183
184 #[inline]
185 fn sub(self, rhs: Self) -> Self {
186 Self::new(self.get() - rhs.get())
187 }
188 }
189
190 impl Sub<$Int> for $Ty {
191 type Output = $Int;
192
193 #[inline]
194 fn sub(self, rhs: $Int) -> $Int {
195 self.get() - rhs
196 }
197 }
198
199 impl Mul for $Ty {
200 type Output = Self;
201
202 #[inline]
203 fn mul(self, rhs: Self) -> Self {
204 Self::new(self.get() * rhs.get())
205 }
206 }
207
208 impl Mul<$Int> for $Ty {
209 type Output = $Int;
210
211 #[inline]
212 fn mul(self, rhs: $Int) -> $Int {
213 self.get() * rhs
214 }
215 }
216
217 impl Div for $Ty {
218 type Output = Self;
219
220 #[inline]
221 fn div(self, rhs: Self) -> Self {
222 Self::new(self.get() / rhs.get())
223 }
224 }
225
226 impl Div<$Int> for $Ty {
227 type Output = $Int;
228
229 #[inline]
230 fn div(self, rhs: $Int) -> $Int {
231 self.get() / rhs
232 }
233 }
234 }
235}
236
237unaligned_integer! {
238 Self = UnalignedU16,
239 Primitive = u16,
240 swap_op = "0x1234",
241 swapped = "0x3412",
242}
243
244unaligned_integer! {
245 Self = UnalignedI16,
246 Primitive = i16,
247 swap_op = "0x1234",
248 swapped = "0x3412",
249}
250
251unaligned_integer! {
252 Self = UnalignedU32,
253 Primitive = u32,
254 swap_op = "0x12345678",
255 swapped = "0x78563412",
256}
257
258unaligned_integer! {
259 Self = UnalignedI32,
260 Primitive = i32,
261 swap_op = "0x12345678",
262 swapped = "0x78563412",
263}
264
265unaligned_integer! {
266 Self = UnalignedU64,
267 Primitive = u64,
268 swap_op = "0x1234567890123456",
269 swapped = "0x5634129078563412",
270}
271
272unaligned_integer! {
273 Self = UnalignedI64,
274 Primitive = i64,
275 swap_op = "0x1234567890123456",
276 swapped = "0x5634129078563412",
277}
278
279#[derive(Copy, Clone, PartialEq, PartialOrd)]
290#[repr(C, packed)]
291pub struct UnalignedF64(f64);
292
293impl UnalignedF64 {
294 #[inline]
296 pub const fn new(value: f64) -> Self {
297 Self(value)
298 }
299
300 #[inline]
302 pub const fn get(self) -> f64 {
303 self.0
304 }
305
306 #[must_use = "this returns the result of the operation, \
317 without modifying the original"]
318 #[inline(always)]
319 pub fn swap_bytes(self) -> Self {
320 let bits = self.0.to_bits().swap_bytes();
321 Self(f64::from_bits(bits))
322 }
323
324 #[must_use = "this returns the result of the operation, \
342 without modifying the original"]
343 #[inline]
344 pub fn to_be(self) -> Self {
345 let bits = self.0.to_bits().to_be();
346 Self(f64::from_bits(bits))
347 }
348
349 #[must_use = "this returns the result of the operation, \
367 without modifying the original"]
368 #[inline(always)]
369 pub fn from_be(x: Self) -> Self {
370 let bits = u64::from_be(x.0.to_bits());
371 Self(f64::from_bits(bits))
372 }
373}
374
375impl fmt::Debug for UnalignedF64 {
376 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377 self.get().fmt(f)
378 }
379}
380
381impl fmt::Display for UnalignedF64 {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 self.get().fmt(f)
384 }
385}
386
387impl From<f64> for UnalignedF64 {
388 #[inline]
389 fn from(value: f64) -> Self {
390 Self::new(value)
391 }
392}
393
394impl From<UnalignedF64> for f64 {
395 #[inline]
396 fn from(value: UnalignedF64) -> Self {
397 value.get()
398 }
399}
400
401impl PartialEq<f64> for UnalignedF64 {
402 #[inline]
403 fn eq(&self, other: &f64) -> bool {
404 self.get() == *other
405 }
406}
407
408impl PartialOrd<f64> for UnalignedF64 {
409 #[inline]
410 fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
411 self.get().partial_cmp(other)
412 }
413}
414
415impl FromStr for UnalignedF64 {
416 type Err = <f64 as FromStr>::Err;
417
418 #[inline]
419 fn from_str(src: &str) -> Result<Self, Self::Err> {
420 Ok(Self::new(src.parse::<f64>()?))
421 }
422}
423
424impl Add for UnalignedF64 {
425 type Output = Self;
426
427 #[inline]
428 fn add(self, rhs: Self) -> Self {
429 Self::new(self.get() + rhs.get())
430 }
431}
432
433impl Add<f64> for UnalignedF64 {
434 type Output = f64;
435
436 #[inline]
437 fn add(self, rhs: f64) -> f64 {
438 self.get() + rhs
439 }
440}
441
442impl Sub for UnalignedF64 {
443 type Output = Self;
444
445 #[inline]
446 fn sub(self, rhs: Self) -> Self {
447 Self::new(self.get() - rhs.get())
448 }
449}
450
451impl Sub<f64> for UnalignedF64 {
452 type Output = f64;
453
454 #[inline]
455 fn sub(self, rhs: f64) -> f64 {
456 self.get() - rhs
457 }
458}
459
460impl Mul for UnalignedF64 {
461 type Output = Self;
462
463 #[inline]
464 fn mul(self, rhs: Self) -> Self {
465 Self::new(self.get() * rhs.get())
466 }
467}
468
469impl Mul<f64> for UnalignedF64 {
470 type Output = f64;
471
472 #[inline]
473 fn mul(self, rhs: f64) -> f64 {
474 self.get() * rhs
475 }
476}
477
478impl Div for UnalignedF64 {
479 type Output = Self;
480
481 #[inline]
482 fn div(self, rhs: Self) -> Self {
483 Self::new(self.get() / rhs.get())
484 }
485}
486
487impl Div<f64> for UnalignedF64 {
488 type Output = f64;
489
490 #[inline]
491 fn div(self, rhs: f64) -> f64 {
492 self.get() / rhs
493 }
494}
495
496#[cfg(test)]
497mod tests {
498 use super::*;
499
500 macro_rules! unaligned_numeric_tests {
501 (
502 Self = $Ty:ident,
503 Primitive = $Prim:ident,
504 swap_value = $swap_val:expr,
505 test_value = $test_val:expr,
506 test_value_str = $test_val_str:literal,
507 add_value = $add_val:expr,
508 sub_value = $sub_val:expr,
509 mul_value = $mul_val:expr,
510 div_value = $div_val:expr,
511 ) => {
512 paste::paste! {
513 #[test]
514 fn [<test_ $Ty:snake _new_and_get>]() {
515 let value = $test_val;
516 let unaligned = $Ty::new(value);
517 assert_eq!(unaligned.get(), value);
518 }
519
520 #[test]
521 fn [<test_ $Ty:snake _from_be>]() {
522 let value = $swap_val;
523 let unaligned = $Ty::new(value);
524 let be = unaligned.to_be();
525 let from_be = $Ty::from_be(be);
526 assert_eq!(from_be, unaligned);
527 }
528
529 #[test]
530 fn [<test_ $Ty:snake _from_ $Prim:snake>]() {
531 let value = $test_val;
532 let unaligned: $Ty = value.into();
533 assert_eq!(unaligned.get(), value);
534 }
535
536 #[test]
537 fn [<test_ $Ty:snake _into_ $Prim:snake>]() {
538 let value = $test_val;
539 let unaligned = $Ty::new(value);
540 let primitive: $Prim = unaligned.into();
541 assert_eq!(primitive, value);
542 }
543
544 #[test]
545 fn [<test_ $Ty:snake _partial_eq_ $Prim:snake>]() {
546 let unaligned = $Ty::new($test_val);
547 assert_eq!(unaligned, $test_val);
548 assert_ne!(unaligned, $test_val + $add_val);
549 }
550
551 #[test]
552 fn [<test_ $Ty:snake _partial_ord_ $Prim:snake>]() {
553 let unaligned = $Ty::new($test_val);
554 assert!(unaligned < $test_val + $add_val);
555 assert!(unaligned > $test_val - $add_val);
556 assert!(unaligned <= $test_val);
557 assert!(unaligned >= $test_val);
558 }
559
560 #[test]
561 fn [<test_ $Ty:snake _from_str>]() {
562 let unaligned: $Ty = $test_val_str.parse().unwrap();
563 assert_eq!(unaligned.get(), $test_val);
564 assert_eq!(unaligned.to_string(), $test_val_str);
565 }
566
567 #[test]
568 fn [<test_ $Ty:snake _from_str_invalid>]() {
569 let result: Result<$Ty, _> = "invalid".parse();
570 assert!(result.is_err());
571 }
572
573 #[test]
574 fn [<test_ $Ty:snake _add>]() {
575 let a = $Ty::new($test_val);
576 let b = $Ty::new($add_val);
577 let result = a + b;
578 assert_eq!(result.get(), $test_val + $add_val);
579 }
580
581 #[test]
582 fn [<test_ $Ty:snake _add_ $Prim:snake>]() {
583 let unaligned = $Ty::new($test_val);
584 let result = unaligned + $add_val;
585 assert_eq!(result, $test_val + $add_val);
586 }
587
588 #[test]
589 fn [<test_ $Ty:snake _sub>]() {
590 let a = $Ty::new($test_val + $sub_val);
591 let b = $Ty::new($sub_val);
592 let result = a - b;
593 assert_eq!(result.get(), $test_val);
594 }
595
596 #[test]
597 fn [<test_ $Ty:snake _sub_ $Prim:snake>]() {
598 let unaligned = $Ty::new($test_val + $sub_val);
599 let result = unaligned - $sub_val;
600 assert_eq!(result, $test_val);
601 }
602
603 #[test]
604 fn [<test_ $Ty:snake _mul>]() {
605 let a = $Ty::new($test_val);
606 let b = $Ty::new($mul_val);
607 let result = a * b;
608 assert_eq!(result.get(), $test_val * $mul_val);
609 }
610
611 #[test]
612 fn [<test_ $Ty:snake _mul_ $Prim:snake>]() {
613 let unaligned = $Ty::new($test_val);
614 let result = unaligned * $mul_val;
615 assert_eq!(result, $test_val * $mul_val);
616 }
617
618 #[test]
619 fn [<test_ $Ty:snake _div>]() {
620 let a = $Ty::new($test_val * $div_val);
621 let b = $Ty::new($div_val);
622 let result = a / b;
623 assert_eq!(result.get(), $test_val);
624 }
625
626 #[test]
627 fn [<test_ $Ty:snake _div_ $Prim:snake>]() {
628 let unaligned = $Ty::new($test_val * $div_val);
629 let result = unaligned / $div_val;
630 assert_eq!(result, $test_val);
631 }
632
633 #[test]
634 fn [<test_ $Ty:snake _debug>]() {
635 let unaligned = $Ty::new($test_val);
636 assert_eq!(format!("{:?}", unaligned), $test_val_str);
637 }
638
639 #[test]
640 fn [<test_ $Ty:snake _clone>]() {
641 let original = $Ty::new($test_val);
642 let cloned = original.clone();
643 assert_eq!(original, cloned);
644 assert_eq!(original.get(), cloned.get());
645 }
646
647 #[test]
648 fn [<test_ $Ty:snake _copy>]() {
649 let original = $Ty::new($test_val);
650 let copied = original;
651 assert_eq!(original, copied);
652 assert_eq!(original.get(), copied.get());
653 }
654
655 #[test]
656 fn [<test_ $Ty:snake _min>]() {
657 let min = $Ty::new($Prim::MIN);
658 assert_eq!(min.get(), $Prim::MIN);
659 assert_eq!(min, $Prim::MIN);
660 }
661
662 #[test]
663 fn [<test_ $Ty:snake _max>]() {
664 let max = $Ty::new($Prim::MAX);
665 assert_eq!(max.get(), $Prim::MAX);
666 assert_eq!(max, $Prim::MAX);
667 }
668 }
669 };
670 }
671
672 macro_rules! unaligned_integer_tests {
673 (
674 Self = $Ty:ident,
675 Primitive = $Prim:ident,
676 swap_value = $swap_val:expr,
677 test_value = $test_val:expr,
678 test_value_str = $test_val_str:literal,
679 add_value = $add_val:expr,
680 sub_value = $sub_val:expr,
681 mul_value = $mul_val:expr,
682 div_value = $div_val:expr,
683 ) => {
684 unaligned_numeric_tests! {
685 Self = $Ty,
686 Primitive = $Prim,
687 swap_value = $swap_val,
688 test_value = $test_val,
689 test_value_str = $test_val_str,
690 add_value = $add_val,
691 sub_value = $sub_val,
692 mul_value = $mul_val,
693 div_value = $div_val,
694 }
695
696 paste::paste! {
697 #[test]
698 fn [<test_ $Ty:snake _swap_bytes>]() {
699 let value = $swap_val;
700 let unaligned = $Ty::new(value);
701 let swapped = unaligned.swap_bytes();
702 assert_eq!(swapped.get(), value.swap_bytes());
703 }
704
705 #[test]
706 fn [<test_ $Ty:snake _to_be>]() {
707 let value = $swap_val;
708 let unaligned = $Ty::new(value);
709 let be = unaligned.to_be();
710 assert_eq!(be.get(), value.to_be());
711 }
712
713 #[test]
714 fn [<test_ $Ty:snake _hash>]() {
715 use std::collections::HashSet;
716 let mut set = HashSet::new();
717 let a = $Ty::new(1);
718 let b = $Ty::new(1);
719 set.insert(a);
720 assert!(set.contains(&b));
721 }
722
723 #[test]
724 fn [<test_ $Ty:snake _ord>]() {
725 let a = $Ty::new(1);
726 let b = $Ty::new(2);
727 let c = $Ty::new(1);
728 assert!(a < b);
729 assert!(a <= c);
730 assert!(b > a);
731 assert!(a >= c);
732 assert_eq!(a.cmp(&c), std::cmp::Ordering::Equal);
733 }
734 }
735 };
736 }
737
738 unaligned_integer_tests! {
739 Self = UnalignedU16,
740 Primitive = u16,
741 swap_value = 0x1234u16,
742 test_value = 42u16,
743 test_value_str = "42",
744 add_value = 20u16,
745 sub_value = 10u16,
746 mul_value = 7u16,
747 div_value = 5u16,
748 }
749
750 unaligned_integer_tests! {
751 Self = UnalignedI16,
752 Primitive = i16,
753 swap_value = 0x1234i16,
754 test_value = 42i16,
755 test_value_str = "42",
756 add_value = 20i16,
757 sub_value = 10i16,
758 mul_value = 7i16,
759 div_value = 5i16,
760 }
761
762 unaligned_integer_tests! {
763 Self = UnalignedU32,
764 Primitive = u32,
765 swap_value = 0x12345678u32,
766 test_value = 42u32,
767 test_value_str = "42",
768 add_value = 20u32,
769 sub_value = 10u32,
770 mul_value = 7u32,
771 div_value = 5u32,
772 }
773
774 unaligned_integer_tests! {
775 Self = UnalignedI32,
776 Primitive = i32,
777 swap_value = 0x12345678i32,
778 test_value = 42i32,
779 test_value_str = "42",
780 add_value = 20i32,
781 sub_value = 10i32,
782 mul_value = 7i32,
783 div_value = 5i32,
784 }
785
786 unaligned_integer_tests! {
787 Self = UnalignedU64,
788 Primitive = u64,
789 swap_value = 0x1234567890123456u64,
790 test_value = 42u64,
791 test_value_str = "42",
792 add_value = 20u64,
793 sub_value = 10u64,
794 mul_value = 7u64,
795 div_value = 5u64,
796 }
797
798 unaligned_integer_tests! {
799 Self = UnalignedI64,
800 Primitive = i64,
801 swap_value = 0x1234567890123456i64,
802 test_value = 42i64,
803 test_value_str = "42",
804 add_value = 20i64,
805 sub_value = 10i64,
806 mul_value = 7i64,
807 div_value = 5i64,
808 }
809
810 unaligned_numeric_tests! {
811 Self = UnalignedF64,
812 Primitive = f64,
813 swap_value = 1.0f64,
814 test_value = 42.5f64,
815 test_value_str = "42.5",
816 add_value = 20.0f64,
817 sub_value = 10.0f64,
818 mul_value = 7.0f64,
819 div_value = 5.0f64,
820 }
821 #[test]
822 fn test_unaligned_f64_swap_bytes() {
823 let value = 1.0f64;
824 let unaligned = UnalignedF64::new(value);
825 let swapped = unaligned.swap_bytes();
826 assert_eq!(swapped.get().to_bits(), value.to_bits().swap_bytes());
827 }
828
829 #[test]
830 fn test_unaligned_f64_to_be() {
831 let value = 1.0f64;
832 let unaligned = UnalignedF64::new(value);
833 let be = unaligned.to_be();
834 assert_eq!(be.get().to_bits(), value.to_bits().to_be());
835 }
836}