Skip to main content

zerovec/ule/
tuplevar.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! [`VarULE`] impls for tuples.
6//!
7//! This module exports [`Tuple2VarULE`], [`Tuple3VarULE`], ..., the corresponding [`VarULE`] types
8//! of tuples containing purely [`VarULE`] types.
9//!
10//! This can be paired with [`VarTupleULE`] to make arbitrary combinations of [`ULE`] and [`VarULE`] types.
11//!
12//! [`VarTupleULE`]: crate::ule::vartuple::VarTupleULE
13
14use super::*;
15use crate::varzerovec::{Index16, VarZeroVecFormat};
16use core::fmt;
17use core::marker::PhantomData;
18use zerofrom::ZeroFrom;
19
20macro_rules! tuple_varule {
21    // Invocation: Should be called like `tuple_ule!(Tuple2VarULE, 2, [ A a AX 0, B b BX 1 ])`
22    //
23    // $T is a generic name, $t is a lowercase version of it, $T_alt is an "alternate" name to use when we need two types referring
24    // to the same input field, $i is an index.
25    //
26    // $name is the name of the type, $len MUST be the total number of fields, and then $i must be an integer going from 0 to (n - 1) in sequence
27    // (This macro code can rely on $i < $len)
28    ($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)] // stable
32        pub struct $name<$($T: ?Sized,)+ Format: VarZeroVecFormat = Index16> {
33            $($t: PhantomData<$T>,)+
34            // Safety invariant: Each "field" $i of the MultiFieldsULE is a valid instance of $t
35            //
36            // In other words, calling `.get_field::<$T>($i)` is always safe.
37            //
38            // This invariant is upheld when this type is constructed during VarULE parsing/validation
39            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                     // Safety: See invariant of `multi`.
47                    unsafe {
48                        self.multi.get_field::<$T>($i)
49                    }
50                }
51
52
53            )+
54        }
55
56        // # Safety
57        //
58        // ## Checklist
59        //
60        // Safety checklist for `VarULE`:
61        //
62        // 1. align(1): repr(transparent) around an align(1) VarULE type: MultiFieldsULE
63        // 2. No padding: see previous point
64        // 3. `validate_bytes` validates that this type is a valid MultiFieldsULE, and that each field is the correct type from the tuple.
65        // 4. `validate_bytes` checks length by deferring to the inner ULEs
66        // 5. `from_bytes_unchecked` returns a fat pointer to the bytes.
67        // 6. All other methods are left at their default impl.
68        // 7. The inner ULEs have byte equality, so this composition has byte equality.
69        unsafe impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> VarULE for $name<$($T,)+ Format>
70        {
71            fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
72                // Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
73                // as in the type def
74                let multi = <MultiFieldsULE<$len, Format> as VarULE>::parse_bytes(bytes)?;
75                $(
76                    // Safety invariant: $i < $len, from the macro invocation
77                    unsafe {
78                        multi.validate_field::<$T>($i)?;
79                    }
80                )+
81                Ok(())
82            }
83
84            unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
85                 // Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
86                // as in the type def
87                let multi = <MultiFieldsULE<$len, Format> as VarULE>::from_bytes_unchecked(bytes);
88
89                // This type is repr(transparent) over MultiFieldsULE<$len>, so its slices can be transmuted
90                // Field invariant upheld here: validate_bytes above validates every field for being the right type
91                &*(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        // We need manual impls since `#[derive()]` is disallowed on packed types
102        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        // # Safety
124        //
125        // encode_var_ule_len: returns the length of the individual VarULEs together.
126        //
127        // encode_var_ule_write: writes bytes by deferring to the inner VarULE impls.
128        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                // unnecessary if the other two are implemented
136                unreachable!()
137            }
138
139            #[inline]
140            fn encode_var_ule_len(&self) -> usize {
141                // Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
142                // as in the type def
143                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                // Safety: We validate that this type is the same kind of MultiFieldsULE (with $len, Format)
150                // as in the type def
151                let multi = MultiFieldsULE::<$len, Format>::new_from_lengths_partially_initialized(lengths, dst);
152                $(
153                    // Safety: $i < $len, from the macro invocation, and field $i is supposed to be of type $T
154                    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            // This impl should be present on almost all VarULE types. if it isn't, that is a bug
186            $(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                // This impl should be present on almost all deserializable VarULE types
205                $( 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                    // This branch should usually not be hit, since Cow-like use cases will hit the Deserialize impl for &'a TupleNVarULE instead.
216
217                    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
239#[doc =
"VarULE type for tuples with 2 elements. See module docs for more information"]
#[repr(transparent)]
#[allow(clippy :: exhaustive_structs)]
pub struct Tuple2VarULE<A: ?Sized, B: ?Sized, Format: VarZeroVecFormat =
    Index16> {
    a: PhantomData<A>,
    b: PhantomData<B>,
    multi: MultiFieldsULE<2, Format>,
}
impl<A: VarULE + ?Sized, B: VarULE + ?Sized, Format: VarZeroVecFormat>
    Tuple2VarULE<A, B, Format> {
    #[doc = "Get field 0of this tuple"]
    pub fn a(&self) -> &A { unsafe { self.multi.get_field::<A>(0) } }
    #[doc = "Get field 1of this tuple"]
    pub fn b(&self) -> &B { unsafe { self.multi.get_field::<B>(1) } }
}
unsafe impl<A: VarULE + ?Sized, B: VarULE + ?Sized, Format: VarZeroVecFormat>
    VarULE for Tuple2VarULE<A, B, Format> {
    fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
        let multi =
            <MultiFieldsULE<2, Format> as VarULE>::parse_bytes(bytes)?;
        unsafe { multi.validate_field::<A>(0)?; }
        unsafe { multi.validate_field::<B>(1)?; }
        Ok(())
    }
    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
        let multi =
            <MultiFieldsULE<2, Format> as
                    VarULE>::from_bytes_unchecked(bytes);
        &*(multi as *const MultiFieldsULE<2, Format> as
                        *const Tuple2VarULE<A, B, Format>)
    }
}
impl<A: fmt::Debug + VarULE + ?Sized, B: fmt::Debug + VarULE + ?Sized,
    Format: VarZeroVecFormat> fmt::Debug for Tuple2VarULE<A, B, Format> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        (self.a(), self.b()).fmt(f)
    }
}
impl<A: PartialEq + VarULE + ?Sized, B: PartialEq + VarULE + ?Sized,
    Format: VarZeroVecFormat> PartialEq for Tuple2VarULE<A, B, Format> {
    fn eq(&self, other: &Self) -> bool {
        (self.a(), self.b()).eq(&(other.a(), other.b()))
    }
}
impl<A: Eq + VarULE + ?Sized, B: Eq + VarULE + ?Sized,
    Format: VarZeroVecFormat> Eq for Tuple2VarULE<A, B, Format> {}
