1use super::*;
15use crate::varzerovec::{Index16, VarZeroVecFormat};
16use core::fmt;
17use core::marker::PhantomData;
18use zerofrom::ZeroFrom;
19
20macro_rules! tuple_varule {
21 ($name:ident, $len:literal, [ $($T:ident $t:ident $T_alt: ident $i:tt),+ ]) => {
29 #[doc = concat!("VarULE type for tuples with ", $len, " elements. See module docs for more information")]
30 #[repr(transparent)]
31 #[allow(clippy::exhaustive_structs)] pub struct $name<$($T: ?Sized,)+ Format: VarZeroVecFormat = Index16> {
33 $($t: PhantomData<$T>,)+
34 multi: MultiFieldsULE<$len, Format>
40 }
41
42 impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> $name<$($T,)+ Format> {
43 $(
44 #[doc = concat!("Get field ", $i, "of this tuple")]
45 pub fn $t(&self) -> &$T {
46 unsafe {
48 self.multi.get_field::<$T>($i)
49 }
50 }
51
52
53 )+
54 }
55
56 unsafe impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> VarULE for $name<$($T,)+ Format>
70 {
71 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
72 let multi = <MultiFieldsULE<$len, Format> as VarULE>::parse_bytes(bytes)?;
75 $(
76 unsafe {
78 multi.validate_field::<$T>($i)?;
79 }
80 )+
81 Ok(())
82 }
83
84 unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
85 let multi = <MultiFieldsULE<$len, Format> as VarULE>::from_bytes_unchecked(bytes);
88
89 &*(multi as *const MultiFieldsULE<$len, Format> as *const $name<$($T,)+ Format>)
92 }
93 }
94
95 impl<$($T: fmt::Debug + VarULE + ?Sized,)+ Format: VarZeroVecFormat> fmt::Debug for $name<$($T,)+ Format> {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
97 ($(self.$t(),)+).fmt(f)
98 }
99 }
100
101 impl<$($T: PartialEq + VarULE + ?Sized,)+ Format: VarZeroVecFormat> PartialEq for $name<$($T,)+ Format> {
103 fn eq(&self, other: &Self) -> bool {
104
105 ($(self.$t(),)+).eq(&($(other.$t(),)+))
106 }
107 }
108
109 impl<$($T: Eq + VarULE + ?Sized,)+ Format: VarZeroVecFormat> Eq for $name<$($T,)+ Format> {}
110
111 impl<$($T: PartialOrd + VarULE + ?Sized,)+ Format: VarZeroVecFormat> PartialOrd for $name<$($T,)+ Format> {
112 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
113 ($(self.$t(),)+).partial_cmp(&($(other.$t(),)+))
114 }
115 }
116
117 impl<$($T: Ord + VarULE + ?Sized,)+ Format: VarZeroVecFormat> Ord for $name<$($T,)+ Format> {
118 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
119 ($(self.$t(),)+).cmp(&($(other.$t(),)+))
120 }
121 }
122
123 unsafe impl<$($T,)+ $($T_alt,)+ Format> EncodeAsVarULE<$name<$($T,)+ Format>> for ( $($T_alt),+ )
129 where
130 $($T: VarULE + ?Sized,)+
131 $($T_alt: EncodeAsVarULE<$T>,)+
132 Format: VarZeroVecFormat,
133 {
134 fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
135 unreachable!()
137 }
138
139 #[inline]
140 fn encode_var_ule_len(&self) -> usize {
141 MultiFieldsULE::<$len, Format>::compute_encoded_len_for([$(self.$i.encode_var_ule_len()),+])
144 }
145
146 #[inline]
147 fn encode_var_ule_write(&self, dst: &mut [u8]) {
148 let lengths = [$(self.$i.encode_var_ule_len()),+];
149 let multi = MultiFieldsULE::<$len, Format>::new_from_lengths_partially_initialized(lengths, dst);
152 $(
153 unsafe {
155 multi.set_field_at::<$T, $T_alt>($i, &self.$i);
156 }
157 )+
158 }
159 }
160
161 #[cfg(feature = "alloc")]
162 impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> alloc::borrow::ToOwned for $name<$($T,)+ Format> {
163 type Owned = alloc::boxed::Box<Self>;
164 fn to_owned(&self) -> Self::Owned {
165 encode_varule_to_box(self)
166 }
167 }
168
169 impl<'a, $($T,)+ $($T_alt,)+ Format> ZeroFrom <'a, $name<$($T,)+ Format>> for ($($T_alt),+)
170 where
171 $($T: VarULE + ?Sized,)+
172 $($T_alt: ZeroFrom<'a, $T>,)+
173 Format: VarZeroVecFormat {
174 fn zero_from(other: &'a $name<$($T,)+ Format>) -> Self {
175 (
176 $($T_alt::zero_from(other.$t()),)+
177 )
178 }
179 }
180
181 #[cfg(feature = "serde")]
182 impl<$($T: serde::Serialize,)+ Format> serde::Serialize for $name<$($T,)+ Format>
183 where
184 $($T: VarULE + ?Sized,)+
185 $(for<'a> &'a $T: ZeroFrom<'a, $T>,)+
187 Format: VarZeroVecFormat
188 {
189 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
190 if serializer.is_human_readable() {
191 let this = (
192 $(self.$t()),+
193 );
194 <($(&$T),+) as serde::Serialize>::serialize(&this, serializer)
195 } else {
196 serializer.serialize_bytes(self.multi.as_bytes())
197 }
198 }
199 }
200
201 #[cfg(all(feature = "serde", feature = "alloc"))]
202 impl<'de, $($T: VarULE + ?Sized,)+ Format> serde::Deserialize<'de> for alloc::boxed::Box<$name<$($T,)+ Format>>
203 where
204 $( alloc::boxed::Box<$T>: serde::Deserialize<'de>,)+
206 Format: VarZeroVecFormat {
207 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> where Des: serde::Deserializer<'de> {
208 if deserializer.is_human_readable() {
209 let this = <( $(alloc::boxed::Box<$T>),+) as serde::Deserialize>::deserialize(deserializer)?;
210 let this_ref = (
211 $(&*this.$i),+
212 );
213 Ok(crate::ule::encode_varule_to_box(&this_ref))
214 } else {
215 let deserialized = <&$name<$($T,)+ Format>>::deserialize(deserializer)?;
218 Ok(deserialized.to_boxed())
219 }
220 }
221 }
222
223 #[cfg(feature = "serde")]
224 impl<'a, 'de: 'a, $($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> serde::Deserialize<'de> for &'a $name<$($T,)+ Format> {
225 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> where Des: serde::Deserializer<'de> {
226 if deserializer.is_human_readable() {
227 Err(serde::de::Error::custom(
228 concat!("&", stringify!($name), " can only deserialize in zero-copy ways"),
229 ))
230 } else {
231 let bytes = <&[u8]>::deserialize(deserializer)?;
232 $name::<$($T,)+ Format>::parse_bytes(bytes).map_err(serde::de::Error::custom)
233 }
234 }
235 }
236 };
237}
238
239tuple_varule!(Tuple2VarULE, 2, [ A a AE 0, B b BE 1 ]);
240tuple_varule!(Tuple3VarULE, 3, [ A a AE 0, B b BE 1, C c CE 2 ]);
241tuple_varule!(Tuple4VarULE, 4, [ A a AE 0, B b BE 1, C c CE 2, D d DE 3 ]);
242tuple_varule!(Tuple5VarULE, 5, [ A a AE 0, B b BE 1, C c CE 2, D d DE 3, E e EE 4 ]);
243tuple_varule!(Tuple6VarULE, 6, [ A a AE 0, B b BE 1, C c CE 2, D d DE 3, E e EE 4, F f FE 5 ]);
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248 use crate::varzerovec::{Index16, Index32, Index8, VarZeroVecFormat};
249 use crate::VarZeroSlice;
250 use crate::VarZeroVec;
251
252 #[test]
253 fn test_pairvarule_validate() {
254 let vec: Vec<(&str, &[u8])> = vec![("a", b"b"), ("foo", b"bar"), ("lorem", b"ipsum\xFF")];
255 let zerovec: VarZeroVec<Tuple2VarULE<str, [u8]>> = (&vec).into();
256 let bytes = zerovec.as_bytes();
257 let zerovec2 = VarZeroVec::parse_bytes(bytes).unwrap();
258 assert_eq!(zerovec, zerovec2);
259
260 let zerovec3 = VarZeroVec::<Tuple2VarULE<str, str>>::parse_bytes(bytes);
263 assert!(zerovec3.is_err());
264
265 #[cfg(feature = "serde")]
266 for val in zerovec.iter() {
267 test_utils::assert_serde_roundtrips::<Tuple2VarULE<str, [u8]>>(val);
269 }
270 }
271 fn test_tripleule_validate_inner<Format: VarZeroVecFormat>() {
272 let vec: Vec<(&str, &[u8], VarZeroVec<str>)> = vec![
273 ("a", b"b", (&vec!["a", "b", "c"]).into()),
274 ("foo", b"bar", (&vec!["baz", "quux"]).into()),
275 (
276 "lorem",
277 b"ipsum\xFF",
278 (&vec!["dolor", "sit", "amet"]).into(),
279 ),
280 ];
281 let zerovec: VarZeroVec<Tuple3VarULE<str, [u8], VarZeroSlice<str>, Format>> = (&vec).into();
282 let bytes = zerovec.as_bytes();
283 let zerovec2 = VarZeroVec::parse_bytes(bytes).unwrap();
284 assert_eq!(zerovec, zerovec2);
285
286 let zerovec3 = VarZeroVec::<Tuple3VarULE<VarZeroSlice<str>, [u8], VarZeroSlice<str>, Format>>::parse_bytes(bytes);
289 assert!(zerovec3.is_err());
290
291 #[cfg(feature = "serde")]
292 for val in zerovec.iter() {
293 test_utils::assert_serde_roundtrips::<Tuple3VarULE<str, [u8], VarZeroSlice<str>, Format>>(
295 val,
296 );
297 }
298 }
299
300 #[test]
301 fn test_tripleule_validate() {
302 test_tripleule_validate_inner::<Index8>();
303 test_tripleule_validate_inner::<Index16>();
304 test_tripleule_validate_inner::<Index32>();
305 }
306}