1use super::*;
27use core::fmt;
28use core::mem;
29
30macro_rules! tuple_ule {
31    ($name:ident, $len:literal, [ $($t:ident $i:tt),+ ]) => {
32        #[doc = concat!("ULE type for tuples with ", $len, " elements.")]
33        #[repr(C, packed)]
34        #[allow(clippy::exhaustive_structs)] pub struct $name<$($t),+>($(pub $t),+);
36
37        unsafe impl<$($t: ULE),+> ULE for $name<$($t),+> {
48            fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
49                let ule_bytes = 0usize $(+ mem::size_of::<$t>())+;
51                if bytes.len() % ule_bytes != 0 {
52                    return Err(UleError::length::<Self>(bytes.len()));
53                }
54                for chunk in bytes.chunks(ule_bytes) {
55                    let mut i = 0;
56                    $(
57                        let j = i;
58                        i += mem::size_of::<$t>();
59                        #[expect(clippy::indexing_slicing)] <$t>::validate_bytes(&chunk[j..i])?;
61                    )+
62                }
63                Ok(())
64            }
65        }
66
67        impl<$($t: AsULE),+> AsULE for ($($t),+) {
68            type ULE = $name<$(<$t>::ULE),+>;
69
70            #[inline]
71            fn to_unaligned(self) -> Self::ULE {
72                $name($(
73                    self.$i.to_unaligned()
74                ),+)
75            }
76
77            #[inline]
78            fn from_unaligned(unaligned: Self::ULE) -> Self {
79                ($(
80                    <$t>::from_unaligned(unaligned.$i)
81                ),+)
82            }
83        }
84
85        impl<$($t: fmt::Debug + ULE),+> fmt::Debug for $name<$($t),+> {
86            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
87                ($(self.$i),+).fmt(f)
88            }
89        }
90
91        impl<$($t: PartialEq + ULE),+> PartialEq for $name<$($t),+> {
93            fn eq(&self, other: &Self) -> bool {
94                ($(self.$i),+).eq(&($(other.$i),+))
95            }
96        }
97
98        impl<$($t: Eq + ULE),+> Eq for $name<$($t),+> {}
99
100        impl<$($t: PartialOrd + ULE),+> PartialOrd for $name<$($t),+> {
101            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
102                ($(self.$i),+).partial_cmp(&($(other.$i),+))
103            }
104        }
105
106        impl<$($t: Ord + ULE),+> Ord for $name<$($t),+> {
107            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
108                ($(self.$i),+).cmp(&($(other.$i),+))
109            }
110        }
111
112        impl<$($t: ULE),+> Clone for $name<$($t),+> {
113            fn clone(&self) -> Self {
114                *self
115            }
116        }
117
118        impl<$($t: ULE),+> Copy for $name<$($t),+> {}
119
120        #[cfg(feature = "alloc")]
121        impl<'a, $($t: Ord + AsULE + 'static),+> crate::map::ZeroMapKV<'a> for ($($t),+) {
122            type Container = crate::ZeroVec<'a, ($($t),+)>;
123            type Slice = crate::ZeroSlice<($($t),+)>;
124            type GetType = $name<$(<$t>::ULE),+>;
125            type OwnedType = ($($t),+);
126        }
127    };
128}
129
130tuple_ule!(Tuple2ULE, "2", [ A 0, B 1 ]);
131tuple_ule!(Tuple3ULE, "3", [ A 0, B 1, C 2 ]);
132tuple_ule!(Tuple4ULE, "4", [ A 0, B 1, C 2, D 3 ]);
133tuple_ule!(Tuple5ULE, "5", [ A 0, B 1, C 2, D 3, E 4 ]);
134tuple_ule!(Tuple6ULE, "6", [ A 0, B 1, C 2, D 3, E 4, F 5 ]);
135
136#[test]
137fn test_pairule_validate() {
138    use crate::ZeroVec;
139    let vec: Vec<(u32, char)> = vec![(1, 'a'), (1234901, '啊'), (100, 'अ')];
140    let zerovec: ZeroVec<(u32, char)> = vec.iter().copied().collect();
141    let bytes = zerovec.as_bytes();
142    let zerovec2 = ZeroVec::parse_bytes(bytes).unwrap();
143    assert_eq!(zerovec, zerovec2);
144
145    let zerovec3 = ZeroVec::<(char, u32)>::parse_bytes(bytes);
148    assert!(zerovec3.is_err());
149}
150
151#[test]
152fn test_tripleule_validate() {
153    use crate::ZeroVec;
154    let vec: Vec<(u32, char, i8)> = vec![(1, 'a', -5), (1234901, '啊', 3), (100, 'अ', -127)];
155    let zerovec: ZeroVec<(u32, char, i8)> = vec.iter().copied().collect();
156    let bytes = zerovec.as_bytes();
157    let zerovec2 = ZeroVec::parse_bytes(bytes).unwrap();
158    assert_eq!(zerovec, zerovec2);
159
160    let zerovec3 = ZeroVec::<(char, i8, u32)>::parse_bytes(bytes);
163    assert!(zerovec3.is_err());
164}
165
166#[test]
167fn test_quadule_validate() {
168    use crate::ZeroVec;
169    let vec: Vec<(u32, char, i8, u16)> =
170        vec![(1, 'a', -5, 3), (1234901, '啊', 3, 11), (100, 'अ', -127, 0)];
171    let zerovec: ZeroVec<(u32, char, i8, u16)> = vec.iter().copied().collect();
172    let bytes = zerovec.as_bytes();
173    let zerovec2 = ZeroVec::parse_bytes(bytes).unwrap();
174    assert_eq!(zerovec, zerovec2);
175
176    let zerovec3 = ZeroVec::<(char, i8, u16, u32)>::parse_bytes(bytes);
179    assert!(zerovec3.is_err());
180}