impl<A: PartialOrd + VarULE + ?Sized, B: PartialOrd + VarULE + ?Sized,
    Format: VarZeroVecFormat> PartialOrd for Tuple2VarULE<A, B, Format> {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        (self.a(), self.b()).partial_cmp(&(other.a(), other.b()))
    }
}
impl<A: Ord + VarULE + ?Sized, B: Ord + VarULE + ?Sized,
    Format: VarZeroVecFormat> Ord for Tuple2VarULE<A, B, Format> {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        (self.a(), self.b()).cmp(&(other.a(), other.b()))
    }
}
unsafe impl<A, B, AE, BE, Format> EncodeAsVarULE<Tuple2VarULE<A, B, Format>>
    for (AE, BE) where A: VarULE + ?Sized, B: VarULE + ?Sized,
    AE: EncodeAsVarULE<A>, BE: EncodeAsVarULE<B>, Format: VarZeroVecFormat {
    fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R)
        -> R {
        ::core::panicking::panic("internal error: entered unreachable code")
    }
    #[inline]
    fn encode_var_ule_len(&self) -> usize {
        MultiFieldsULE::<2,
                Format>::compute_encoded_len_for([self.0.encode_var_ule_len(),
                    self.1.encode_var_ule_len()])
    }
    #[inline]
    fn encode_var_ule_write(&self, dst: &mut [u8]) {
        let lengths =
            [self.0.encode_var_ule_len(), self.1.encode_var_ule_len()];
        let multi =
            MultiFieldsULE::<2,
                    Format>::new_from_lengths_partially_initialized(lengths,
                dst);
        unsafe { multi.set_field_at::<A, AE>(0, &self.0); }
        unsafe { multi.set_field_at::<B, BE>(1, &self.1); }
    }
}
impl<'a, A, B, AE, BE, Format> ZeroFrom<'a, Tuple2VarULE<A, B, Format>> for
    (AE, BE) where A: VarULE + ?Sized, B: VarULE + ?Sized,
    AE: ZeroFrom<'a, A>, BE: ZeroFrom<'a, B>, Format: VarZeroVecFormat {
    fn zero_from(other: &'a Tuple2VarULE<A, B, Format>) -> Self {
        (AE::zero_from(other.a()), BE::zero_from(other.b()))
    }
}tuple_varule!(Tuple2VarULE, 2, [ A a AE 0, B b BE 1 ]);
240#[doc =
"VarULE type for tuples with 3 elements. See module docs for more information"]
#[repr(transparent)]
#[allow(clippy :: exhaustive_structs)]
pub struct Tuple3VarULE<A: ?Sized, B: ?Sized, C: ?Sized,
    Format: VarZeroVecFormat = Index16> {
    a: PhantomData<A>,
    b: PhantomData<B>,
    c: PhantomData<C>,
    multi: MultiFieldsULE<3, Format>,
}
impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    Format: VarZeroVecFormat> Tuple3VarULE<A, B, C, Format> {
    #[doc = "Get field 0of this tuple"]
    pub fn a(&self) -> &A { unsafe { self.multi.get_field::<A>(0) } }
    #[doc = "Get field 1of this tuple"]
    pub fn b(&self) -> &B { unsafe { self.multi.get_field::<B>(1) } }
    #[doc = "Get field 2of this tuple"]
    pub fn c(&self) -> &C { unsafe { self.multi.get_field::<C>(2) } }
}
unsafe impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    Format: VarZeroVecFormat> VarULE for Tuple3VarULE<A, B, C, Format> {
    fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
        let multi =
            <MultiFieldsULE<3, Format> as VarULE>::parse_bytes(bytes)?;
        unsafe { multi.validate_field::<A>(0)?; }
        unsafe { multi.validate_field::<B>(1)?; }
        unsafe { multi.validate_field::<C>(2)?; }
        Ok(())
    }
    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
        let multi =
            <MultiFieldsULE<3, Format> as
                    VarULE>::from_bytes_unchecked(bytes);
        &*(multi as *const MultiFieldsULE<3, Format> as
                        *const Tuple3VarULE<A, B, C, Format>)
    }
}
impl<A: fmt::Debug + VarULE + ?Sized, B: fmt::Debug + VarULE + ?Sized,
    C: fmt::Debug + VarULE + ?Sized, Format: VarZeroVecFormat> fmt::Debug for
    Tuple3VarULE<A, B, C, Format> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        (self.a(), self.b(), self.c()).fmt(f)
    }
}
impl<A: PartialEq + VarULE + ?Sized, B: PartialEq + VarULE + ?Sized,
    C: PartialEq + VarULE + ?Sized, Format: VarZeroVecFormat> PartialEq for
    Tuple3VarULE<A, B, C, Format> {
    fn eq(&self, other: &Self) -> bool {
        (self.a(), self.b(), self.c()).eq(&(other.a(), other.b(), other.c()))
    }
}
impl<A: Eq + VarULE + ?Sized, B: Eq + VarULE + ?Sized, C: Eq + VarULE +
    ?Sized, Format: VarZeroVecFormat> Eq for Tuple3VarULE<A, B, C, Format> {}
