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