Coverage Report

Created: 2026-05-16 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zerovec-0.11.6/src/ule/tuplevar.rs
Line
Count
Source
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
14
use super::*;
15
use crate::varzerovec::{Index16, VarZeroVecFormat};
16
use core::fmt;
17
use core::marker::PhantomData;
18
use zerofrom::ZeroFrom;
19
20
macro_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
0
                pub fn $t(&self) -> &$T {
46
                     // Safety: See invariant of `multi`.
47
                    unsafe {
48
0
                        self.multi.get_field::<$T>($i)
49
                    }
50
0
                }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _>>::a
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _>>::b
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>::a
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>::b
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>::c
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>::a
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>::b
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>::c
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>::d
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>::a
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>::b
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>::c
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>::d
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>::e
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>::a
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>::b
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>::c
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>::d
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>::e
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>::f
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
0
            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
0
                let multi = <MultiFieldsULE<$len, Format> as VarULE>::parse_bytes(bytes)?;
75
                $(
76
                    // Safety invariant: $i < $len, from the macro invocation
77
                    unsafe {
78
0
                        multi.validate_field::<$T>($i)?;
79
                    }
80
                )+
81
0
                Ok(())
82
0
            }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _> as zerovec::ule::VarULE>::validate_bytes
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _> as zerovec::ule::VarULE>::validate_bytes
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _> as zerovec::ule::VarULE>::validate_bytes
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _> as zerovec::ule::VarULE>::validate_bytes
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _> as zerovec::ule::VarULE>::validate_bytes
83
84
0
            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
0
                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
0
                &*(multi as *const MultiFieldsULE<$len, Format> as *const $name<$($T,)+ Format>)
92
0
            }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _> as zerovec::ule::VarULE>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _> as zerovec::ule::VarULE>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _> as zerovec::ule::VarULE>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _> as zerovec::ule::VarULE>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _> as zerovec::ule::VarULE>::from_bytes_unchecked
93
        }
94
95
        impl<$($T: fmt::Debug + VarULE + ?Sized,)+ Format: VarZeroVecFormat> fmt::Debug for $name<$($T,)+ Format> {
96
0
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
97
0
                ($(self.$t(),)+).fmt(f)
98
0
            }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _> as core::fmt::Debug>::fmt
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _> as core::fmt::Debug>::fmt
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _> as core::fmt::Debug>::fmt
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _> as core::fmt::Debug>::fmt
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _> as core::fmt::Debug>::fmt
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
0
            fn eq(&self, other: &Self) -> bool {
104
105
0
                ($(self.$t(),)+).eq(&($(other.$t(),)+))
106
0
            }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _> as core::cmp::PartialEq>::eq
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _> as core::cmp::PartialEq>::eq
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _> as core::cmp::PartialEq>::eq
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _> as core::cmp::PartialEq>::eq
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _> as core::cmp::PartialEq>::eq
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
0
            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
113
0
                ($(self.$t(),)+).partial_cmp(&($(other.$t(),)+))
114
0
            }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _> as core::cmp::PartialOrd>::partial_cmp
115
        }
116
117
        impl<$($T: Ord + VarULE + ?Sized,)+ Format: VarZeroVecFormat> Ord for $name<$($T,)+ Format>  {
118
0
            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
119
0
                ($(self.$t(),)+).cmp(&($(other.$t(),)+))
120
0
            }
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple2VarULE<_, _, _> as core::cmp::Ord>::cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _> as core::cmp::Ord>::cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _> as core::cmp::Ord>::cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _> as core::cmp::Ord>::cmp
Unexecuted instantiation: <zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _> as core::cmp::Ord>::cmp
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
0
            fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
135
                // unnecessary if the other two are implemented
136
0
                unreachable!()
Unexecuted instantiation: <(_, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple2VarULE<_, _, _>>>::encode_var_ule_as_slices::<_, _>
Unexecuted instantiation: <(_, _, _, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>>::encode_var_ule_as_slices::<_, _>
Unexecuted instantiation: <(_, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>>::encode_var_ule_as_slices::<_, _>
Unexecuted instantiation: <(_, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>>::encode_var_ule_as_slices::<_, _>
Unexecuted instantiation: <(_, _, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>>::encode_var_ule_as_slices::<_, _>
137
            }
138
139
            #[inline]
140
0
            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
0
                MultiFieldsULE::<$len, Format>::compute_encoded_len_for([$(self.$i.encode_var_ule_len()),+])
144
0
            }
Unexecuted instantiation: <(_, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple2VarULE<_, _, _>>>::encode_var_ule_len
Unexecuted instantiation: <(_, _, _, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>>::encode_var_ule_len
Unexecuted instantiation: <(_, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>>::encode_var_ule_len
Unexecuted instantiation: <(_, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>>::encode_var_ule_len
Unexecuted instantiation: <(_, _, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>>::encode_var_ule_len
145
146
            #[inline]
147
0
            fn encode_var_ule_write(&self, dst: &mut [u8]) {
148
0
                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
0
                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
0
                    unsafe {
155
0
                        multi.set_field_at::<$T, $T_alt>($i, &self.$i);
156
0
                    }
157
                )+
158
0
            }
Unexecuted instantiation: <(_, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple2VarULE<_, _, _>>>::encode_var_ule_write
Unexecuted instantiation: <(_, _, _, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>>::encode_var_ule_write
Unexecuted instantiation: <(_, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>>::encode_var_ule_write
Unexecuted instantiation: <(_, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>>::encode_var_ule_write
Unexecuted instantiation: <(_, _, _, _, _) as zerovec::ule::encode::EncodeAsVarULE<zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>>::encode_var_ule_write
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
0
            fn zero_from(other: &'a $name<$($T,)+ Format>) -> Self {
175
0
                (
176
0
                    $($T_alt::zero_from(other.$t()),)+
177
0
                )
178
0
            }
Unexecuted instantiation: <(_, _) as zerofrom::zero_from::ZeroFrom<zerovec::ule::tuplevar::Tuple2VarULE<_, _, _>>>::zero_from
Unexecuted instantiation: <(_, _, _, _, _, _) as zerofrom::zero_from::ZeroFrom<zerovec::ule::tuplevar::Tuple6VarULE<_, _, _, _, _, _, _>>>::zero_from
Unexecuted instantiation: <(_, _, _) as zerofrom::zero_from::ZeroFrom<zerovec::ule::tuplevar::Tuple3VarULE<_, _, _, _>>>::zero_from
Unexecuted instantiation: <(_, _, _, _) as zerofrom::zero_from::ZeroFrom<zerovec::ule::tuplevar::Tuple4VarULE<_, _, _, _, _>>>::zero_from
Unexecuted instantiation: <(_, _, _, _, _) as zerofrom::zero_from::ZeroFrom<zerovec::ule::tuplevar::Tuple5VarULE<_, _, _, _, _, _>>>::zero_from
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
tuple_varule!(Tuple2VarULE, 2, [ A a AE 0, B b BE 1 ]);
240
tuple_varule!(Tuple3VarULE, 3, [ A a AE 0, B b BE 1, C c CE 2 ]);
241
tuple_varule!(Tuple4VarULE, 4, [ A a AE 0, B b BE 1, C c CE 2, D d DE 3 ]);
242
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
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)]
246
mod 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
}