impl<A: PartialOrd + VarULE + ?Sized, B: PartialOrd + VarULE + ?Sized,
    C: PartialOrd + VarULE + ?Sized, Format: VarZeroVecFormat> PartialOrd for
    Tuple3VarULE<A, B, C, Format> {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        (self.a(), self.b(),
                self.c()).partial_cmp(&(other.a(), other.b(), other.c()))
    }
}
impl<A: Ord + VarULE + ?Sized, B: Ord + VarULE + ?Sized, C: Ord + VarULE +
    ?Sized, Format: VarZeroVecFormat> Ord for Tuple3VarULE<A, B, C, Format> {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        (self.a(), self.b(), self.c()).cmp(&(other.a(), other.b(), other.c()))
    }
}
unsafe impl<A, B, C, AE, BE, CE, Format>
    EncodeAsVarULE<Tuple3VarULE<A, B, C, Format>> for (AE, BE, CE) where
    A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    AE: EncodeAsVarULE<A>, BE: EncodeAsVarULE<B>, CE: EncodeAsVarULE<C>,
    Format: VarZeroVecFormat {
    fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R)
        -> R {
        ::core::panicking::panic("internal error: entered unreachable code")
    }
    #[inline]
    fn encode_var_ule_len(&self) -> usize {
        MultiFieldsULE::<3,
                Format>::compute_encoded_len_for([self.0.encode_var_ule_len(),
                    self.1.encode_var_ule_len(), self.2.encode_var_ule_len()])
    }
    #[inline]
    fn encode_var_ule_write(&self, dst: &mut [u8]) {
        let lengths =
            [self.0.encode_var_ule_len(), self.1.encode_var_ule_len(),
                    self.2.encode_var_ule_len()];
        let multi =
            MultiFieldsULE::<3,
                    Format>::new_from_lengths_partially_initialized(lengths,
                dst);
        unsafe { multi.set_field_at::<A, AE>(0, &self.0); }
        unsafe { multi.set_field_at::<B, BE>(1, &self.1); }
        unsafe { multi.set_field_at::<C, CE>(2, &self.2); }
    }
}
impl<'a, A, B, C, AE, BE, CE, Format>
    ZeroFrom<'a, Tuple3VarULE<A, B, C, Format>> for (AE, BE, CE) where
    A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    AE: ZeroFrom<'a, A>, BE: ZeroFrom<'a, B>, CE: ZeroFrom<'a, C>,
    Format: VarZeroVecFormat {
    fn zero_from(other: &'a Tuple3VarULE<A, B, C, Format>) -> Self {
        (AE::zero_from(other.a()), BE::zero_from(other.b()),
            CE::zero_from(other.c()))
    }
}tuple_varule!(Tuple3VarULE, 3, [ A a AE 0, B b BE 1, C c CE 2 ]);
241#[doc =
"VarULE type for tuples with 4 elements. See module docs for more information"]
#[repr(transparent)]
#[allow(clippy :: exhaustive_structs)]
pub struct Tuple4VarULE<A: ?Sized, B: ?Sized, C: ?Sized, D: ?Sized,
    Format: VarZeroVecFormat = Index16> {
    a: PhantomData<A>,
    b: PhantomData<B>,
    c: PhantomData<C>,
    d: PhantomData<D>,
    multi: MultiFieldsULE<4, Format>,
}
impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized, D: VarULE +
    ?Sized, Format: VarZeroVecFormat> Tuple4VarULE<A, B, C, D, Format> {
    #[doc = "Get field 0of this tuple"]
    pub fn a(&self) -> &A { unsafe { self.multi.get_field::<A>(0) } }
    #[doc = "Get field 1of this tuple"]
    pub fn b(&self) -> &B { unsafe { self.multi.get_field::<B>(1) } }
    #[doc = "Get field 2of this tuple"]
    pub fn c(&self) -> &C { unsafe { self.multi.get_field::<C>(2) } }
    #[doc = "Get field 3of this tuple"]
    pub fn d(&self) -> &D { unsafe { self.multi.get_field::<D>(3) } }
}
unsafe impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    D: VarULE + ?Sized, Format: VarZeroVecFormat> VarULE for
    Tuple4VarULE<A, B, C, D, Format> {
    fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
        let multi =
            <MultiFieldsULE<4, Format> as VarULE>::parse_bytes(bytes)?;
        unsafe { multi.validate_field::<A>(0)?; }
        unsafe { multi.validate_field::<B>(1)?; }
        unsafe { multi.validate_field::<C>(2)?; }
        unsafe { multi.validate_field::<D>(3)?; }
        Ok(())
    }
    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
        let multi =
            <MultiFieldsULE<4, Format> as
                    VarULE>::from_bytes_unchecked(bytes);
        &*(multi as *const MultiFieldsULE<4, Format> as
                        *const Tuple4VarULE<A, B, C, D, Format>)
    }
}
impl<A: fmt::Debug + VarULE + ?Sized, B: fmt::Debug + VarULE + ?Sized,
    C: fmt::Debug + VarULE + ?Sized, D: fmt::Debug + VarULE + ?Sized,
    Format: VarZeroVecFormat> fmt::Debug for Tuple4VarULE<A, B, C, D, Format>
    {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        (self.a(), self.b(), self.c(), self.d()).fmt(f)
    }
}
impl<A: PartialEq + VarULE + ?Sized, B: PartialEq + VarULE + ?Sized,
    C: PartialEq + VarULE + ?Sized, D: PartialEq + VarULE + ?Sized,
    Format: VarZeroVecFormat> PartialEq for Tuple4VarULE<A, B, C, D, Format> {
    fn eq(&self, other: &Self) -> bool {
        (self.a(), self.b(), self.c(),
                self.d()).eq(&(other.a(), other.b(), other.c(), other.d()))
    }
}
impl<A: Eq + VarULE + ?Sized, B: Eq + VarULE + ?Sized, C: Eq + VarULE +
    ?Sized, D: Eq + VarULE + ?Sized, Format: VarZeroVecFormat> Eq for
    Tuple4VarULE<A, B, C, D, Format> {}
