diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/zerovec/src/ule/tuple.rs | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/zerovec/src/ule/tuple.rs')
-rw-r--r-- | third_party/rust/zerovec/src/ule/tuple.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/third_party/rust/zerovec/src/ule/tuple.rs b/third_party/rust/zerovec/src/ule/tuple.rs new file mode 100644 index 0000000000..3e0f291b3f --- /dev/null +++ b/third_party/rust/zerovec/src/ule/tuple.rs @@ -0,0 +1,179 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! ULE impls for tuples. +//! +//! Rust does not guarantee the layout of tuples, so ZeroVec defines its own tuple ULE types. +//! +//! Impls are defined for tuples of up to 6 elements. For longer tuples, use a custom struct +//! with [`#[make_ule]`](crate::make_ule). +//! +//! # Examples +//! +//! ``` +//! use zerovec::ZeroVec; +//! +//! // ZeroVec of tuples! +//! let zerovec: ZeroVec<(u32, char)> = [(1, 'a'), (1234901, '啊'), (100, 'अ')] +//! .iter() +//! .copied() +//! .collect(); +//! +//! assert_eq!(zerovec.get(1), Some((1234901, '啊'))); +//! ``` + +use super::*; +use core::fmt; +use core::mem; + +macro_rules! tuple_ule { + ($name:ident, $len:literal, [ $($t:ident $i:tt),+ ]) => { + #[doc = concat!("ULE type for tuples with ", $len, " elements.")] + #[repr(packed)] + #[allow(clippy::exhaustive_structs)] // stable + pub struct $name<$($t),+>($(pub $t),+); + + // Safety (based on the safety checklist on the ULE trait): + // 1. TupleULE does not include any uninitialized or padding bytes. + // (achieved by `#[repr(packed)]` on a struct containing only ULE fields) + // 2. TupleULE is aligned to 1 byte. + // (achieved by `#[repr(packed)]` on a struct containing only ULE fields) + // 3. The impl of validate_byte_slice() returns an error if any byte is not valid. + // 4. The impl of validate_byte_slice() returns an error if there are extra bytes. + // 5. The other ULE methods use the default impl. + // 6. TupleULE byte equality is semantic equality by relying on the ULE equality + // invariant on the subfields + unsafe impl<$($t: ULE),+> ULE for $name<$($t),+> { + fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> { + // expands to: 0size + mem::size_of::<A>() + mem::size_of::<B>(); + let ule_bytes = 0usize $(+ mem::size_of::<$t>())+; + if bytes.len() % ule_bytes != 0 { + return Err(ZeroVecError::length::<Self>(bytes.len())); + } + for chunk in bytes.chunks(ule_bytes) { + let mut i = 0; + $( + let j = i; + i += mem::size_of::<$t>(); + #[allow(clippy::indexing_slicing)] // length checked + <$t>::validate_byte_slice(&chunk[j..i])?; + )+ + } + Ok(()) + } + } + + impl<$($t: AsULE),+> AsULE for ($($t),+) { + type ULE = $name<$(<$t>::ULE),+>; + + #[inline] + fn to_unaligned(self) -> Self::ULE { + $name($( + self.$i.to_unaligned() + ),+) + } + + #[inline] + fn from_unaligned(unaligned: Self::ULE) -> Self { + ($( + <$t>::from_unaligned(unaligned.$i) + ),+) + } + } + + impl<$($t: fmt::Debug + ULE),+> fmt::Debug for $name<$($t),+> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + ($(self.$i),+).fmt(f) + } + } + + // We need manual impls since `#[derive()]` is disallowed on packed types + impl<$($t: PartialEq + ULE),+> PartialEq for $name<$($t),+> { + fn eq(&self, other: &Self) -> bool { + ($(self.$i),+).eq(&($(other.$i),+)) + } + } + + impl<$($t: Eq + ULE),+> Eq for $name<$($t),+> {} + + impl<$($t: PartialOrd + ULE),+> PartialOrd for $name<$($t),+> { + fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { + ($(self.$i),+).partial_cmp(&($(other.$i),+)) + } + } + + impl<$($t: Ord + ULE),+> Ord for $name<$($t),+> { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + ($(self.$i),+).cmp(&($(other.$i),+)) + } + } + + impl<$($t: ULE),+> Clone for $name<$($t),+> { + fn clone(&self) -> Self { + *self + } + } + + impl<$($t: ULE),+> Copy for $name<$($t),+> {} + + impl<'a, $($t: Ord + AsULE + 'static),+> crate::map::ZeroMapKV<'a> for ($($t),+) { + type Container = crate::ZeroVec<'a, ($($t),+)>; + type Slice = crate::ZeroSlice<($($t),+)>; + type GetType = $name<$(<$t>::ULE),+>; + type OwnedType = ($($t),+); + } + }; +} + +tuple_ule!(Tuple2ULE, "2", [ A 0, B 1 ]); +tuple_ule!(Tuple3ULE, "3", [ A 0, B 1, C 2 ]); +tuple_ule!(Tuple4ULE, "4", [ A 0, B 1, C 2, D 3 ]); +tuple_ule!(Tuple5ULE, "5", [ A 0, B 1, C 2, D 3, E 4 ]); +tuple_ule!(Tuple6ULE, "6", [ A 0, B 1, C 2, D 3, E 4, F 5 ]); + +#[test] +fn test_pairule_validate() { + use crate::ZeroVec; + let vec: Vec<(u32, char)> = vec![(1, 'a'), (1234901, '啊'), (100, 'अ')]; + let zerovec: ZeroVec<(u32, char)> = vec.iter().copied().collect(); + let bytes = zerovec.as_bytes(); + let zerovec2 = ZeroVec::parse_byte_slice(bytes).unwrap(); + assert_eq!(zerovec, zerovec2); + + // Test failed validation with a correctly sized but differently constrained tuple + // Note: 1234901 is not a valid char + let zerovec3 = ZeroVec::<(char, u32)>::parse_byte_slice(bytes); + assert!(zerovec3.is_err()); +} + +#[test] +fn test_tripleule_validate() { + use crate::ZeroVec; + let vec: Vec<(u32, char, i8)> = vec![(1, 'a', -5), (1234901, '啊', 3), (100, 'अ', -127)]; + let zerovec: ZeroVec<(u32, char, i8)> = vec.iter().copied().collect(); + let bytes = zerovec.as_bytes(); + let zerovec2 = ZeroVec::parse_byte_slice(bytes).unwrap(); + assert_eq!(zerovec, zerovec2); + + // Test failed validation with a correctly sized but differently constrained tuple + // Note: 1234901 is not a valid char + let zerovec3 = ZeroVec::<(char, i8, u32)>::parse_byte_slice(bytes); + assert!(zerovec3.is_err()); +} + +#[test] +fn test_quadule_validate() { + use crate::ZeroVec; + let vec: Vec<(u32, char, i8, u16)> = + vec![(1, 'a', -5, 3), (1234901, '啊', 3, 11), (100, 'अ', -127, 0)]; + let zerovec: ZeroVec<(u32, char, i8, u16)> = vec.iter().copied().collect(); + let bytes = zerovec.as_bytes(); + let zerovec2 = ZeroVec::parse_byte_slice(bytes).unwrap(); + assert_eq!(zerovec, zerovec2); + + // Test failed validation with a correctly sized but differently constrained tuple + // Note: 1234901 is not a valid char + let zerovec3 = ZeroVec::<(char, i8, u16, u32)>::parse_byte_slice(bytes); + assert!(zerovec3.is_err()); +} |