/rust/registry/src/index.crates.io-6f17d22bba15001f/zerovec-0.10.4/src/ule/tuple.rs
Line | Count | Source (jump to first uncovered line) |
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 | | //! ULE impls for tuples. |
6 | | //! |
7 | | //! Rust does not guarantee the layout of tuples, so ZeroVec defines its own tuple ULE types. |
8 | | //! |
9 | | //! Impls are defined for tuples of up to 6 elements. For longer tuples, use a custom struct |
10 | | //! with [`#[make_ule]`](crate::make_ule). |
11 | | //! |
12 | | //! # Examples |
13 | | //! |
14 | | //! ``` |
15 | | //! use zerovec::ZeroVec; |
16 | | //! |
17 | | //! // ZeroVec of tuples! |
18 | | //! let zerovec: ZeroVec<(u32, char)> = [(1, 'a'), (1234901, '啊'), (100, 'अ')] |
19 | | //! .iter() |
20 | | //! .copied() |
21 | | //! .collect(); |
22 | | //! |
23 | | //! assert_eq!(zerovec.get(1), Some((1234901, '啊'))); |
24 | | //! ``` |
25 | | |
26 | | use super::*; |
27 | | use core::fmt; |
28 | | use core::mem; |
29 | | |
30 | | macro_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)] // stable |
35 | | pub struct $name<$($t),+>($(pub $t),+); |
36 | | |
37 | | // Safety (based on the safety checklist on the ULE trait): |
38 | | // 1. TupleULE does not include any uninitialized or padding bytes. |
39 | | // (achieved by `#[repr(C, packed)]` on a struct containing only ULE fields) |
40 | | // 2. TupleULE is aligned to 1 byte. |
41 | | // (achieved by `#[repr(C, packed)]` on a struct containing only ULE fields) |
42 | | // 3. The impl of validate_byte_slice() returns an error if any byte is not valid. |
43 | | // 4. The impl of validate_byte_slice() returns an error if there are extra bytes. |
44 | | // 5. The other ULE methods use the default impl. |
45 | | // 6. TupleULE byte equality is semantic equality by relying on the ULE equality |
46 | | // invariant on the subfields |
47 | | unsafe impl<$($t: ULE),+> ULE for $name<$($t),+> { |
48 | 0 | fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> { |
49 | 0 | // expands to: 0size + mem::size_of::<A>() + mem::size_of::<B>(); |
50 | 0 | let ule_bytes = 0usize $(+ mem::size_of::<$t>())+; |
51 | 0 | if bytes.len() % ule_bytes != 0 { |
52 | 0 | return Err(ZeroVecError::length::<Self>(bytes.len())); |
53 | 0 | } |
54 | 0 | for chunk in bytes.chunks(ule_bytes) { |
55 | 0 | let mut i = 0; |
56 | | $( |
57 | 0 | let j = i; |
58 | 0 | i += mem::size_of::<$t>(); |
59 | 0 | #[allow(clippy::indexing_slicing)] // length checked |
60 | 0 | <$t>::validate_byte_slice(&chunk[j..i])?; |
61 | | )+ |
62 | | } |
63 | 0 | Ok(()) |
64 | 0 | } Unexecuted instantiation: <zerovec::ule::tuple::Tuple2ULE<_, _> as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <zerovec::ule::tuple::Tuple3ULE<_, _, _> as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <zerovec::ule::tuple::Tuple4ULE<_, _, _, _> as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <zerovec::ule::tuple::Tuple5ULE<_, _, _, _, _> as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <zerovec::ule::tuple::Tuple6ULE<_, _, _, _, _, _> as zerovec::ule::ULE>::validate_byte_slice |
65 | | } |
66 | | |
67 | | impl<$($t: AsULE),+> AsULE for ($($t),+) { |
68 | | type ULE = $name<$(<$t>::ULE),+>; |
69 | | |
70 | | #[inline] |
71 | 0 | fn to_unaligned(self) -> Self::ULE { |
72 | 0 | $name($( |
73 | 0 | self.$i.to_unaligned() |
74 | 0 | ),+) |
75 | 0 | } Unexecuted instantiation: <(_, _) as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <(_, _, _) as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <(_, _, _, _) as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <(_, _, _, _, _) as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <(_, _, _, _, _, _) as zerovec::ule::AsULE>::to_unaligned |
76 | | |
77 | | #[inline] |
78 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
79 | 0 | ($( |
80 | 0 | <$t>::from_unaligned(unaligned.$i) |
81 | 0 | ),+) |
82 | 0 | } Unexecuted instantiation: <(icu_calendar::provider::EraStartDate, tinystr::ascii::TinyAsciiStr<16>) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(icu_locid::subtags::script::Script, icu_locid::subtags::region::Region) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(tinystr::unvalidated::UnvalidatedTinyAsciiStr<3>, tinystr::unvalidated::UnvalidatedTinyAsciiStr<3>) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(tinystr::unvalidated::UnvalidatedTinyAsciiStr<3>, tinystr::unvalidated::UnvalidatedTinyAsciiStr<4>) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(tinystr::unvalidated::UnvalidatedTinyAsciiStr<4>, tinystr::unvalidated::UnvalidatedTinyAsciiStr<3>) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(icu_locid::subtags::language::Language, core::option::Option<icu_locid::subtags::script::Script>, core::option::Option<icu_locid::subtags::region::Region>) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(icu_locid::subtags::language::Language, icu_locid::subtags::region::Region) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(icu_locid::subtags::language::Language, icu_locid::subtags::script::Script) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(_, _) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(_, _, _) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(_, _, _, _) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(_, _, _, _, _) as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <(_, _, _, _, _, _) as zerovec::ule::AsULE>::from_unaligned |
83 | | } |
84 | | |
85 | | impl<$($t: fmt::Debug + ULE),+> fmt::Debug for $name<$($t),+> { |
86 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
87 | 0 | ($(self.$i),+).fmt(f) |
88 | 0 | } Unexecuted instantiation: <zerovec::ule::tuple::Tuple2ULE<_, _> as core::fmt::Debug>::fmt Unexecuted instantiation: <zerovec::ule::tuple::Tuple3ULE<_, _, _> as core::fmt::Debug>::fmt Unexecuted instantiation: <zerovec::ule::tuple::Tuple4ULE<_, _, _, _> as core::fmt::Debug>::fmt Unexecuted instantiation: <zerovec::ule::tuple::Tuple5ULE<_, _, _, _, _> as core::fmt::Debug>::fmt Unexecuted instantiation: <zerovec::ule::tuple::Tuple6ULE<_, _, _, _, _, _> as core::fmt::Debug>::fmt |
89 | | } |
90 | | |
91 | | // We need manual impls since `#[derive()]` is disallowed on packed types |
92 | | impl<$($t: PartialEq + ULE),+> PartialEq for $name<$($t),+> { |
93 | 0 | fn eq(&self, other: &Self) -> bool { |
94 | 0 | ($(self.$i),+).eq(&($(other.$i),+)) |
95 | 0 | } Unexecuted instantiation: <zerovec::ule::tuple::Tuple2ULE<_, _> as core::cmp::PartialEq>::eq Unexecuted instantiation: <zerovec::ule::tuple::Tuple3ULE<_, _, _> as core::cmp::PartialEq>::eq Unexecuted instantiation: <zerovec::ule::tuple::Tuple4ULE<_, _, _, _> as core::cmp::PartialEq>::eq Unexecuted instantiation: <zerovec::ule::tuple::Tuple5ULE<_, _, _, _, _> as core::cmp::PartialEq>::eq Unexecuted instantiation: <zerovec::ule::tuple::Tuple6ULE<_, _, _, _, _, _> as core::cmp::PartialEq>::eq |
96 | | } |
97 | | |
98 | | impl<$($t: Eq + ULE),+> Eq for $name<$($t),+> {} |
99 | | |
100 | | impl<$($t: PartialOrd + ULE),+> PartialOrd for $name<$($t),+> { |
101 | 0 | fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { |
102 | 0 | ($(self.$i),+).partial_cmp(&($(other.$i),+)) |
103 | 0 | } Unexecuted instantiation: <zerovec::ule::tuple::Tuple2ULE<_, _> as core::cmp::PartialOrd>::partial_cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple3ULE<_, _, _> as core::cmp::PartialOrd>::partial_cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple4ULE<_, _, _, _> as core::cmp::PartialOrd>::partial_cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple5ULE<_, _, _, _, _> as core::cmp::PartialOrd>::partial_cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple6ULE<_, _, _, _, _, _> as core::cmp::PartialOrd>::partial_cmp |
104 | | } |
105 | | |
106 | | impl<$($t: Ord + ULE),+> Ord for $name<$($t),+> { |
107 | 0 | fn cmp(&self, other: &Self) -> core::cmp::Ordering { |
108 | 0 | ($(self.$i),+).cmp(&($(other.$i),+)) |
109 | 0 | } Unexecuted instantiation: <zerovec::ule::tuple::Tuple2ULE<_, _> as core::cmp::Ord>::cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple3ULE<_, _, _> as core::cmp::Ord>::cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple4ULE<_, _, _, _> as core::cmp::Ord>::cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple5ULE<_, _, _, _, _> as core::cmp::Ord>::cmp Unexecuted instantiation: <zerovec::ule::tuple::Tuple6ULE<_, _, _, _, _, _> as core::cmp::Ord>::cmp |
110 | | } |
111 | | |
112 | | impl<$($t: ULE),+> Clone for $name<$($t),+> { |
113 | 0 | fn clone(&self) -> Self { |
114 | 0 | *self |
115 | 0 | } Unexecuted instantiation: <zerovec::ule::tuple::Tuple2ULE<_, _> as core::clone::Clone>::clone Unexecuted instantiation: <zerovec::ule::tuple::Tuple3ULE<_, _, _> as core::clone::Clone>::clone Unexecuted instantiation: <zerovec::ule::tuple::Tuple4ULE<_, _, _, _> as core::clone::Clone>::clone Unexecuted instantiation: <zerovec::ule::tuple::Tuple5ULE<_, _, _, _, _> as core::clone::Clone>::clone Unexecuted instantiation: <zerovec::ule::tuple::Tuple6ULE<_, _, _, _, _, _> as core::clone::Clone>::clone |
116 | | } |
117 | | |
118 | | impl<$($t: ULE),+> Copy for $name<$($t),+> {} |
119 | | |
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 | | |
129 | | tuple_ule!(Tuple2ULE, "2", [ A 0, B 1 ]); |
130 | | tuple_ule!(Tuple3ULE, "3", [ A 0, B 1, C 2 ]); |
131 | | tuple_ule!(Tuple4ULE, "4", [ A 0, B 1, C 2, D 3 ]); |
132 | | tuple_ule!(Tuple5ULE, "5", [ A 0, B 1, C 2, D 3, E 4 ]); |
133 | | tuple_ule!(Tuple6ULE, "6", [ A 0, B 1, C 2, D 3, E 4, F 5 ]); |
134 | | |
135 | | #[test] |
136 | | fn 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_byte_slice(bytes).unwrap(); |
142 | | assert_eq!(zerovec, zerovec2); |
143 | | |
144 | | // Test failed validation with a correctly sized but differently constrained tuple |
145 | | // Note: 1234901 is not a valid char |
146 | | let zerovec3 = ZeroVec::<(char, u32)>::parse_byte_slice(bytes); |
147 | | assert!(zerovec3.is_err()); |
148 | | } |
149 | | |
150 | | #[test] |
151 | | fn 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_byte_slice(bytes).unwrap(); |
157 | | assert_eq!(zerovec, zerovec2); |
158 | | |
159 | | // Test failed validation with a correctly sized but differently constrained tuple |
160 | | // Note: 1234901 is not a valid char |
161 | | let zerovec3 = ZeroVec::<(char, i8, u32)>::parse_byte_slice(bytes); |
162 | | assert!(zerovec3.is_err()); |
163 | | } |
164 | | |
165 | | #[test] |
166 | | fn 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_byte_slice(bytes).unwrap(); |
173 | | assert_eq!(zerovec, zerovec2); |
174 | | |
175 | | // Test failed validation with a correctly sized but differently constrained tuple |
176 | | // Note: 1234901 is not a valid char |
177 | | let zerovec3 = ZeroVec::<(char, i8, u16, u32)>::parse_byte_slice(bytes); |
178 | | assert!(zerovec3.is_err()); |
179 | | } |