impl<A: PartialOrd + VarULE + ?Sized, B: PartialOrd + VarULE + ?Sized,
    C: PartialOrd + VarULE + ?Sized, D: PartialOrd + VarULE + ?Sized,
    Format: VarZeroVecFormat> PartialOrd for Tuple4VarULE<A, B, C, D, Format>
    {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        (self.a(), self.b(), self.c(),
                self.d()).partial_cmp(&(other.a(), other.b(), other.c(),
                    other.d()))
    }
}
impl<A: Ord + VarULE + ?Sized, B: Ord + VarULE + ?Sized, C: Ord + VarULE +
    ?Sized, D: Ord + VarULE + ?Sized, Format: VarZeroVecFormat> Ord for
    Tuple4VarULE<A, B, C, D, Format> {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        (self.a(), self.b(), self.c(),
                self.d()).cmp(&(other.a(), other.b(), other.c(), other.d()))
    }
}
unsafe impl<A, B, C, D, AE, BE, CE, DE, Format>
    EncodeAsVarULE<Tuple4VarULE<A, B, C, D, Format>> for (AE, BE, CE, DE)
    where A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    D: VarULE + ?Sized, AE: EncodeAsVarULE<A>, BE: EncodeAsVarULE<B>,
    CE: EncodeAsVarULE<C>, DE: EncodeAsVarULE<D>, Format: VarZeroVecFormat {
    fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R)
        -> R {
        ::core::panicking::panic("internal error: entered unreachable code")
    }
    #[inline]
    fn encode_var_ule_len(&self) -> usize {
        MultiFieldsULE::<4,
                Format>::compute_encoded_len_for([self.0.encode_var_ule_len(),
                    self.1.encode_var_ule_len(), self.2.encode_var_ule_len(),
                    self.3.encode_var_ule_len()])
    }
    #[inline]
    fn encode_var_ule_write(&self, dst: &mut [u8]) {
        let lengths =
            [self.0.encode_var_ule_len(), self.1.encode_var_ule_len(),
                    self.2.encode_var_ule_len(), self.3.encode_var_ule_len()];
        let multi =
            MultiFieldsULE::<4,
                    Format>::new_from_lengths_partially_initialized(lengths,
                dst);
        unsafe { multi.set_field_at::<A, AE>(0, &self.0); }
        unsafe { multi.set_field_at::<B, BE>(1, &self.1); }
        unsafe { multi.set_field_at::<C, CE>(2, &self.2); }
        unsafe { multi.set_field_at::<D, DE>(3, &self.3); }
    }
}
impl<'a, A, B, C, D, AE, BE, CE, DE, Format>
    ZeroFrom<'a, Tuple4VarULE<A, B, C, D, Format>> for (AE, BE, CE, DE) where
    A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized, D: VarULE +
    ?Sized, AE: ZeroFrom<'a, A>, BE: ZeroFrom<'a, B>, CE: ZeroFrom<'a, C>,
    DE: ZeroFrom<'a, D>, Format: VarZeroVecFormat {
    fn zero_from(other: &'a Tuple4VarULE<A, B, C, D, Format>) -> Self {
        (AE::zero_from(other.a()), BE::zero_from(other.b()),
            CE::zero_from(other.c()), DE::zero_from(other.d()))
    }
}tuple_varule!(Tuple4VarULE, 4, [ A a AE 0, B b BE 1, C c CE 2, D d DE 3 ]);
242#[doc =
"VarULE type for tuples with 5 elements. See module docs for more information"]
#[repr(transparent)]
#[allow(clippy :: exhaustive_structs)]
pub struct Tuple5VarULE<A: ?Sized, B: ?Sized, C: ?Sized, D: ?Sized, E: ?Sized,
    Format: VarZeroVecFormat = Index16> {
    a: PhantomData<A>,
    b: PhantomData<B>,
    c: PhantomData<C>,
    d: PhantomData<D>,
    e: PhantomData<E>,
    multi: MultiFieldsULE<5, Format>,
}
impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized, D: VarULE +
    ?Sized, E: VarULE + ?Sized, Format: VarZeroVecFormat>
    Tuple5VarULE<A, B, C, D, E, Format> {
    #[doc = "Get field 0of this tuple"]
    pub fn a(&self) -> &A { unsafe { self.multi.get_field::<A>(0) } }
    #[doc = "Get field 1of this tuple"]
    pub fn b(&self) -> &B { unsafe { self.multi.get_field::<B>(1) } }
    #[doc = "Get field 2of this tuple"]
    pub fn c(&self) -> &C { unsafe { self.multi.get_field::<C>(2) } }
    #[doc = "Get field 3of this tuple"]
    pub fn d(&self) -> &D { unsafe { self.multi.get_field::<D>(3) } }
    #[doc = "Get field 4of this tuple"]
    pub fn e(&self) -> &E { unsafe { self.multi.get_field::<E>(4) } }
}
unsafe impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    D: VarULE + ?Sized, E: VarULE + ?Sized, Format: VarZeroVecFormat> VarULE
    for Tuple5VarULE<A, B, C, D, E, Format> {
    fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
        let multi =
            <MultiFieldsULE<5, Format> as VarULE>::parse_bytes(bytes)?;
        unsafe { multi.validate_field::<A>(0)?; }
        unsafe { multi.validate_field::<B>(1)?; }
        unsafe { multi.validate_field::<C>(2)?; }
        unsafe { multi.validate_field::<D>(3)?; }
        unsafe { multi.validate_field::<E>(4)?; }
        Ok(())
    }
    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
        let multi =
            <MultiFieldsULE<5, Format> as
                    VarULE>::from_bytes_unchecked(bytes);
        &*(multi as *const MultiFieldsULE<5, Format> as
                        *const Tuple5VarULE<A, B, C, D, E, Format>)
    }
}
impl<A: fmt::Debug + VarULE + ?Sized, B: fmt::Debug + VarULE + ?Sized,
    C: fmt::Debug + VarULE + ?Sized, D: fmt::Debug + VarULE + ?Sized,
    E: fmt::Debug + VarULE + ?Sized, Format: VarZeroVecFormat> fmt::Debug for
    Tuple5VarULE<A, B, C, D, E, Format> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        (self.a(), self.b(), self.c(), self.d(), self.e()).fmt(f)
    }
}
impl<A: PartialEq + VarULE + ?Sized, B: PartialEq + VarULE + ?Sized,
    C: PartialEq + VarULE + ?Sized, D: PartialEq + VarULE + ?Sized,
    E: PartialEq + VarULE + ?Sized, Format: VarZeroVecFormat> PartialEq for
    Tuple5VarULE<A, B, C, D, E, Format> {
    fn eq(&self, other: &Self) -> bool {
        (self.a(), self.b(), self.c(), self.d(),
                self.e()).eq(&(other.a(), other.b(), other.c(), other.d(),
                    other.e()))
    }
}
impl<A: Eq + VarULE + ?Sized, B: Eq + VarULE + ?Sized, C: Eq + VarULE +
    ?Sized, D: Eq + VarULE + ?Sized, E: Eq + VarULE + ?Sized,
    Format: VarZeroVecFormat> Eq for Tuple5VarULE<A, B, C, D, E, Format> {}
