Skip to main content

vpp_plugin/vlibapi/
num_unaligned.rs

1//! Utilities for unaligned numeric types used in VPP API messages.
2
3use 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        // Used in doc comments.
17        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        ///
22        /// This is useful in packed structures and slices of data contained in variable-length
23        /// arrays in VPP messages.
24        ///
25        /// # Layout
26        ///
27        #[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`.")]
28        ///
29        /// They are also guaranteed to have the same size.
30        #[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            /// Returns the contained value as a primitive type.
42            #[inline]
43            pub const fn get(self) -> $Int {
44                self.0
45            }
46
47            /// Reverses the byte order of the integer.
48            ///
49            /// # Examples
50            ///
51            /// ```
52            #[doc = concat!("# use vpp_plugin::vlibapi::num_unaligned::", stringify!($Ty), ";")]
53            #[doc = concat!("let n = ", stringify!($Ty), "::new(", $swap_op, stringify!($Int), ");")]
54            /// let m = n.swap_bytes();
55            ///
56            #[doc = concat!("assert_eq!(m, ", $swapped, ");")]
57            /// ```
58            #[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            /// Converts `self` to big endian from the target's endianness.
66            ///
67            /// On big endian this is a no-op. On little endian the bytes are
68            /// swapped.
69            ///
70            /// # Examples
71            ///
72            /// ```
73            #[doc = concat!("# use vpp_plugin::vlibapi::num_unaligned::", stringify!($Ty), ";")]
74            #[doc = concat!("let n = ", stringify!($Ty), "::new(0x1A", stringify!($Int), ");")]
75            ///
76            /// if cfg!(target_endian = "big") {
77            ///     assert_eq!(n.to_be(), n)
78            /// } else {
79            ///     assert_eq!(n.to_be(), n.swap_bytes())
80            /// }
81            /// ```
82            #[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            /// Converts an integer from big endian to the target's endianness.
90            ///
91            /// On big endian this is a no-op. On little endian the bytes are
92            /// swapped.
93            ///
94            /// # Examples
95            ///
96            /// ```
97            #[doc = concat!("# use vpp_plugin::vlibapi::num_unaligned::", stringify!($Ty), ";")]
98            #[doc = concat!("let n = ", stringify!($Ty), "::new(0x1A", stringify!($Int), ");")]
99            ///
100            /// if cfg!(target_endian = "big") {
101            #[doc = concat!("    assert_eq!(", stringify!($Ty), "::from_be(n), n)")]
102            /// } else {
103            #[doc = concat!("    assert_eq!(", stringify!($Ty), "::from_be(n), n.swap_bytes())")]
104            /// }
105            /// ```
106            #[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/// A f64 that has an alignment requirement of 1 byte, i.e. is unaligned
280///
281/// This is useful in packed structures and slices of data contained in variable-length
282/// arrays in VPP messages.
283///
284/// # Layout
285///
286/// `UnalignedF64` is guaranteed to have the same layout and bit validity as `f64`.
287///
288/// They are also guaranteed to have the same size.
289#[derive(Copy, Clone, PartialEq, PartialOrd)]
290#[repr(C, packed)]
291pub struct UnalignedF64(f64);
292
293impl UnalignedF64 {
294    /// Creates a f64 that has an alignment requirement of 1 byte, i.e. is unaligned.
295    #[inline]
296    pub const fn new(value: f64) -> Self {
297        Self(value)
298    }
299
300    /// Returns the contained value as a primitive type.
301    #[inline]
302    pub const fn get(self) -> f64 {
303        self.0
304    }
305
306    /// Reverses the byte order of the float.
307    ///
308    /// # Examples
309    ///
310    /// ```
311    /// # use vpp_plugin::vlibapi::num_unaligned::UnalignedF64;
312    /// let n = UnalignedF64::new(1.0f64);
313    /// let m = n.swap_bytes();
314    /// // The result depends on the endianness of the target
315    /// ```
316    #[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    /// Converts `self` to big endian from the target's endianness.
325    ///
326    /// On big endian this is a no-op. On little endian the bytes are
327    /// swapped.
328    ///
329    /// # Examples
330    ///
331    /// ```
332    /// # use vpp_plugin::vlibapi::num_unaligned::UnalignedF64;
333    /// let n = UnalignedF64::new(1.0f64);
334    ///
335    /// if cfg!(target_endian = "big") {
336    ///     assert_eq!(n.to_be(), n)
337    /// } else {
338    ///     assert_eq!(n.to_be(), n.swap_bytes())
339    /// }
340    /// ```
341    #[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    /// Converts a float from big endian to the target's endianness.
350    ///
351    /// On big endian this is a no-op. On little endian the bytes are
352    /// swapped.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// # use vpp_plugin::vlibapi::num_unaligned::UnalignedF64;
358    /// let n = UnalignedF64::new(1.0f64);
359    ///
360    /// if cfg!(target_endian = "big") {
361    ///     assert_eq!(UnalignedF64::from_be(n), n)
362    /// } else {
363    ///     assert_eq!(UnalignedF64::from_be(n), n.swap_bytes())
364    /// }
365    /// ```
366    #[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}