impl<A: PartialOrd + VarULE + ?Sized, B: PartialOrd + VarULE + ?Sized,
    C: PartialOrd + VarULE + ?Sized, D: PartialOrd + VarULE + ?Sized,
    E: PartialOrd + VarULE + ?Sized, Format: VarZeroVecFormat> PartialOrd for
    Tuple5VarULE<A, B, C, D, E, Format> {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        (self.a(), self.b(), self.c(), self.d(),
                self.e()).partial_cmp(&(other.a(), other.b(), other.c(),
                    other.d(), other.e()))
    }
}
impl<A: Ord + VarULE + ?Sized, B: Ord + VarULE + ?Sized, C: Ord + VarULE +
    ?Sized, D: Ord + VarULE + ?Sized, E: Ord + VarULE + ?Sized,
    Format: VarZeroVecFormat> Ord for Tuple5VarULE<A, B, C, D, E, Format> {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        (self.a(), self.b(), self.c(), self.d(),
                self.e()).cmp(&(other.a(), other.b(), other.c(), other.d(),
                    other.e()))
    }
}
unsafe impl<A, B, C, D, E, AE, BE, CE, DE, EE, Format>
    EncodeAsVarULE<Tuple5VarULE<A, B, C, D, E, Format>> for
    (AE, BE, CE, DE, EE) where A: VarULE + ?Sized, B: VarULE + ?Sized,
    C: VarULE + ?Sized, D: VarULE + ?Sized, E: VarULE + ?Sized,
    AE: EncodeAsVarULE<A>, BE: EncodeAsVarULE<B>, CE: EncodeAsVarULE<C>,
    DE: EncodeAsVarULE<D>, EE: EncodeAsVarULE<E>, Format: VarZeroVecFormat {
    fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R)
        -> R {
        ::core::panicking::panic("internal error: entered unreachable code")
    }
    #[inline]
    fn encode_var_ule_len(&self) -> usize {
        MultiFieldsULE::<5,
                Format>::compute_encoded_len_for([self.0.encode_var_ule_len(),
                    self.1.encode_var_ule_len(), self.2.encode_var_ule_len(),
                    self.3.encode_var_ule_len(), self.4.encode_var_ule_len()])
    }
    #[inline]
    fn encode_var_ule_write(&self, dst: &mut [u8]) {
        let lengths =
            [self.0.encode_var_ule_len(), self.1.encode_var_ule_len(),
                    self.2.encode_var_ule_len(), self.3.encode_var_ule_len(),
                    self.4.encode_var_ule_len()];
        let multi =
            MultiFieldsULE::<5,
                    Format>::new_from_lengths_partially_initialized(lengths,
                dst);
        unsafe { multi.set_field_at::<A, AE>(0, &self.0); }
        unsafe { multi.set_field_at::<B, BE>(1, &self.1); }
        unsafe { multi.set_field_at::<C, CE>(2, &self.2); }
        unsafe { multi.set_field_at::<D, DE>(3, &self.3); }
        unsafe { multi.set_field_at::<E, EE>(4, &self.4); }
    }
}
impl<'a, A, B, C, D, E, AE, BE, CE, DE, EE, Format>
    ZeroFrom<'a, Tuple5VarULE<A, B, C, D, E, Format>> for (AE, BE, CE, DE, EE)
    where A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    D: VarULE + ?Sized, E: VarULE + ?Sized, AE: ZeroFrom<'a, A>,
    BE: ZeroFrom<'a, B>, CE: ZeroFrom<'a, C>, DE: ZeroFrom<'a, D>,
    EE: ZeroFrom<'a, E>, Format: VarZeroVecFormat {
    fn zero_from(other: &'a Tuple5VarULE<A, B, C, D, E, Format>) -> Self {
        (AE::zero_from(other.a()), BE::zero_from(other.b()),
            CE::zero_from(other.c()), DE::zero_from(other.d()),
            EE::zero_from(other.e()))
    }
}tuple_varule!(Tuple5VarULE, 5, [ A a AE 0, B b BE 1, C c CE 2, D d DE 3, E e EE 4 ]);
243#[doc =
"VarULE type for tuples with 6 elements. See module docs for more information"]
#[repr(transparent)]
#[allow(clippy :: exhaustive_structs)]
pub struct Tuple6VarULE<A: ?Sized, B: ?Sized, C: ?Sized, D: ?Sized, E: ?Sized,
    F: ?Sized, Format: VarZeroVecFormat = Index16> {
    a: PhantomData<A>,
    b: PhantomData<B>,
    c: PhantomData<C>,
    d: PhantomData<D>,
    e: PhantomData<E>,
    f: PhantomData<F>,
    multi: MultiFieldsULE<6, Format>,
}
impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized, D: VarULE +
    ?Sized, E: VarULE + ?Sized, F: VarULE + ?Sized, Format: VarZeroVecFormat>
    Tuple6VarULE<A, B, C, D, E, F, Format> {
    #[doc = "Get field 0of this tuple"]
    pub fn a(&self) -> &A { unsafe { self.multi.get_field::<A>(0) } }
    #[doc = "Get field 1of this tuple"]
    pub fn b(&self) -> &B { unsafe { self.multi.get_field::<B>(1) } }
    #[doc = "Get field 2of this tuple"]
    pub fn c(&self) -> &C { unsafe { self.multi.get_field::<C>(2) } }
    #[doc = "Get field 3of this tuple"]
    pub fn d(&self) -> &D { unsafe { self.multi.get_field::<D>(3) } }
    #[doc = "Get field 4of this tuple"]
    pub fn e(&self) -> &E { unsafe { self.multi.get_field::<E>(4) } }
    #[doc = "Get field 5of this tuple"]
    pub fn f(&self) -> &F { unsafe { self.multi.get_field::<F>(5) } }
}
unsafe impl<A: VarULE + ?Sized, B: VarULE + ?Sized, C: VarULE + ?Sized,
    D: VarULE + ?Sized, E: VarULE + ?Sized, F: VarULE + ?Sized,
    Format: VarZeroVecFormat> VarULE for
    Tuple6VarULE<A, B, C, D, E, F, Format> {
    fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
        let multi =
            <MultiFieldsULE<6, Format> as VarULE>::parse_bytes(bytes)?;
        unsafe { multi.validate_field::<A>(0)?; }
        unsafe { multi.validate_field::<B>(1)?; }
        unsafe { multi.validate_field::<C>(2)?; }
        unsafe { multi.validate_field::<D>(3)?; }
        unsafe { multi.validate_field::<E>(4)?; }
        unsafe { multi.validate_field::<F>(5)?; }
        Ok(())
    }
    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
        let multi =
            <MultiFieldsULE<6, Format> as
                    VarULE>::from_bytes_unchecked(bytes);
        &*(multi as *const MultiFieldsULE<6, Format> as
                        *const Tuple6VarULE<A, B, C, D, E, F, Format>)
    }
}
impl<A: fmt::Debug + VarULE + ?Sized, B: fmt::Debug + VarULE + ?Sized,
    C: fmt::Debug + VarULE + ?Sized, D: fmt::Debug + VarULE + ?Sized,
    E: fmt::Debug + VarULE + ?Sized, F: fmt::Debug + VarULE + ?Sized,
    Format: VarZeroVecFormat> fmt::Debug for
    Tuple6VarULE<A, B, C, D, E, F, Format> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        (self.a(), self.b(), self.c(), self.d(), self.e(), self.f()).fmt(f)
    }
}
impl<A: PartialEq + VarULE + ?Sized, B: PartialEq + VarULE + ?Sized,
    C: PartialEq + VarULE + ?Sized, D: PartialEq + VarULE + ?Sized,
    E: PartialEq + VarULE + ?Sized, F: PartialEq + VarULE + ?Sized,
    Format: VarZeroVecFormat> PartialEq for
    Tuple6VarULE<A, B, C, D, E, F, Format> {
    fn eq(&self, other: &Self) -> bool {
        (self.a(), self.b(), self.c(), self.d(), self.e(),
                self.f()).eq(&(other.a(), other.b(), other.c(), other.d(),
                    other.e(), other.f()))
    }
}
impl<A: Eq + VarULE + ?Sized, B: Eq + VarULE + ?Sized, C: Eq + VarULE +
    ?Sized, D: Eq + VarULE + ?Sized, E: Eq + VarULE + ?Sized, F: Eq + VarULE +
    ?Sized, Format: VarZeroVecFormat> Eq for
    Tuple6VarULE<A, B, C, D, E, F, Format> {}
impl<A: PartialOrd + VarULE + ?Sized, B: PartialOrd + VarULE + ?Sized,
    C: PartialOrd + VarULE + ?Sized, D: PartialOrd + VarULE + ?Sized,
    E: PartialOrd + VarULE + ?Sized, F: PartialOrd + VarULE + ?Sized,
    Format: VarZeroVecFormat> PartialOrd for
    Tuple6VarULE<A, B, C, D, E, F, Format> {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        (self.a(), self.b(), self.c(), self.d(), self.e(),
                self.f()).partial_cmp(&(other.a(), other.b(), other.c(),
                    other.d(), other.e(), other.f()))
    }
}
impl<A: Ord + VarULE + ?Sized, B: Ord + VarULE + ?Sized, C: Ord + VarULE +
    ?Sized, D: Ord + VarULE + ?Sized, E: Ord + VarULE + ?Sized, F: Ord +
    VarULE + ?Sized, Format: VarZeroVecFormat> Ord for
    Tuple6VarULE<A, B, C, D, E, F, Format> {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        (self.a(), self.b(), self.c(), self.d(), self.e(),
                self.f()).cmp(&(other.a(), other.b(), other.c(), other.d(),
                    other.e(), other.f()))
    }
}
unsafe impl<A, B, C, D, E, F, AE, BE, CE, DE, EE, FE, Format>
    EncodeAsVarULE<Tuple6VarULE<A, B, C, D, E, F, Format>> for
    (AE, BE, CE, DE, EE, FE) where A: VarULE + ?Sized, B: VarULE + ?Sized,
    C: VarULE + ?Sized, D: VarULE + ?Sized, E: VarULE + ?Sized, F: VarULE +
    ?Sized, AE: EncodeAsVarULE<A>, BE: EncodeAsVarULE<B>,
    CE: EncodeAsVarULE<C>, DE: EncodeAsVarULE<D>, EE: EncodeAsVarULE<E>,
    FE: EncodeAsVarULE<F>, Format: VarZeroVecFormat {
    fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R)
        -> R {
        ::core::panicking::panic("internal error: entered unreachable code")
    }
    #[inline]
    fn encode_var_ule_len(&self) -> usize {
        MultiFieldsULE::<6,
                Format>::compute_encoded_len_for([self.0.encode_var_ule_len(),
                    self.1.encode_var_ule_len(), self.2.encode_var_ule_len(),
                    self.3.encode_var_ule_len(), self.4.encode_var_ule_len(),
                    self.5.encode_var_ule_len()])
    }
    #[inline]
    fn encode_var_ule_write(&self, dst: &mut [u8]) {
        let lengths =
            [self.0.encode_var_ule_len(), self.1.encode_var_ule_len(),
                    self.2.encode_var_ule_len(), self.3.encode_var_ule_len(),
                    self.4.encode_var_ule_len(), self.5.encode_var_ule_len()];
        let multi =
            MultiFieldsULE::<6,
                    Format>::new_from_lengths_partially_initialized(lengths,
                dst);
        unsafe { multi.set_field_at::<A, AE>(0, &self.0); }
        unsafe { multi.set_field_at::<B, BE>(1, &self.1); }
        unsafe { multi.set_field_at::<C, CE>(2, &self.2); }
        unsafe { multi.set_field_at::<D, DE>(3, &self.3); }
        unsafe { multi.set_field_at::<E, EE>(4, &self.4); }
        unsafe { multi.set_field_at::<F, FE>(5, &self.5); }
    }
}
impl<'a, A, B, C, D, E, F, AE, BE, CE, DE, EE, FE, Format>
    ZeroFrom<'a, Tuple6VarULE<A, B, C, D, E, F, Format>> for
    (AE, BE, CE, DE, EE, FE) where A: VarULE + ?Sized, B: VarULE + ?Sized,
    C: VarULE + ?Sized, D: VarULE + ?Sized, E: VarULE + ?Sized, F: VarULE +
    ?Sized, AE: ZeroFrom<'a, A>, BE: ZeroFrom<'a, B>, CE: ZeroFrom<'a, C>,
    DE: ZeroFrom<'a, D>, EE: ZeroFrom<'a, E>, FE: ZeroFrom<'a, F>,
    Format: VarZeroVecFormat {
    fn zero_from(other: &'a Tuple6VarULE<A, B, C, D, E, F, Format>) -> Self {
        (AE::zero_from(other.a()), BE::zero_from(other.b()),
            CE::zero_from(other.c()), DE::zero_from(other.d()),
            EE::zero_from(other.e()), FE::zero_from(other.f()))
    }
}tuple_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        // Test failed validation with a correctly sized but differently constrained tuple
261        // Note: ipsum\xFF is not a valid str
262        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            // Can't use inference due to https://github.com/rust-lang/rust/issues/130180
268            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        // Test failed validation with a correctly sized but differently constrained tuple
287        // Note: the str is unlikely to be a valid varzerovec
288        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            // Can't use inference due to https://github.com/rust-lang/rust/issues/130180
294            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}