summaryrefslogtreecommitdiffstats
path: root/vendor/zerovec/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/zerovec/src')
-rw-r--r--vendor/zerovec/src/flexzerovec/databake.rs6
-rw-r--r--vendor/zerovec/src/flexzerovec/slice.rs17
-rw-r--r--vendor/zerovec/src/hashmap/mod.rs18
-rw-r--r--vendor/zerovec/src/hashmap/serde.rs2
-rw-r--r--vendor/zerovec/src/lib.rs41
-rw-r--r--vendor/zerovec/src/map/borrowed.rs11
-rw-r--r--vendor/zerovec/src/map/databake.rs4
-rw-r--r--vendor/zerovec/src/map2d/borrowed.rs7
-rw-r--r--vendor/zerovec/src/map2d/databake.rs16
-rw-r--r--vendor/zerovec/src/map2d/map.rs16
-rw-r--r--vendor/zerovec/src/samples.rs30
-rw-r--r--vendor/zerovec/src/ule/chars.rs45
-rw-r--r--vendor/zerovec/src/ule/custom.rs4
-rw-r--r--vendor/zerovec/src/ule/encode.rs8
-rw-r--r--vendor/zerovec/src/ule/macros.rs29
-rw-r--r--vendor/zerovec/src/ule/mod.rs10
-rw-r--r--vendor/zerovec/src/ule/multi.rs8
-rw-r--r--vendor/zerovec/src/ule/option.rs3
-rw-r--r--vendor/zerovec/src/ule/plain.rs145
-rw-r--r--vendor/zerovec/src/ule/tuple.rs11
-rw-r--r--vendor/zerovec/src/ule/unvalidated.rs318
-rw-r--r--vendor/zerovec/src/varzerovec/components.rs23
-rw-r--r--vendor/zerovec/src/varzerovec/databake.rs8
-rw-r--r--vendor/zerovec/src/varzerovec/owned.rs22
-rw-r--r--vendor/zerovec/src/varzerovec/serde.rs26
-rw-r--r--vendor/zerovec/src/varzerovec/slice.rs10
-rw-r--r--vendor/zerovec/src/varzerovec/vec.rs34
-rw-r--r--vendor/zerovec/src/yoke_impls.rs47
-rw-r--r--vendor/zerovec/src/zerovec/databake.rs10
-rw-r--r--vendor/zerovec/src/zerovec/mod.rs165
-rw-r--r--vendor/zerovec/src/zerovec/serde.rs2
-rw-r--r--vendor/zerovec/src/zerovec/slice.rs29
32 files changed, 880 insertions, 245 deletions
diff --git a/vendor/zerovec/src/flexzerovec/databake.rs b/vendor/zerovec/src/flexzerovec/databake.rs
index 4ce5f7dea..bd165352e 100644
--- a/vendor/zerovec/src/flexzerovec/databake.rs
+++ b/vendor/zerovec/src/flexzerovec/databake.rs
@@ -9,7 +9,7 @@ impl Bake for FlexZeroVec<'_> {
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("zerovec");
if self.is_empty() {
- quote! { ::zerovec::vecs::FlexZeroVec::new() }
+ quote! { zerovec::vecs::FlexZeroVec::new() }
} else {
let slice = self.as_ref().bake(env);
quote! { #slice.as_flexzerovec() }
@@ -21,10 +21,10 @@ impl Bake for &FlexZeroSlice {
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("zerovec");
if self.is_empty() {
- quote! { ::zerovec::vecs::FlexZeroSlice::new_empty() }
+ quote! { zerovec::vecs::FlexZeroSlice::new_empty() }
} else {
let bytes = databake::Bake::bake(&self.as_bytes(), env);
- quote! { unsafe { ::zerovec::vecs::FlexZeroSlice::from_byte_slice_unchecked(#bytes) } }
+ quote! { unsafe { zerovec::vecs::FlexZeroSlice::from_byte_slice_unchecked(#bytes) } }
}
}
}
diff --git a/vendor/zerovec/src/flexzerovec/slice.rs b/vendor/zerovec/src/flexzerovec/slice.rs
index fb58d6215..41cb7116f 100644
--- a/vendor/zerovec/src/flexzerovec/slice.rs
+++ b/vendor/zerovec/src/flexzerovec/slice.rs
@@ -134,18 +134,18 @@ impl FlexZeroSlice {
// equal to the length of the `data` field, which will be one less than the length of the
// overall array.
#[allow(clippy::panic)] // panic is documented in function contract
- let (_, remainder) = match bytes.split_last() {
- Some(v) => v,
- None => panic!("slice should be non-empty"),
- };
- &*(remainder as *const [u8] as *const Self)
+ if bytes.is_empty() {
+ panic!("from_byte_slice_unchecked called with empty slice")
+ }
+ let slice = core::ptr::slice_from_raw_parts(bytes.as_ptr(), bytes.len() - 1);
+ &*(slice as *const Self)
}
#[inline]
pub(crate) unsafe fn from_byte_slice_mut_unchecked(bytes: &mut [u8]) -> &mut Self {
// Safety: See comments in `from_byte_slice_unchecked`
- let remainder = core::slice::from_raw_parts_mut(bytes.as_mut_ptr(), bytes.len() - 1);
- &mut *(remainder as *mut [u8] as *mut Self)
+ let remainder = core::ptr::slice_from_raw_parts_mut(bytes.as_mut_ptr(), bytes.len() - 1);
+ &mut *(remainder as *mut Self)
}
/// Returns this slice as its underlying `&[u8]` byte buffer representation.
@@ -298,8 +298,7 @@ impl FlexZeroSlice {
/// assert_eq!(pairs_it.next(), None);
/// ```
pub fn iter_pairs(&self) -> impl Iterator<Item = (usize, Option<usize>)> + '_ {
- self.iter()
- .zip(self.iter().skip(1).map(Some).chain(core::iter::once(None)))
+ self.iter().zip(self.iter().skip(1).map(Some).chain([None]))
}
/// Creates a `Vec<usize>` from a [`FlexZeroSlice`] (or `FlexZeroVec`).
diff --git a/vendor/zerovec/src/hashmap/mod.rs b/vendor/zerovec/src/hashmap/mod.rs
index 5d91114ad..e3aed1198 100644
--- a/vendor/zerovec/src/hashmap/mod.rs
+++ b/vendor/zerovec/src/hashmap/mod.rs
@@ -20,8 +20,8 @@ mod serde;
/// ```
/// use zerovec::ZeroHashMap;
///
-/// let kv = vec![(0, "a"), (1, "b"), (2, "c")];
-/// let hashmap: ZeroHashMap<i32, str> = ZeroHashMap::from_iter(kv.into_iter());
+/// let hashmap =
+/// ZeroHashMap::<i32, str>::from_iter([(0, "a"), (1, "b"), (2, "c")]);
/// assert_eq!(hashmap.get(&0), Some("a"));
/// assert_eq!(hashmap.get(&2), Some("c"));
/// assert_eq!(hashmap.get(&4), None);
@@ -91,8 +91,7 @@ where
/// ```
/// use zerovec::ZeroHashMap;
///
- /// let hashmap: ZeroHashMap<str, str> =
- /// ZeroHashMap::from_iter(vec![("a", "A"), ("z", "Z")].into_iter());
+ /// let hashmap = ZeroHashMap::<str, str>::from_iter([("a", "A"), ("z", "Z")]);
///
/// assert_eq!(hashmap.get("a"), Some("A"));
/// assert_eq!(hashmap.get("z"), Some("Z"));
@@ -111,8 +110,7 @@ where
/// ```rust
/// use zerovec::ZeroHashMap;
///
- /// let hashmap: ZeroHashMap<str, str> =
- /// ZeroHashMap::from_iter(vec![("a", "A"), ("z", "Z")].into_iter());
+ /// let hashmap = ZeroHashMap::<str, str>::from_iter([("a", "A"), ("z", "Z")]);
///
/// assert!(hashmap.contains_key("a"));
/// assert!(!hashmap.contains_key("p"));
@@ -176,8 +174,12 @@ where
/// ```
/// use zerovec::ZeroHashMap;
///
- /// let kv: Vec<(i32, &str)> = vec![(1, "a"), (2, "b"), (3, "c"), (4, "d")];
- /// let hashmap: ZeroHashMap<i32, str> = ZeroHashMap::from_iter(kv.into_iter());
+ /// let hashmap = ZeroHashMap::<i32, str>::from_iter([
+ /// (1, "a"),
+ /// (2, "b"),
+ /// (3, "c"),
+ /// (4, "d"),
+ /// ]);
/// assert_eq!(hashmap.get(&1), Some("a"));
/// assert_eq!(hashmap.get(&2), Some("b"));
/// assert_eq!(hashmap.get(&3), Some("c"));
diff --git a/vendor/zerovec/src/hashmap/serde.rs b/vendor/zerovec/src/hashmap/serde.rs
index 2d724ac05..7a4941205 100644
--- a/vendor/zerovec/src/hashmap/serde.rs
+++ b/vendor/zerovec/src/hashmap/serde.rs
@@ -77,7 +77,7 @@ mod test {
}
fn make_zerohashmap() -> ZeroHashMap<'static, u32, str> {
- ZeroHashMap::from_iter(vec![(0, "a"), (1, "b"), (2, "c")].into_iter())
+ ZeroHashMap::from_iter([(0, "a"), (1, "b"), (2, "c")])
}
fn build_invalid_hashmap_str(
diff --git a/vendor/zerovec/src/lib.rs b/vendor/zerovec/src/lib.rs
index add52f113..961d62f34 100644
--- a/vendor/zerovec/src/lib.rs
+++ b/vendor/zerovec/src/lib.rs
@@ -403,7 +403,8 @@ pub use zerovec_derive::make_ule;
///
/// This can be attached to structs containing only [`AsULE`] types with the last fields being
/// [`Cow<'a, str>`](alloc::borrow::Cow), [`ZeroSlice`], or [`VarZeroSlice`]. If there is more than one such field, it will be represented
-/// using [`MultiFieldsULE`](crate::ule::MultiFieldsULE) and getters will be generated.
+/// using [`MultiFieldsULE`](crate::ule::MultiFieldsULE) and getters will be generated. Other VarULE fields will be detected if they are
+/// tagged with `#[zerovec::varule(NameOfVarULETy)]`.
///
/// The type must be [`PartialEq`] and [`Eq`].
///
@@ -517,3 +518,41 @@ pub use zerovec_derive::make_ule;
/// ```
#[cfg(feature = "derive")]
pub use zerovec_derive::make_varule;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use core::mem::size_of;
+
+ /// Checks that the size of the type is one of the given sizes.
+ /// The size might differ across Rust versions or channels.
+ macro_rules! check_size_of {
+ ($sizes:pat, $type:path) => {
+ assert!(
+ matches!(size_of::<$type>(), $sizes),
+ concat!(stringify!($type), " is of size {}"),
+ size_of::<$type>()
+ );
+ };
+ }
+
+ #[test]
+ fn check_sizes() {
+ check_size_of!(24, ZeroVec<u8>);
+ check_size_of!(24, ZeroVec<u32>);
+ check_size_of!(32 | 24, VarZeroVec<[u8]>);
+ check_size_of!(32 | 24, VarZeroVec<str>);
+ check_size_of!(48, ZeroMap<u32, u32>);
+ check_size_of!(56 | 48, ZeroMap<u32, str>);
+ check_size_of!(56 | 48, ZeroMap<str, u32>);
+ check_size_of!(64 | 48, ZeroMap<str, str>);
+ check_size_of!(120 | 96, ZeroMap2d<str, str, str>);
+ check_size_of!(32 | 24, vecs::FlexZeroVec);
+
+ check_size_of!(32, Option<ZeroVec<u8>>);
+ check_size_of!(32, Option<VarZeroVec<str>>);
+ check_size_of!(64 | 56, Option<ZeroMap<str, str>>);
+ check_size_of!(120 | 104, Option<ZeroMap2d<str, str, str>>);
+ check_size_of!(32, Option<vecs::FlexZeroVec>);
+ }
+}
diff --git a/vendor/zerovec/src/map/borrowed.rs b/vendor/zerovec/src/map/borrowed.rs
index bc93ee497..98b2d2f9d 100644
--- a/vendor/zerovec/src/map/borrowed.rs
+++ b/vendor/zerovec/src/map/borrowed.rs
@@ -63,10 +63,7 @@ where
V: ?Sized,
{
fn clone(&self) -> Self {
- ZeroMapBorrowed {
- keys: self.keys,
- values: self.values,
- }
+ *self
}
}
@@ -252,6 +249,12 @@ where
self.values.get(index)
}
+ /// For cases when `V` is fixed-size, obtain a direct copy of `V` instead of `V::ULE`
+ pub fn get_copied_by(&self, predicate: impl FnMut(&K) -> Ordering) -> Option<V> {
+ let index = self.keys.zvl_binary_search_by(predicate).ok()?;
+ self.values.get(index)
+ }
+
/// Similar to [`Self::iter()`] except it returns a direct copy of the values instead of references
/// to `V::ULE`, in cases when `V` is fixed-size
pub fn iter_copied_values<'b>(
diff --git a/vendor/zerovec/src/map/databake.rs b/vendor/zerovec/src/map/databake.rs
index fceb6a966..f861e5c29 100644
--- a/vendor/zerovec/src/map/databake.rs
+++ b/vendor/zerovec/src/map/databake.rs
@@ -16,7 +16,7 @@ where
env.insert("zerovec");
let keys = self.keys.bake(env);
let values = self.values.bake(env);
- quote! { unsafe { #[allow(unused_unsafe)] ::zerovec::ZeroMap::from_parts_unchecked(#keys, #values) } }
+ quote! { unsafe { #[allow(unused_unsafe)] zerovec::ZeroMap::from_parts_unchecked(#keys, #values) } }
}
}
@@ -31,7 +31,7 @@ where
env.insert("zerovec");
let keys = self.keys.bake(env);
let values = self.values.bake(env);
- quote! { unsafe { #[allow(unused_unsafe)] ::zerovec::maps::ZeroMapBorrowed::from_parts_unchecked(#keys, #values) } }
+ quote! { unsafe { #[allow(unused_unsafe)] zerovec::maps::ZeroMapBorrowed::from_parts_unchecked(#keys, #values) } }
}
}
diff --git a/vendor/zerovec/src/map2d/borrowed.rs b/vendor/zerovec/src/map2d/borrowed.rs
index 209da299b..166f1be74 100644
--- a/vendor/zerovec/src/map2d/borrowed.rs
+++ b/vendor/zerovec/src/map2d/borrowed.rs
@@ -73,12 +73,7 @@ where
V: ?Sized,
{
fn clone(&self) -> Self {
- ZeroMap2dBorrowed {
- keys0: self.keys0,
- joiner: self.joiner,
- keys1: self.keys1,
- values: self.values,
- }
+ *self
}
}
diff --git a/vendor/zerovec/src/map2d/databake.rs b/vendor/zerovec/src/map2d/databake.rs
index 65e475c32..c5b9aca54 100644
--- a/vendor/zerovec/src/map2d/databake.rs
+++ b/vendor/zerovec/src/map2d/databake.rs
@@ -20,7 +20,7 @@ where
let joiner = self.joiner.bake(env);
let keys1 = self.keys1.bake(env);
let values = self.values.bake(env);
- quote! { unsafe { #[allow(unused_unsafe)] ::zerovec::ZeroMap2d::from_parts_unchecked(#keys0, #joiner, #keys1, #values) } }
+ quote! { unsafe { #[allow(unused_unsafe)] zerovec::ZeroMap2d::from_parts_unchecked(#keys0, #joiner, #keys1, #values) } }
}
}
@@ -39,7 +39,7 @@ where
let joiner = self.joiner.bake(env);
let keys1 = self.keys1.bake(env);
let values = self.values.bake(env);
- quote! { unsafe { #[allow(unused_unsafe)] ::zerovec::maps::ZeroMap2dBorrowed::from_parts_unchecked(#keys0, #joiner, #keys1, #values) } }
+ quote! { unsafe { #[allow(unused_unsafe)] zerovec::maps::ZeroMap2dBorrowed::from_parts_unchecked(#keys0, #joiner, #keys1, #values) } }
}
}
@@ -52,7 +52,7 @@ fn test_baked_map() {
crate::ZeroMap2d::from_parts_unchecked(
unsafe {
crate::VarZeroVec::from_bytes_unchecked(
- b"arcaz\0cu\0en\0ff\0grckk\0ku\0ky\0lifmanmn\0pa\0palsd\0tg\0ug\0unruz\0yuezh\0"
+ b"\x0E\0\0\0\0\0\x05\0\x07\0\t\0\x0B\0\x10\0\x12\0\x14\0\x1C\0\x1E\0#\0%\0'\0,\0arcazcuenffgrckkkukylifmanmnpapalsdtgugunruzyuezh"
)
},
unsafe {
@@ -62,12 +62,12 @@ fn test_baked_map() {
},
unsafe {
crate::VarZeroVec::from_bytes_unchecked(
- b"NbatPalmArabGlagShawAdlmLinbArabArabYeziArabLatnLimbNkooMongArabPhlpDevaKhojSindArabCyrlDevaArabHansBopoHanbHant"
+ b"\x1C\0\0\0\0\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0 \0$\0(\0,\x000\x004\08\0<\0@\0D\0H\0L\0P\0T\0X\0\\\0`\0d\0h\0l\0NbatPalmArabGlagShawAdlmLinbArabArabYeziArabLatnLimbNkooMongArabPhlpDevaKhojSindArabCyrlDevaArabHansBopoHanbHant"
)
},
unsafe {
crate::VarZeroVec::from_bytes_unchecked(
- b"JO\0SY\0IR\0BG\0GB\0GN\0GR\0CN\0IQ\0GE\0CN\0TR\0IN\0GN\0CN\0PK\0CN\0IN\0IN\0IN\0PK\0KZ\0NP\0AF\0CN\0TW\0TW\0TW\0"
+ b"\x1C\0\0\0\0\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0\x12\0\x14\0\x16\0\x18\0\x1A\0\x1C\0\x1E\0 \0\"\0$\0&\0(\0*\0,\0.\x000\x002\x004\x006\0JOSYIRBGGBGNGRCNIQGECNTRINGNCNPKCNINININPKKZNPAFCNTWTWTW"
)
},
)
@@ -85,7 +85,7 @@ fn test_baked_borrowed_map() {
crate::maps::ZeroMap2dBorrowed::from_parts_unchecked(
unsafe {
crate::VarZeroSlice::from_bytes_unchecked(
- b"arcaz\0cu\0en\0ff\0grckk\0ku\0ky\0lifmanmn\0pa\0palsd\0tg\0ug\0unruz\0yuezh\0"
+ b"\x0E\0\0\0\0\0\x05\0\x07\0\t\0\x0B\0\x10\0\x12\0\x14\0\x1C\0\x1E\0#\0%\0'\0,\0arcazcuenffgrckkkukylifmanmnpapalsdtgugunruzyuezh"
)
},
unsafe {
@@ -95,12 +95,12 @@ fn test_baked_borrowed_map() {
},
unsafe {
crate::VarZeroSlice::from_bytes_unchecked(
- b"NbatPalmArabGlagShawAdlmLinbArabArabYeziArabLatnLimbNkooMongArabPhlpDevaKhojSindArabCyrlDevaArabHansBopoHanbHant"
+ b"\x1C\0\0\0\0\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0 \0$\0(\0,\x000\x004\08\0<\0@\0D\0H\0L\0P\0T\0X\0\\\0`\0d\0h\0l\0NbatPalmArabGlagShawAdlmLinbArabArabYeziArabLatnLimbNkooMongArabPhlpDevaKhojSindArabCyrlDevaArabHansBopoHanbHant"
)
},
unsafe {
crate::VarZeroSlice::from_bytes_unchecked(
- b"JO\0SY\0IR\0BG\0GB\0GN\0GR\0CN\0IQ\0GE\0CN\0TR\0IN\0GN\0CN\0PK\0CN\0IN\0IN\0IN\0PK\0KZ\0NP\0AF\0CN\0TW\0TW\0TW\0"
+ b"\x1C\0\0\0\0\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0\x12\0\x14\0\x16\0\x18\0\x1A\0\x1C\0\x1E\0 \0\"\0$\0&\0(\0*\0,\0.\x000\x002\x004\x006\0JOSYIRBGGBGNGRCNIQGECNTRINGNCNPKCNINININPKKZNPAFCNTWTWTW"
)
},
)
diff --git a/vendor/zerovec/src/map2d/map.rs b/vendor/zerovec/src/map2d/map.rs
index 8bdefe792..90854018f 100644
--- a/vendor/zerovec/src/map2d/map.rs
+++ b/vendor/zerovec/src/map2d/map.rs
@@ -716,7 +716,7 @@ mod test {
assert_eq!(zm2d.get0(&0), None);
let result = zm2d.try_append(&3, "ccc", "CCC");
- assert!(matches!(result, None));
+ assert!(result.is_none());
assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3]), joiner: ZeroVec([1]), keys1: [\"ccc\"], values: [\"CCC\"] }");
assert_eq!(zm2d.get0(&0), None);
@@ -725,7 +725,7 @@ mod test {
assert_eq!(zm2d.get0(&99), None);
let result = zm2d.try_append(&3, "eee", "EEE");
- assert!(matches!(result, None));
+ assert!(result.is_none());
assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3]), joiner: ZeroVec([2]), keys1: [\"ccc\", \"eee\"], values: [\"CCC\", \"EEE\"] }");
assert_eq!(zm2d.get0(&0), None);
@@ -737,19 +737,19 @@ mod test {
// Out of order
let result = zm2d.try_append(&3, "ddd", "DD0");
- assert!(matches!(result, Some(_)));
+ assert!(result.is_some());
// Append a few more elements
let result = zm2d.try_append(&5, "ddd", "DD1");
- assert!(matches!(result, None));
+ assert!(result.is_none());
let result = zm2d.try_append(&7, "ddd", "DD2");
- assert!(matches!(result, None));
+ assert!(result.is_none());
let result = zm2d.try_append(&7, "eee", "EEE");
- assert!(matches!(result, None));
+ assert!(result.is_none());
let result = zm2d.try_append(&7, "www", "WWW");
- assert!(matches!(result, None));
+ assert!(result.is_none());
let result = zm2d.try_append(&9, "yyy", "YYY");
- assert!(matches!(result, None));
+ assert!(result.is_none());
assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3, 5, 7, 9]), joiner: ZeroVec([2, 3, 6, 7]), keys1: [\"ccc\", \"eee\", \"ddd\", \"ddd\", \"eee\", \"www\", \"yyy\"], values: [\"CCC\", \"EEE\", \"DD1\", \"DD2\", \"EEE\", \"WWW\", \"YYY\"] }");
assert_eq!(zm2d.get0(&0), None);
diff --git a/vendor/zerovec/src/samples.rs b/vendor/zerovec/src/samples.rs
index 7a9a73241..723aacded 100644
--- a/vendor/zerovec/src/samples.rs
+++ b/vendor/zerovec/src/samples.rs
@@ -44,9 +44,31 @@ pub const BINCODE_BUF: &[u8] = &[
0, 72, 73, 74, 0, 76, 77, 78, 0,
];
-/// Representation of a VarZeroVec<str> of length 4 as bytes.
-/// Safety: The bytes were manually verified to be valid.
+/// Representation of a VarZeroVec<str> with contents ["w", "ω", "文", "𑄃"]
pub const TEST_VARZEROSLICE_BYTES: &[u8] = &[
- 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 119, 207, 137, 230, 150, 135, 240,
- 145, 132, 131,
+ 4, 0, 0, 0, 0, 0, 1, 0, 3, 0, 6, 0, 119, 207, 137, 230, 150, 135, 240, 145, 132, 131,
];
+
+#[test]
+fn validate() {
+ use crate::{VarZeroVec, ZeroVec};
+
+ assert_eq!(
+ ZeroVec::<u32>::parse_byte_slice(TEST_BUFFER_LE).unwrap(),
+ ZeroVec::alloc_from_slice(TEST_SLICE)
+ );
+
+ assert_eq!(TEST_SLICE.iter().sum::<u32>(), TEST_SUM);
+
+ assert_eq!(
+ serde_json::from_str::<ZeroVec::<u32>>(JSON_STR).unwrap(),
+ ZeroVec::alloc_from_slice(TEST_SLICE)
+ );
+
+ assert_eq!(
+ bincode::deserialize::<ZeroVec::<u32>>(BINCODE_BUF).unwrap(),
+ ZeroVec::alloc_from_slice(TEST_SLICE)
+ );
+
+ VarZeroVec::<str>::parse_byte_slice(TEST_VARZEROSLICE_BYTES).unwrap();
+}
diff --git a/vendor/zerovec/src/ule/chars.rs b/vendor/zerovec/src/ule/chars.rs
index 7a4a97a4a..e0ec25240 100644
--- a/vendor/zerovec/src/ule/chars.rs
+++ b/vendor/zerovec/src/ule/chars.rs
@@ -6,10 +6,11 @@
//! ULE implementation for the `char` type.
use super::*;
+use crate::impl_ule_from_array;
use core::cmp::Ordering;
use core::convert::TryFrom;
-/// A u8 array of little-endian data corresponding to a Unicode code point.
+/// A u8 array of little-endian data corresponding to a Unicode scalar value.
///
/// The bytes of a `CharULE` are guaranteed to represent a little-endian-encoded u32 that is a
/// valid `char` and can be converted without validation.
@@ -40,6 +41,20 @@ use core::convert::TryFrom;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct CharULE([u8; 3]);
+impl CharULE {
+ /// Converts a [`char`] to a [`CharULE`]. This is equivalent to calling
+ /// [`AsULE::to_unaligned()`]
+ ///
+ /// See the type-level documentation for [`CharULE`] for more information.
+ #[inline]
+ pub const fn from_aligned(c: char) -> Self {
+ let [u0, u1, u2, _u3] = (c as u32).to_le_bytes();
+ Self([u0, u1, u2])
+ }
+
+ impl_ule_from_array!(char, CharULE, Self([0; 3]));
+}
+
// Safety (based on the safety checklist on the ULE trait):
// 1. CharULE does not include any uninitialized or padding bytes.
// (achieved by `#[repr(transparent)]` on a type that satisfies this invariant)
@@ -72,13 +87,12 @@ impl AsULE for char {
#[inline]
fn to_unaligned(self) -> Self::ULE {
- let [u0, u1, u2, _u3] = u32::from(self).to_le_bytes();
- CharULE([u0, u1, u2])
+ CharULE::from_aligned(self)
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
- // Safe because the bytes of CharULE are defined to represent a valid Unicode code point.
+ // Safe because the bytes of CharULE are defined to represent a valid Unicode scalar value.
unsafe {
Self::from_u32_unchecked(u32::from_le_bytes([
unaligned.0[0],
@@ -107,6 +121,25 @@ mod test {
use super::*;
#[test]
+ fn test_from_array() {
+ const CHARS: [char; 2] = ['a', '🙃'];
+ const CHARS_ULE: [CharULE; 2] = CharULE::from_array(CHARS);
+ assert_eq!(
+ CharULE::as_byte_slice(&CHARS_ULE),
+ &[0x61, 0x00, 0x00, 0x43, 0xF6, 0x01]
+ );
+ }
+
+ #[test]
+ fn test_from_array_zst() {
+ const CHARS: [char; 0] = [];
+ const CHARS_ULE: [CharULE; 0] = CharULE::from_array(CHARS);
+ let bytes = CharULE::as_byte_slice(&CHARS_ULE);
+ let empty: &[u8] = &[];
+ assert_eq!(bytes, empty);
+ }
+
+ #[test]
fn test_parse() {
// 1-byte, 2-byte, 3-byte, and two 4-byte character in UTF-8 (not as relevant in UTF-32)
let chars = ['w', 'ω', '文', '𑄃', '🙃'];
@@ -141,7 +174,7 @@ mod test {
.collect();
let u32_bytes: &[u8] = RawBytesULE::<4>::as_byte_slice(&u32_ules);
let parsed_ules_result = CharULE::parse_byte_slice(u32_bytes);
- assert!(matches!(parsed_ules_result, Err(_)));
+ assert!(parsed_ules_result.is_err());
// 0x20FFFF is out of range for a char
let u32s = [0x20FFFF];
@@ -152,6 +185,6 @@ mod test {
.collect();
let u32_bytes: &[u8] = RawBytesULE::<4>::as_byte_slice(&u32_ules);
let parsed_ules_result = CharULE::parse_byte_slice(u32_bytes);
- assert!(matches!(parsed_ules_result, Err(_)));
+ assert!(parsed_ules_result.is_err());
}
}
diff --git a/vendor/zerovec/src/ule/custom.rs b/vendor/zerovec/src/ule/custom.rs
index b2e4cb0e5..8cc6e9de4 100644
--- a/vendor/zerovec/src/ule/custom.rs
+++ b/vendor/zerovec/src/ule/custom.rs
@@ -129,8 +129,8 @@
//! }
//!
//! fn main() {
-//! let mut foos = vec![Foo {field1: 'u', field2: 983, field3: ZeroVec::alloc_from_slice(&[1212,2309,500,7000])},
-//! Foo {field1: 'l', field2: 1010, field3: ZeroVec::alloc_from_slice(&[1932, 0, 8888, 91237])}];
+//! let mut foos = [Foo {field1: 'u', field2: 983, field3: ZeroVec::alloc_from_slice(&[1212,2309,500,7000])},
+//! Foo {field1: 'l', field2: 1010, field3: ZeroVec::alloc_from_slice(&[1932, 0, 8888, 91237])}];
//!
//! let vzv = VarZeroVec::<_>::from(&foos);
//!
diff --git a/vendor/zerovec/src/ule/encode.rs b/vendor/zerovec/src/ule/encode.rs
index 2091cf06b..adea123aa 100644
--- a/vendor/zerovec/src/ule/encode.rs
+++ b/vendor/zerovec/src/ule/encode.rs
@@ -8,7 +8,7 @@ use crate::{VarZeroSlice, VarZeroVec, ZeroSlice, ZeroVec};
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::string::String;
-use alloc::vec::Vec;
+use alloc::{vec, vec::Vec};
use core::mem;
/// Allows types to be encoded as VarULEs. This is highly useful for implementing VarULE on
@@ -82,16 +82,14 @@ pub unsafe trait EncodeAsVarULE<T: VarULE + ?Sized> {
///
/// This is primarily useful for generating `Deserialize` impls for VarULE types
pub fn encode_varule_to_box<S: EncodeAsVarULE<T>, T: VarULE + ?Sized>(x: &S) -> Box<T> {
- let mut vec: Vec<u8> = Vec::new();
// zero-fill the vector to avoid uninitialized data UB
- vec.resize(x.encode_var_ule_len(), 0);
+ let mut vec: Vec<u8> = vec![0; x.encode_var_ule_len()];
x.encode_var_ule_write(&mut vec);
- let boxed = vec.into_boxed_slice();
+ let boxed = mem::ManuallyDrop::new(vec.into_boxed_slice());
unsafe {
// Safety: `ptr` is a box, and `T` is a VarULE which guarantees it has the same memory layout as `[u8]`
// and can be recouped via from_byte_slice_unchecked()
let ptr: *mut T = T::from_byte_slice_unchecked(&boxed) as *const T as *mut T;
- mem::forget(boxed);
// Safety: we can construct an owned version since we have mem::forgotten the older owner
Box::from_raw(ptr)
diff --git a/vendor/zerovec/src/ule/macros.rs b/vendor/zerovec/src/ule/macros.rs
new file mode 100644
index 000000000..955b1eb2e
--- /dev/null
+++ b/vendor/zerovec/src/ule/macros.rs
@@ -0,0 +1,29 @@
+// 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 ).
+
+/// Given `Self` (`$aligned`), `Self::ULE` (`$unaligned`), and a conversion function (`$single` or
+/// `Self::from_aligned`), implement `from_array` for arrays of `$aligned` to `$unaligned`.
+///
+/// The `$default` argument is due to current compiler limitations.
+/// Pass any (cheap to construct) value.
+#[macro_export]
+macro_rules! impl_ule_from_array {
+ ($aligned:ty, $unaligned:ty, $default:expr, $single:path) => {
+ #[doc = concat!("Convert an array of `", stringify!($aligned), "` to an array of `", stringify!($unaligned), "`.")]
+ pub const fn from_array<const N: usize>(arr: [$aligned; N]) -> [Self; N] {
+ let mut result = [$default; N];
+ let mut i = 0;
+ // Won't panic because i < N and arr has length N
+ #[allow(clippy::indexing_slicing)]
+ while i < N {
+ result[i] = $single(arr[i]);
+ i += 1;
+ }
+ result
+ }
+ };
+ ($aligned:ty, $unaligned:ty, $default:expr) => {
+ impl_ule_from_array!($aligned, $unaligned, $default, Self::from_aligned);
+ };
+}
diff --git a/vendor/zerovec/src/ule/mod.rs b/vendor/zerovec/src/ule/mod.rs
index e8ecd26e5..5a6d9cd47 100644
--- a/vendor/zerovec/src/ule/mod.rs
+++ b/vendor/zerovec/src/ule/mod.rs
@@ -14,6 +14,7 @@ mod chars;
#[cfg(doc)]
pub mod custom;
mod encode;
+mod macros;
mod multi;
mod niche;
mod option;
@@ -29,7 +30,7 @@ pub use multi::MultiFieldsULE;
pub use niche::{NicheBytes, NichedOption, NichedOptionULE};
pub use option::{OptionULE, OptionVarULE};
pub use plain::RawBytesULE;
-pub use unvalidated::UnvalidatedStr;
+pub use unvalidated::{UnvalidatedChar, UnvalidatedStr};
use alloc::alloc::Layout;
use alloc::borrow::ToOwned;
@@ -156,7 +157,7 @@ where
/// A trait for any type that has a 1:1 mapping with an unaligned little-endian (ULE) type.
///
-/// If you need to implement this trait, consider using [`#[make_varule]`](crate::make_ule) instead.
+/// If you need to implement this trait, consider using [`#[make_ule]`](crate::make_ule) instead.
pub trait AsULE: Copy {
/// The ULE type corresponding to `Self`.
///
@@ -356,13 +357,12 @@ pub unsafe trait VarULE: 'static {
#[inline]
fn to_boxed(&self) -> Box<Self> {
let bytesvec = self.as_byte_slice().to_owned().into_boxed_slice();
+ let bytesvec = mem::ManuallyDrop::new(bytesvec);
unsafe {
// Get the pointer representation
let ptr: *mut Self =
Self::from_byte_slice_unchecked(&bytesvec) as *const Self as *mut Self;
- assert_eq!(Layout::for_value(&*ptr), Layout::for_value(&*bytesvec));
- // Forget the allocation
- mem::forget(bytesvec);
+ assert_eq!(Layout::for_value(&*ptr), Layout::for_value(&**bytesvec));
// Transmute the pointer to an owned pointer
Box::from_raw(ptr)
}
diff --git a/vendor/zerovec/src/ule/multi.rs b/vendor/zerovec/src/ule/multi.rs
index 0ba0aea89..3281b2088 100644
--- a/vendor/zerovec/src/ule/multi.rs
+++ b/vendor/zerovec/src/ule/multi.rs
@@ -44,7 +44,7 @@ impl MultiFieldsULE {
lengths, output,
);
debug_assert!(
- <VarZeroSlice<[u8]>>::validate_byte_slice(output).is_ok(),
+ <VarZeroSlice<[u8], Index32>>::validate_byte_slice(output).is_ok(),
"Encoded slice must be valid VarZeroSlice"
);
// Safe since write_serializable_bytes produces a valid VarZeroSlice buffer
@@ -141,12 +141,14 @@ unsafe impl VarULE for MultiFieldsULE {
/// This impl exists so that EncodeAsVarULE can work.
#[inline]
fn validate_byte_slice(slice: &[u8]) -> Result<(), ZeroVecError> {
- <VarZeroSlice<[u8]>>::validate_byte_slice(slice)
+ <VarZeroSlice<[u8], Index32>>::validate_byte_slice(slice)
}
#[inline]
unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self {
// &Self is transparent over &VZS<..>
- mem::transmute(<VarZeroSlice<[u8]>>::from_byte_slice_unchecked(bytes))
+ mem::transmute(<VarZeroSlice<[u8], Index32>>::from_byte_slice_unchecked(
+ bytes,
+ ))
}
}
diff --git a/vendor/zerovec/src/ule/option.rs b/vendor/zerovec/src/ule/option.rs
index 50b193aac..9b0dc5b28 100644
--- a/vendor/zerovec/src/ule/option.rs
+++ b/vendor/zerovec/src/ule/option.rs
@@ -197,9 +197,8 @@ unsafe impl<U: VarULE + ?Sized> VarULE for OptionVarULE<U> {
#[inline]
unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self {
- let metadata = bytes.len() - 1;
let entire_struct_as_slice: *const [u8] =
- ::core::slice::from_raw_parts(bytes.as_ptr(), metadata);
+ ::core::ptr::slice_from_raw_parts(bytes.as_ptr(), bytes.len() - 1);
&*(entire_struct_as_slice as *const Self)
}
}
diff --git a/vendor/zerovec/src/ule/plain.rs b/vendor/zerovec/src/ule/plain.rs
index 49455d45f..f244f6b68 100644
--- a/vendor/zerovec/src/ule/plain.rs
+++ b/vendor/zerovec/src/ule/plain.rs
@@ -6,6 +6,7 @@
//! ULE implementation for Plain Old Data types, including all sized integers.
use super::*;
+use crate::impl_ule_from_array;
use crate::ZeroSlice;
use core::num::{NonZeroI8, NonZeroU8};
@@ -15,69 +16,69 @@ use core::num::{NonZeroI8, NonZeroU8};
#[allow(clippy::exhaustive_structs)] // newtype
pub struct RawBytesULE<const N: usize>(pub [u8; N]);
-macro_rules! impl_byte_slice_size {
- ($unsigned:ty, $size:literal) => {
- impl From<[u8; $size]> for RawBytesULE<$size> {
- #[inline]
- fn from(le_bytes: [u8; $size]) -> Self {
- Self(le_bytes)
- }
- }
- impl RawBytesULE<$size> {
- #[inline]
- pub fn as_bytes(&self) -> &[u8] {
- &self.0
- }
- }
- // Safety (based on the safety checklist on the ULE trait):
- // 1. RawBytesULE does not include any uninitialized or padding bytes.
- // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant)
- // 2. RawBytesULE is aligned to 1 byte.
- // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant)
- // 3. The impl of validate_byte_slice() returns an error if any byte is not valid (never).
- // 4. The impl of validate_byte_slice() returns an error if there are leftover bytes.
- // 5. The other ULE methods use the default impl.
- // 6. RawBytesULE byte equality is semantic equality
- unsafe impl ULE for RawBytesULE<$size> {
- #[inline]
- fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> {
- if bytes.len() % $size == 0 {
- // Safe because Self is transparent over [u8; $size]
- Ok(())
- } else {
- Err(ZeroVecError::length::<Self>(bytes.len()))
- }
- }
+impl<const N: usize> RawBytesULE<N> {
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.0
+ }
+
+ #[inline]
+ pub fn from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
+ let data = bytes.as_mut_ptr();
+ let len = bytes.len() / N;
+ // Safe because Self is transparent over [u8; N]
+ unsafe { core::slice::from_raw_parts_mut(data as *mut Self, len) }
+ }
+}
+
+// Safety (based on the safety checklist on the ULE trait):
+// 1. RawBytesULE does not include any uninitialized or padding bytes.
+// (achieved by `#[repr(transparent)]` on a type that satisfies this invariant)
+// 2. RawBytesULE is aligned to 1 byte.
+// (achieved by `#[repr(transparent)]` on a type that satisfies this invariant)
+// 3. The impl of validate_byte_slice() returns an error if any byte is not valid (never).
+// 4. The impl of validate_byte_slice() returns an error if there are leftover bytes.
+// 5. The other ULE methods use the default impl.
+// 6. RawBytesULE byte equality is semantic equality
+unsafe impl<const N: usize> ULE for RawBytesULE<N> {
+ #[inline]
+ fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> {
+ if bytes.len() % N == 0 {
+ // Safe because Self is transparent over [u8; N]
+ Ok(())
+ } else {
+ Err(ZeroVecError::length::<Self>(bytes.len()))
}
+ }
+}
- impl RawBytesULE<$size> {
- #[inline]
- pub fn from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
- let data = bytes.as_mut_ptr();
- let len = bytes.len() / $size;
- // Safe because Self is transparent over [u8; $size]
- unsafe { core::slice::from_raw_parts_mut(data as *mut Self, len) }
- }
+impl<const N: usize> From<[u8; N]> for RawBytesULE<N> {
+ #[inline]
+ fn from(le_bytes: [u8; N]) -> Self {
+ Self(le_bytes)
+ }
+}
- /// Gets this RawBytesULE as an unsigned int. This is equivalent to calling
- /// [AsULE::from_unaligned()] on the appropriately sized type.
+macro_rules! impl_byte_slice_size {
+ ($unsigned:ty, $size:literal) => {
+ impl RawBytesULE<$size> {
+ #[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($unsigned), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on the appropriately sized type.")]
#[inline]
pub fn as_unsigned_int(&self) -> $unsigned {
<$unsigned as $crate::ule::AsULE>::from_unaligned(*self)
}
- /// Convert an array of native-endian aligned integers to an array of RawBytesULE.
- pub const fn from_array<const N: usize>(arr: [$unsigned; N]) -> [Self; N] {
- let mut result = [RawBytesULE([0; $size]); N];
- let mut i = 0;
- // Won't panic because i < N and arr has length N
- #[allow(clippy::indexing_slicing)]
- while i < N {
- result[i].0 = arr[i].to_le_bytes();
- i += 1;
- }
- result
+ #[doc = concat!("Converts a `", stringify!($unsigned), "` to a `RawBytesULE`. This is equivalent to calling [`AsULE::to_unaligned()`] on the appropriately sized type.")]
+ #[inline]
+ pub const fn from_aligned(value: $unsigned) -> Self {
+ Self(value.to_le_bytes())
}
+
+ impl_ule_from_array!(
+ $unsigned,
+ RawBytesULE<$size>,
+ RawBytesULE([0; $size])
+ );
}
};
}
@@ -110,7 +111,7 @@ macro_rules! impl_const_constructors {
}
macro_rules! impl_byte_slice_type {
- ($type:ty, $size:literal) => {
+ ($single_fn:ident, $type:ty, $size:literal) => {
impl From<$type> for RawBytesULE<$size> {
#[inline]
fn from(value: $type) -> Self {
@@ -131,6 +132,24 @@ macro_rules! impl_byte_slice_type {
// EqULE is true because $type and RawBytesULE<$size>
// have the same byte sequence on little-endian
unsafe impl EqULE for $type {}
+
+ impl RawBytesULE<$size> {
+ pub const fn $single_fn(v: $type) -> Self {
+ RawBytesULE(v.to_le_bytes())
+ }
+ }
+ };
+}
+
+macro_rules! impl_byte_slice_unsigned_type {
+ ($type:ty, $size:literal) => {
+ impl_byte_slice_type!(from_unsigned, $type, $size);
+ };
+}
+
+macro_rules! impl_byte_slice_signed_type {
+ ($type:ty, $size:literal) => {
+ impl_byte_slice_type!(from_signed, $type, $size);
};
}
@@ -139,15 +158,15 @@ impl_byte_slice_size!(u32, 4);
impl_byte_slice_size!(u64, 8);
impl_byte_slice_size!(u128, 16);
-impl_byte_slice_type!(u16, 2);
-impl_byte_slice_type!(u32, 4);
-impl_byte_slice_type!(u64, 8);
-impl_byte_slice_type!(u128, 16);
+impl_byte_slice_unsigned_type!(u16, 2);
+impl_byte_slice_unsigned_type!(u32, 4);
+impl_byte_slice_unsigned_type!(u64, 8);
+impl_byte_slice_unsigned_type!(u128, 16);
-impl_byte_slice_type!(i16, 2);
-impl_byte_slice_type!(i32, 4);
-impl_byte_slice_type!(i64, 8);
-impl_byte_slice_type!(i128, 16);
+impl_byte_slice_signed_type!(i16, 2);
+impl_byte_slice_signed_type!(i32, 4);
+impl_byte_slice_signed_type!(i64, 8);
+impl_byte_slice_signed_type!(i128, 16);
impl_const_constructors!(u8, 1);
impl_const_constructors!(u16, 2);
diff --git a/vendor/zerovec/src/ule/tuple.rs b/vendor/zerovec/src/ule/tuple.rs
index c26567e98..3e0f291b3 100644
--- a/vendor/zerovec/src/ule/tuple.rs
+++ b/vendor/zerovec/src/ule/tuple.rs
@@ -111,10 +111,7 @@ macro_rules! tuple_ule {
impl<$($t: ULE),+> Clone for $name<$($t),+> {
fn clone(&self) -> Self {
- // copy to the stack to avoid hitting a future incompat error
- // https://github.com/rust-lang/rust/issues/82523#issuecomment-947900712
- let stack = ($(self.$i),+);
- $name($(stack.$i),+)
+ *self
}
}
@@ -147,7 +144,7 @@ fn test_pairule_validate() {
// 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!(matches!(zerovec3, Err(_)));
+ assert!(zerovec3.is_err());
}
#[test]
@@ -162,7 +159,7 @@ fn test_tripleule_validate() {
// 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!(matches!(zerovec3, Err(_)));
+ assert!(zerovec3.is_err());
}
#[test]
@@ -178,5 +175,5 @@ fn test_quadule_validate() {
// 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!(matches!(zerovec3, Err(_)));
+ assert!(zerovec3.is_err());
}
diff --git a/vendor/zerovec/src/ule/unvalidated.rs b/vendor/zerovec/src/ule/unvalidated.rs
index 4564c8673..21cfb0c0d 100644
--- a/vendor/zerovec/src/ule/unvalidated.rs
+++ b/vendor/zerovec/src/ule/unvalidated.rs
@@ -2,9 +2,11 @@
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
-use super::VarULE;
+use super::{AsULE, RawBytesULE, VarULE};
+use crate::ule::EqULE;
use crate::{map::ZeroMapKV, VarZeroSlice, VarZeroVec, ZeroVecError};
use alloc::boxed::Box;
+use core::cmp::Ordering;
use core::fmt;
use core::ops::Deref;
@@ -209,3 +211,317 @@ where
}
}
}
+
+/// A u8 array of little-endian data that is expected to be a Unicode scalar value, but is not
+/// validated as such.
+///
+/// Use this type instead of `char` when you want to deal with data that is expected to be valid
+/// Unicode scalar values, but you want control over when or if you validate that assumption.
+///
+/// # Examples
+///
+/// ```
+/// use zerovec::ule::{RawBytesULE, UnvalidatedChar, ULE};
+/// use zerovec::{ZeroSlice, ZeroVec};
+///
+/// // data known to be little-endian three-byte chunks of valid Unicode scalar values
+/// let data = [0x68, 0x00, 0x00, 0x69, 0x00, 0x00, 0x4B, 0xF4, 0x01];
+/// // ground truth expectation
+/// let real = ['h', 'i', '👋'];
+///
+/// let chars: &ZeroSlice<UnvalidatedChar> = ZeroSlice::parse_byte_slice(&data).expect("invalid data length");
+/// let parsed: Vec<_> = chars.iter().map(|c| unsafe { c.to_char_unchecked() }).collect();
+/// assert_eq!(&parsed, &real);
+///
+/// let real_chars: ZeroVec<_> = real.iter().copied().map(UnvalidatedChar::from_char).collect();
+/// let serialized_data = chars.as_bytes();
+/// assert_eq!(serialized_data, &data);
+/// ```
+#[repr(transparent)]
+#[derive(PartialEq, Eq, Clone, Copy, Hash)]
+pub struct UnvalidatedChar([u8; 3]);
+
+impl UnvalidatedChar {
+ /// Create a [`UnvalidatedChar`] from a `char`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::ule::UnvalidatedChar;
+ ///
+ /// let a = UnvalidatedChar::from_char('a');
+ /// assert_eq!(a.try_to_char().unwrap(), 'a');
+ /// ```
+ #[inline]
+ pub const fn from_char(c: char) -> Self {
+ let [u0, u1, u2, _u3] = (c as u32).to_le_bytes();
+ Self([u0, u1, u2])
+ }
+
+ #[inline]
+ #[doc(hidden)]
+ pub const fn from_u24(c: u32) -> Self {
+ let [u0, u1, u2, _u3] = c.to_le_bytes();
+ Self([u0, u1, u2])
+ }
+
+ /// Attempt to convert a [`UnvalidatedChar`] to a `char`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::ule::{AsULE, UnvalidatedChar};
+ ///
+ /// let a = UnvalidatedChar::from_char('a');
+ /// assert_eq!(a.try_to_char(), Ok('a'));
+ ///
+ /// let b = UnvalidatedChar::from_unaligned([0xFF, 0xFF, 0xFF].into());
+ /// assert!(matches!(b.try_to_char(), Err(_)));
+ /// ```
+ #[inline]
+ pub fn try_to_char(self) -> Result<char, core::char::CharTryFromError> {
+ let [u0, u1, u2] = self.0;
+ char::try_from(u32::from_le_bytes([u0, u1, u2, 0]))
+ }
+
+ /// Convert a [`UnvalidatedChar`] to a `char', returning [`char::REPLACEMENT_CHARACTER`]
+ /// if the `UnvalidatedChar` does not represent a valid Unicode scalar value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::ule::{AsULE, UnvalidatedChar};
+ ///
+ /// let a = UnvalidatedChar::from_unaligned([0xFF, 0xFF, 0xFF].into());
+ /// assert_eq!(a.to_char_lossy(), char::REPLACEMENT_CHARACTER);
+ /// ```
+ #[inline]
+ pub fn to_char_lossy(self) -> char {
+ self.try_to_char().unwrap_or(char::REPLACEMENT_CHARACTER)
+ }
+
+ /// Convert a [`UnvalidatedChar`] to a `char` without checking that it is
+ /// a valid Unicode scalar value.
+ ///
+ /// # Safety
+ ///
+ /// The `UnvalidatedChar` must be a valid Unicode scalar value in little-endian order.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::ule::UnvalidatedChar;
+ ///
+ /// let a = UnvalidatedChar::from_char('a');
+ /// assert_eq!(unsafe { a.to_char_unchecked() }, 'a');
+ /// ```
+ #[inline]
+ pub unsafe fn to_char_unchecked(self) -> char {
+ let [u0, u1, u2] = self.0;
+ char::from_u32_unchecked(u32::from_le_bytes([u0, u1, u2, 0]))
+ }
+}
+
+impl RawBytesULE<3> {
+ /// Converts a [`UnvalidatedChar`] to its ULE type. This is equivalent to calling
+ /// [`AsULE::to_unaligned`].
+ #[inline]
+ pub const fn from_unvalidated_char(uc: UnvalidatedChar) -> Self {
+ RawBytesULE(uc.0)
+ }
+}
+
+impl AsULE for UnvalidatedChar {
+ type ULE = RawBytesULE<3>;
+
+ #[inline]
+ fn to_unaligned(self) -> Self::ULE {
+ RawBytesULE(self.0)
+ }
+
+ #[inline]
+ fn from_unaligned(unaligned: Self::ULE) -> Self {
+ Self(unaligned.0)
+ }
+}
+
+// Safety: UnvalidatedChar is always the little-endian representation of a char,
+// which corresponds to its AsULE::ULE type
+unsafe impl EqULE for UnvalidatedChar {}
+
+impl fmt::Debug for UnvalidatedChar {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Debug as a char if possible
+ match self.try_to_char() {
+ Ok(c) => fmt::Debug::fmt(&c, f),
+ Err(_) => fmt::Debug::fmt(&self.0, f),
+ }
+ }
+}
+
+impl PartialOrd for UnvalidatedChar {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for UnvalidatedChar {
+ // custom implementation, as derived Ord would compare lexicographically
+ fn cmp(&self, other: &Self) -> Ordering {
+ let [a0, a1, a2] = self.0;
+ let a = u32::from_le_bytes([a0, a1, a2, 0]);
+ let [b0, b1, b2] = other.0;
+ let b = u32::from_le_bytes([b0, b1, b2, 0]);
+ a.cmp(&b)
+ }
+}
+
+impl From<char> for UnvalidatedChar {
+ #[inline]
+ fn from(value: char) -> Self {
+ Self::from_char(value)
+ }
+}
+
+impl TryFrom<UnvalidatedChar> for char {
+ type Error = core::char::CharTryFromError;
+
+ #[inline]
+ fn try_from(value: UnvalidatedChar) -> Result<char, Self::Error> {
+ value.try_to_char()
+ }
+}
+
+/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
+#[cfg(feature = "serde")]
+impl serde::Serialize for UnvalidatedChar {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ use serde::ser::Error;
+ let c = self
+ .try_to_char()
+ .map_err(|_| S::Error::custom("invalid Unicode scalar value in UnvalidatedChar"))?;
+ if serializer.is_human_readable() {
+ serializer.serialize_char(c)
+ } else {
+ self.0.serialize(serializer)
+ }
+ }
+}
+
+/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for UnvalidatedChar {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ if deserializer.is_human_readable() {
+ let c = <char>::deserialize(deserializer)?;
+ Ok(UnvalidatedChar::from_char(c))
+ } else {
+ let bytes = <[u8; 3]>::deserialize(deserializer)?;
+ Ok(UnvalidatedChar(bytes))
+ }
+ }
+}
+
+#[cfg(feature = "databake")]
+impl databake::Bake for UnvalidatedChar {
+ fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream {
+ match self.try_to_char() {
+ Ok(ch) => {
+ env.insert("zerovec");
+ let ch = ch.bake(env);
+ databake::quote! {
+ zerovec::ule::UnvalidatedChar::from_char(#ch)
+ }
+ }
+ Err(_) => {
+ env.insert("zerovec");
+ let u24 = u32::from_le_bytes([self.0[0], self.0[1], self.0[2], 0]);
+ databake::quote! {
+ zerovec::ule::UnvalidatedChar::from_u24(#u24)
+ }
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::ZeroVec;
+
+ #[test]
+ fn test_serde_fail() {
+ let uc = UnvalidatedChar([0xFF, 0xFF, 0xFF]);
+ serde_json::to_string(&uc).expect_err("serialize invalid char bytes");
+ bincode::serialize(&uc).expect_err("serialize invalid char bytes");
+ }
+
+ #[test]
+ fn test_serde_json() {
+ let c = '🙃';
+ let uc = UnvalidatedChar::from_char(c);
+ let json_ser = serde_json::to_string(&uc).unwrap();
+
+ assert_eq!(json_ser, r#""🙃""#);
+
+ let json_de: UnvalidatedChar = serde_json::from_str(&json_ser).unwrap();
+
+ assert_eq!(uc, json_de);
+ }
+
+ #[test]
+ fn test_serde_bincode() {
+ let c = '🙃';
+ let uc = UnvalidatedChar::from_char(c);
+ let bytes_ser = bincode::serialize(&uc).unwrap();
+
+ assert_eq!(bytes_ser, [0x43, 0xF6, 0x01]);
+
+ let bytes_de: UnvalidatedChar = bincode::deserialize(&bytes_ser).unwrap();
+
+ assert_eq!(uc, bytes_de);
+ }
+
+ #[test]
+ fn test_representation() {
+ let chars = ['w', 'ω', '文', '𑄃', '🙃'];
+
+ // backed by [UnvalidatedChar]
+ let uvchars: Vec<_> = chars
+ .iter()
+ .copied()
+ .map(UnvalidatedChar::from_char)
+ .collect();
+ // backed by [RawBytesULE<3>]
+ let zvec: ZeroVec<_> = uvchars.clone().into_iter().collect();
+
+ let ule_bytes = zvec.as_bytes();
+ let uvbytes;
+ unsafe {
+ let ptr = &uvchars[..] as *const _ as *const u8;
+ uvbytes = core::slice::from_raw_parts(ptr, ule_bytes.len());
+ }
+
+ // UnvalidatedChar is defined as little-endian, so this must be true on all platforms
+ // also asserts that to_unaligned/from_unaligned are no-ops
+ assert_eq!(uvbytes, ule_bytes);
+
+ assert_eq!(
+ &[119, 0, 0, 201, 3, 0, 135, 101, 0, 3, 17, 1, 67, 246, 1],
+ ule_bytes
+ );
+ }
+
+ #[test]
+ fn test_char_bake() {
+ databake::test_bake!(UnvalidatedChar, const: crate::ule::UnvalidatedChar::from_char('b'), zerovec);
+ // surrogate code point
+ databake::test_bake!(UnvalidatedChar, const: crate::ule::UnvalidatedChar::from_u24(55296u32), zerovec);
+ }
+}
diff --git a/vendor/zerovec/src/varzerovec/components.rs b/vendor/zerovec/src/varzerovec/components.rs
index ff26d9029..9b48a5bd6 100644
--- a/vendor/zerovec/src/varzerovec/components.rs
+++ b/vendor/zerovec/src/varzerovec/components.rs
@@ -53,7 +53,7 @@ pub unsafe trait VarZeroVecFormat: 'static + Sized {
/// Will have a smaller data size, but it's more likely for larger arrays
/// to be unrepresentable (and error on construction)
///
-/// This is the default index size used by all [`VarZeroVec`](super::VarZeroVec) tyoes.
+/// This is the default index size used by all [`VarZeroVec`](super::VarZeroVec) types.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[allow(clippy::exhaustive_structs)] // marker
pub struct Index16;
@@ -128,13 +128,7 @@ pub struct VarZeroVecComponents<'a, T: ?Sized, F> {
impl<'a, T: ?Sized, F> Copy for VarZeroVecComponents<'a, T, F> {}
impl<'a, T: ?Sized, F> Clone for VarZeroVecComponents<'a, T, F> {
fn clone(&self) -> Self {
- VarZeroVecComponents {
- len: self.len,
- indices: self.indices,
- things: self.things,
- entire_slice: self.entire_slice,
- marker: PhantomData,
- }
+ *self
}
}
@@ -161,13 +155,14 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F>
/// Construct a new VarZeroVecComponents, checking invariants about the overall buffer size:
///
/// - There must be either zero or at least four bytes (if four, this is the "length" parsed as a usize)
- /// - There must be at least `4*length + 4` bytes total, to form the the array `indices` of indices
+ /// - There must be at least `4*length + 4` bytes total, to form the array `indices` of indices
/// - `indices[i]..indices[i+1]` must index into a valid section of
/// `things`, such that it parses to a `T::VarULE`
/// - `indices[len - 1]..things.len()` must index into a valid section of
/// `things`, such that it parses to a `T::VarULE`
#[inline]
pub fn parse_byte_slice(slice: &'a [u8]) -> Result<Self, ZeroVecError> {
+ // The empty VZV is special-cased to the empty slice
if slice.is_empty() {
return Ok(VarZeroVecComponents {
len: 0,
@@ -219,6 +214,7 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F>
/// The bytes must have previously successfully run through
/// [`VarZeroVecComponents::parse_byte_slice()`]
pub unsafe fn from_bytes_unchecked(slice: &'a [u8]) -> Self {
+ // The empty VZV is special-cased to the empty slice
if slice.is_empty() {
return VarZeroVecComponents {
len: 0,
@@ -369,7 +365,7 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F>
.copied()
.map(F::rawbytes_to_usize)
.skip(1)
- .chain(core::iter::once(self.things.len())),
+ .chain([self.things.len()]),
)
.map(move |(start, end)| unsafe { self.things.get_unchecked(start..end) })
.map(|bytes| unsafe { T::from_byte_slice_unchecked(bytes) })
@@ -485,12 +481,13 @@ where
}
/// Collects the bytes for a VarZeroSlice into a Vec.
-pub fn get_serializable_bytes<T, A, F>(elements: &[A]) -> Option<Vec<u8>>
+pub fn get_serializable_bytes_non_empty<T, A, F>(elements: &[A]) -> Option<Vec<u8>>
where
T: VarULE + ?Sized,
A: EncodeAsVarULE<T>,
F: VarZeroVecFormat,
{
+ debug_assert!(!elements.is_empty());
let len = compute_serializable_len::<T, A, F>(elements)?;
debug_assert!(len >= LENGTH_WIDTH as u32);
let mut output: Vec<u8> = alloc::vec![0; len as usize];
@@ -566,9 +563,7 @@ where
let data_len: u32 = elements
.iter()
.map(|v| u32::try_from(v.encode_var_ule_len()).ok())
- .fold(Some(0u32), |s, v| {
- s.and_then(|s| v.and_then(|v| s.checked_add(v)))
- })?;
+ .try_fold(0u32, |s, v| s.checked_add(v?))?;
let ret = idx_len.checked_add(data_len);
if let Some(r) = ret {
if r >= F::MAX_VALUE {
diff --git a/vendor/zerovec/src/varzerovec/databake.rs b/vendor/zerovec/src/varzerovec/databake.rs
index 8d9fc0bfc..a3f9db2d1 100644
--- a/vendor/zerovec/src/varzerovec/databake.rs
+++ b/vendor/zerovec/src/varzerovec/databake.rs
@@ -9,11 +9,11 @@ impl<T: VarULE + ?Sized> Bake for VarZeroVec<'_, T> {
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("zerovec");
if self.is_empty() {
- quote! { ::zerovec::VarZeroVec::new() }
+ quote! { zerovec::VarZeroVec::new() }
} else {
let bytes = databake::Bake::bake(&self.as_bytes(), env);
// Safe because self.as_bytes is a safe input
- quote! { unsafe { ::zerovec::VarZeroVec::from_bytes_unchecked(#bytes) } }
+ quote! { unsafe { zerovec::VarZeroVec::from_bytes_unchecked(#bytes) } }
}
}
}
@@ -22,11 +22,11 @@ impl<T: VarULE + ?Sized> Bake for &VarZeroSlice<T> {
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("zerovec");
if self.is_empty() {
- quote! { ::zerovec::VarZeroSlice::new_empty() }
+ quote! { zerovec::VarZeroSlice::new_empty() }
} else {
let bytes = databake::Bake::bake(&self.as_bytes(), env);
// Safe because self.as_bytes is a safe input
- quote! { unsafe { ::zerovec::VarZeroSlice::from_bytes_unchecked(#bytes) } }
+ quote! { unsafe { zerovec::VarZeroSlice::from_bytes_unchecked(#bytes) } }
}
}
}
diff --git a/vendor/zerovec/src/varzerovec/owned.rs b/vendor/zerovec/src/varzerovec/owned.rs
index 76de48760..c5556315f 100644
--- a/vendor/zerovec/src/varzerovec/owned.rs
+++ b/vendor/zerovec/src/varzerovec/owned.rs
@@ -84,13 +84,18 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> {
where
A: EncodeAsVarULE<T>,
{
- Ok(Self {
- marker: PhantomData,
- // TODO(#1410): Rethink length errors in VZV.
- entire_slice: components::get_serializable_bytes::<T, A, F>(elements).ok_or(
- "Attempted to build VarZeroVec out of elements that \
+ Ok(if elements.is_empty() {
+ Self::from_slice(VarZeroSlice::new_empty())
+ } else {
+ Self {
+ marker: PhantomData,
+ // TODO(#1410): Rethink length errors in VZV.
+ entire_slice: components::get_serializable_bytes_non_empty::<T, A, F>(elements)
+ .ok_or(
+ "Attempted to build VarZeroVec out of elements that \
cumulatively are larger than a u32 in size",
- )?,
+ )?,
+ }
})
}
@@ -279,7 +284,7 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> {
any::type_name::<F>()
);
}
- self.entire_slice.reserve(shift as usize);
+ self.entire_slice.resize(new_slice_len, 0);
}
// Now that we've ensured there's enough space, we can shift the data around.
@@ -287,6 +292,7 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> {
// Note: There are no references introduced between pointer creation and pointer use, and all
// raw pointers are derived from a single &mut. This preserves pointer provenance.
let slice_range = self.entire_slice.as_mut_ptr_range();
+ let old_slice_end = slice_range.start.add(slice_len);
let data_start = slice_range
.start
.add(LENGTH_WIDTH + METADATA_WIDTH + len * F::INDEX_WIDTH);
@@ -316,7 +322,7 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> {
// Shift data after the element to its new position.
shift_bytes(
- prev_element_p.end..slice_range.end,
+ prev_element_p.end..old_slice_end,
prev_element_p
.start
.offset((new_size as i64 + index_shift) as isize),
diff --git a/vendor/zerovec/src/varzerovec/serde.rs b/vendor/zerovec/src/varzerovec/serde.rs
index 649b29cfb..8025fc085 100644
--- a/vendor/zerovec/src/varzerovec/serde.rs
+++ b/vendor/zerovec/src/varzerovec/serde.rs
@@ -72,7 +72,7 @@ where
where
D: Deserializer<'de>,
{
- let visitor = VarZeroVecVisitor::default();
+ let visitor = VarZeroVecVisitor::<T, F>::default();
if deserializer.is_human_readable() {
deserializer.deserialize_seq(visitor)
} else {
@@ -98,7 +98,7 @@ where
"&VarZeroSlice cannot be deserialized from human-readable formats",
))
} else {
- let deserialized: VarZeroVec<'a, T, F> = VarZeroVec::deserialize(deserializer)?;
+ let deserialized = VarZeroVec::<'a, T, F>::deserialize(deserializer)?;
let borrowed = if let VarZeroVec::Borrowed(b) = deserialized {
b
} else {
@@ -112,6 +112,22 @@ where
}
/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
+impl<'de, T, F> Deserialize<'de> for Box<VarZeroSlice<T, F>>
+where
+ T: VarULE + ?Sized,
+ Box<T>: Deserialize<'de>,
+ F: VarZeroVecFormat,
+{
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let deserialized = VarZeroVec::<T, F>::deserialize(deserializer)?;
+ Ok(deserialized.to_boxed())
+ }
+}
+
+/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
#[cfg(feature = "serde")]
impl<T, F> Serialize for VarZeroVec<'_, T, F>
where
@@ -166,6 +182,12 @@ mod test {
_data: &'data VarZeroSlice<str>,
}
+ #[derive(serde::Serialize, serde::Deserialize)]
+ struct DeriveTest_VarZeroVec_of_VarZeroSlice<'data> {
+ #[serde(borrow)]
+ _data: VarZeroVec<'data, VarZeroSlice<str>>,
+ }
+
// ["foo", "bar", "baz", "dolor", "quux", "lorem ipsum"];
const BYTES: &[u8] = &[
6, 0, 0, 0, 0, 0, 3, 0, 6, 0, 9, 0, 14, 0, 18, 0, 102, 111, 111, 98, 97, 114, 98, 97, 122,
diff --git a/vendor/zerovec/src/varzerovec/slice.rs b/vendor/zerovec/src/varzerovec/slice.rs
index afdbe80d9..119f1d38f 100644
--- a/vendor/zerovec/src/varzerovec/slice.rs
+++ b/vendor/zerovec/src/varzerovec/slice.rs
@@ -108,8 +108,8 @@ pub struct VarZeroSlice<T: ?Sized, F = Index16> {
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroSlice<T, F> {
/// Construct a new empty VarZeroSlice
pub const fn new_empty() -> &'static Self {
- let arr: &[u8] = &[];
- unsafe { mem::transmute(arr) }
+ // The empty VZV is special-cased to the empty slice
+ unsafe { mem::transmute(&[] as &[u8]) }
}
/// Obtain a [`VarZeroVecComponents`] borrowing from the internal buffer
@@ -192,7 +192,7 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroSlice<T, F> {
self.as_components().iter()
}
- /// Get one of this slice's elements, returning None if the index is out of bounds
+ /// Get one of this slice's elements, returning `None` if the index is out of bounds
///
/// # Example
///
@@ -366,7 +366,7 @@ where
/// assert_eq!(vec.binary_search_in_range("g", 1..6), Some(Ok(2)));
/// assert_eq!(vec.binary_search_in_range("h", 1..6), Some(Err(3)));
///
- /// // Will return None if the range is out of bounds:
+ /// // Will return `None` if the range is out of bounds:
/// assert_eq!(vec.binary_search_in_range("x", 100..200), None);
/// assert_eq!(vec.binary_search_in_range("x", 0..200), None);
/// # Ok::<(), ZeroVecError>(())
@@ -460,7 +460,7 @@ where
/// Some(Err(3))
/// );
///
- /// // Will return None if the range is out of bounds:
+ /// // Will return `None` if the range is out of bounds:
/// assert_eq!(
/// vec.binary_search_in_range_by(|v| v.cmp("x"), 100..200),
/// None
diff --git a/vendor/zerovec/src/varzerovec/vec.rs b/vendor/zerovec/src/varzerovec/vec.rs
index 1401a180a..64928509f 100644
--- a/vendor/zerovec/src/varzerovec/vec.rs
+++ b/vendor/zerovec/src/varzerovec/vec.rs
@@ -425,8 +425,12 @@ where
{
#[inline]
fn from(elements: &[A]) -> Self {
- #[allow(clippy::unwrap_used)] // TODO(#1410) Better story for fallibility
- VarZeroVecOwned::try_from_elements(elements).unwrap().into()
+ if elements.is_empty() {
+ VarZeroSlice::new_empty().into()
+ } else {
+ #[allow(clippy::unwrap_used)] // TODO(#1410) Better story for fallibility
+ VarZeroVecOwned::try_from_elements(elements).unwrap().into()
+ }
}
}
@@ -451,8 +455,14 @@ where
{
#[inline]
fn eq(&self, other: &VarZeroVec<'b, T, F>) -> bool {
- // VarULE has an API guarantee that this is equivalent
- // to `T::VarULE::eq()`
+ // VZV::from_elements used to produce a non-canonical representation of the
+ // empty VZV, so we cannot use byte equality for empty vecs.
+ if self.is_empty() || other.is_empty() {
+ return self.is_empty() && other.is_empty();
+ }
+ // VarULE has an API guarantee that byte equality is semantic equality.
+ // For non-empty VZVs, there's only a single metadata representation,
+ // so this guarantee extends to the whole VZV representation.
self.as_bytes().eq(other.as_bytes())
}
}
@@ -503,3 +513,19 @@ impl<'a, T: VarULE + ?Sized + Ord, F: VarZeroVecFormat> Ord for VarZeroVec<'a, T
self.iter().cmp(other.iter())
}
}
+
+#[test]
+fn assert_single_empty_representation() {
+ assert_eq!(
+ VarZeroVec::<str>::new().as_bytes(),
+ VarZeroVec::<str>::from(&[] as &[&str]).as_bytes()
+ );
+}
+
+#[test]
+fn weird_empty_representation_equality() {
+ assert_eq!(
+ VarZeroVec::<str>::parse_byte_slice(&[0, 0, 0, 0]).unwrap(),
+ VarZeroVec::<str>::parse_byte_slice(&[]).unwrap()
+ );
+}
diff --git a/vendor/zerovec/src/yoke_impls.rs b/vendor/zerovec/src/yoke_impls.rs
index a5064a554..8b196cf9a 100644
--- a/vendor/zerovec/src/yoke_impls.rs
+++ b/vendor/zerovec/src/yoke_impls.rs
@@ -3,6 +3,9 @@
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
// This way we can copy-paste Yokeable impls
+#![allow(unknown_lints)] // forgetting_copy_types
+#![allow(renamed_and_removed_lints)] // forgetting_copy_types
+#![allow(forgetting_copy_types)]
#![allow(clippy::forget_copy)]
#![allow(clippy::forget_non_drop)]
@@ -30,8 +33,8 @@ unsafe impl<'a, T: 'static + AsULE + ?Sized> Yokeable<'a> for ZeroVec<'static, T
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
@@ -58,8 +61,8 @@ unsafe impl<'a, T: 'static + VarULE + ?Sized> Yokeable<'a> for VarZeroVec<'stati
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
@@ -86,8 +89,8 @@ unsafe impl<'a> Yokeable<'a> for FlexZeroVec<'static> {
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
@@ -124,16 +127,16 @@ where
unsafe {
// Similar problem as transform(), but we need to use ptr::read since
// the compiler isn't sure of the sizes
- let ptr: *const Self::Output = (&self as *const Self).cast();
- mem::forget(self);
+ let this = mem::ManuallyDrop::new(self);
+ let ptr: *const Self::Output = (&*this as *const Self).cast();
ptr::read(ptr)
}
}
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
@@ -170,16 +173,16 @@ where
unsafe {
// Similar problem as transform(), but we need to use ptr::read since
// the compiler isn't sure of the sizes
- let ptr: *const Self::Output = (&self as *const Self).cast();
- mem::forget(self);
+ let this = mem::ManuallyDrop::new(self);
+ let ptr: *const Self::Output = (&*this as *const Self).cast();
ptr::read(ptr)
}
}
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
@@ -218,16 +221,16 @@ where
unsafe {
// Similar problem as transform(), but we need to use ptr::read since
// the compiler isn't sure of the sizes
- let ptr: *const Self::Output = (&self as *const Self).cast();
- mem::forget(self);
+ let this = mem::ManuallyDrop::new(self);
+ let ptr: *const Self::Output = (&*this as *const Self).cast();
ptr::read(ptr)
}
}
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
@@ -266,16 +269,16 @@ where
unsafe {
// Similar problem as transform(), but we need to use ptr::read since
// the compiler isn't sure of the sizes
- let ptr: *const Self::Output = (&self as *const Self).cast();
- mem::forget(self);
+ let this = mem::ManuallyDrop::new(self);
+ let ptr: *const Self::Output = (&*this as *const Self).cast();
ptr::read(ptr)
}
}
#[inline]
unsafe fn make(from: Self::Output) -> Self {
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
- let ptr: *const Self = (&from as *const Self::Output).cast();
- mem::forget(from);
+ let from = mem::ManuallyDrop::new(from);
+ let ptr: *const Self = (&*from as *const Self::Output).cast();
ptr::read(ptr)
}
#[inline]
diff --git a/vendor/zerovec/src/zerovec/databake.rs b/vendor/zerovec/src/zerovec/databake.rs
index e46065c38..31f167594 100644
--- a/vendor/zerovec/src/zerovec/databake.rs
+++ b/vendor/zerovec/src/zerovec/databake.rs
@@ -8,15 +8,15 @@ use databake::*;
impl<T> Bake for ZeroVec<'_, T>
where
- T: AsULE + ?Sized,
+ T: AsULE + ?Sized + Bake,
{
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("zerovec");
if self.is_empty() {
- quote! { ::zerovec::ZeroVec::new() }
+ quote! { zerovec::ZeroVec::new() }
} else {
let bytes = databake::Bake::bake(&self.as_bytes(), env);
- quote! { unsafe { ::zerovec::ZeroVec::from_bytes_unchecked(#bytes) } }
+ quote! { unsafe { zerovec::ZeroVec::from_bytes_unchecked(#bytes) } }
}
}
}
@@ -28,10 +28,10 @@ where
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("zerovec");
if self.is_empty() {
- quote! { ::zerovec::ZeroSlice::new_empty() }
+ quote! { zerovec::ZeroSlice::new_empty() }
} else {
let bytes = databake::Bake::bake(&self.as_bytes(), env);
- quote! { unsafe { ::zerovec::ZeroSlice::from_bytes_unchecked(#bytes) } }
+ quote! { unsafe { zerovec::ZeroSlice::from_bytes_unchecked(#bytes) } }
}
}
}
diff --git a/vendor/zerovec/src/zerovec/mod.rs b/vendor/zerovec/src/zerovec/mod.rs
index e7c87f68e..e6186be0a 100644
--- a/vendor/zerovec/src/zerovec/mod.rs
+++ b/vendor/zerovec/src/zerovec/mod.rs
@@ -20,7 +20,9 @@ use core::fmt;
use core::iter::FromIterator;
use core::marker::PhantomData;
use core::mem;
+use core::num::NonZeroUsize;
use core::ops::Deref;
+use core::ptr;
/// A zero-copy, byte-aligned vector for fixed-width types.
///
@@ -138,8 +140,8 @@ impl<U> EyepatchHackVector<U> {
}
// Return a slice to the inner data
#[inline]
- fn as_slice<'a>(&'a self) -> &'a [U] {
- unsafe { &*self.buf }
+ const fn as_slice<'a>(&'a self) -> &'a [U] {
+ unsafe { &*(self.buf as *const [U]) }
}
/// Return this type as a vector
@@ -255,6 +257,24 @@ impl<'a, T: AsULE + Ord> Ord for ZeroVec<'a, T> {
}
}
+impl<'a, T: AsULE> AsRef<[T::ULE]> for ZeroVec<'a, T> {
+ fn as_ref(&self) -> &[T::ULE] {
+ self.as_ule_slice()
+ }
+}
+
+impl<'a, T: AsULE> From<&'a [T::ULE]> for ZeroVec<'a, T> {
+ fn from(other: &'a [T::ULE]) -> Self {
+ ZeroVec::new_borrowed(other)
+ }
+}
+
+impl<'a, T: AsULE> From<Vec<T::ULE>> for ZeroVec<'a, T> {
+ fn from(other: Vec<T::ULE>) -> Self {
+ ZeroVec::new_owned(other)
+ }
+}
+
impl<'a, T> ZeroVec<'a, T>
where
T: AsULE + ?Sized,
@@ -274,6 +294,11 @@ where
Self::new_borrowed(&[])
}
+ /// Same as `ZeroSlice::len`, which is available through `Deref` and not `const`.
+ pub const fn const_len(&self) -> usize {
+ self.vector.as_slice().len()
+ }
+
/// Creates a new owned `ZeroVec` using an existing
/// allocated backing buffer
///
@@ -284,10 +309,10 @@ where
// Deconstruct the vector into parts
// This is the only part of the code that goes from Vec
// to ZeroVec, all other such operations should use this function
- let slice: &[T::ULE] = &vec;
- let slice = slice as *const [_] as *mut [_];
let capacity = vec.capacity();
- mem::forget(vec);
+ let len = vec.len();
+ let ptr = mem::ManuallyDrop::new(vec).as_mut_ptr();
+ let slice = ptr::slice_from_raw_parts_mut(ptr, len);
Self {
vector: EyepatchHackVector {
buf: slice,
@@ -352,10 +377,10 @@ where
/// `bytes` need to be an output from [`ZeroSlice::as_bytes()`].
pub const unsafe fn from_bytes_unchecked(bytes: &'a [u8]) -> Self {
// &[u8] and &[T::ULE] are the same slice with different length metadata.
- Self::new_borrowed(core::mem::transmute((
- bytes.as_ptr(),
+ Self::new_borrowed(core::slice::from_raw_parts(
+ bytes.as_ptr() as *const T::ULE,
bytes.len() / core::mem::size_of::<T::ULE>(),
- )))
+ ))
}
/// Converts a `ZeroVec<T>` into a `ZeroVec<u8>`, retaining the current ownership model.
@@ -554,6 +579,34 @@ where
Some(ZeroSlice::from_ule_slice(ule_slice))
}
}
+
+ /// If the ZeroVec is owned, returns the capacity of the vector.
+ ///
+ /// Otherwise, if the ZeroVec is borrowed, returns `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::ZeroVec;
+ ///
+ /// let mut zv = ZeroVec::<u8>::new_borrowed(&[0, 1, 2, 3]);
+ /// assert!(!zv.is_owned());
+ /// assert_eq!(zv.owned_capacity(), None);
+ ///
+ /// // Convert to owned without appending anything
+ /// zv.with_mut(|v| ());
+ /// assert!(zv.is_owned());
+ /// assert_eq!(zv.owned_capacity(), Some(4.try_into().unwrap()));
+ ///
+ /// // Double the size by appending
+ /// zv.with_mut(|v| v.push(0));
+ /// assert!(zv.is_owned());
+ /// assert_eq!(zv.owned_capacity(), Some(8.try_into().unwrap()));
+ /// ```
+ #[inline]
+ pub fn owned_capacity(&self) -> Option<NonZeroUsize> {
+ NonZeroUsize::try_from(self.vector.capacity).ok()
+ }
}
impl<'a> ZeroVec<'a, u8> {
@@ -860,21 +913,18 @@ where
/// the logical equivalent of this type's internal representation
#[inline]
pub fn into_cow(self) -> Cow<'a, [T::ULE]> {
- if self.is_owned() {
+ let this = mem::ManuallyDrop::new(self);
+ if this.is_owned() {
let vec = unsafe {
// safe to call: we know it's owned,
- // and we mem::forget self immediately afterwards
- self.vector.get_vec()
+ // and `self`/`this` are thenceforth no longer used or dropped
+ { this }.vector.get_vec()
};
- mem::forget(self);
Cow::Owned(vec)
} else {
// We can extend the lifetime of the slice to 'a
// since we know it is borrowed
- let slice = unsafe { self.vector.as_arbitrary_slice() };
- // The borrowed destructor is a no-op, but we want to prevent
- // the check being run
- mem::forget(self);
+ let slice = unsafe { { this }.vector.as_arbitrary_slice() };
Cow::Borrowed(slice)
}
}
@@ -890,6 +940,89 @@ impl<T: AsULE> FromIterator<T> for ZeroVec<'_, T> {
}
}
+/// Convenience wrapper for [`ZeroSlice::from_ule_slice`]. The value will be created at compile-time,
+/// meaning that all arguments must also be constant.
+///
+/// # Arguments
+///
+/// * `$aligned` - The type of an element in its canonical, aligned form, e.g., `char`.
+/// * `$convert` - A const function that converts an `$aligned` into its unaligned equivalent, e.g.,
+/// `const fn from_aligned(a: CanonicalType) -> CanonicalType::ULE`.
+/// * `$x` - The elements that the `ZeroSlice` will hold.
+///
+/// # Examples
+///
+/// Using array-conversion functions provided by this crate:
+///
+/// ```
+/// use zerovec::{ZeroSlice, zeroslice, ule::AsULE};
+/// use zerovec::ule::UnvalidatedChar;
+///
+/// const SIGNATURE: &ZeroSlice<char> = zeroslice!(char; <char as AsULE>::ULE::from_aligned; ['b', 'y', 'e', '✌']);
+/// const EMPTY: &ZeroSlice<u32> = zeroslice![];
+/// const UC: &ZeroSlice<UnvalidatedChar> =
+/// zeroslice!(
+/// UnvalidatedChar;
+/// <UnvalidatedChar as AsULE>::ULE::from_unvalidated_char;
+/// [UnvalidatedChar::from_char('a')]
+/// );
+/// let empty: &ZeroSlice<u32> = zeroslice![];
+/// let nums = zeroslice!(u32; <u32 as AsULE>::ULE::from_unsigned; [1, 2, 3, 4, 5]);
+/// assert_eq!(nums.last().unwrap(), 5);
+/// ```
+///
+/// Using a custom array-conversion function:
+///
+/// ```
+/// use zerovec::{ule::AsULE, ule::RawBytesULE, zeroslice, ZeroSlice};
+///
+/// const fn be_convert(num: i16) -> <i16 as AsULE>::ULE {
+/// RawBytesULE(num.to_be_bytes())
+/// }
+///
+/// const NUMBERS_BE: &ZeroSlice<i16> =
+/// zeroslice!(i16; be_convert; [1, -2, 3, -4, 5]);
+/// ```
+#[macro_export]
+macro_rules! zeroslice {
+ () => (
+ $crate::ZeroSlice::new_empty()
+ );
+ ($aligned:ty; $convert:expr; [$($x:expr),+ $(,)?]) => (
+ $crate::ZeroSlice::<$aligned>::from_ule_slice(
+ {const X: &[<$aligned as $crate::ule::AsULE>::ULE] = &[
+ $($convert($x)),*
+ ]; X}
+ )
+ );
+}
+
+/// Creates a borrowed `ZeroVec`. Convenience wrapper for `zeroslice!(...).as_zerovec()`. The value
+/// will be created at compile-time, meaning that all arguments must also be constant.
+///
+/// See [`zeroslice!`](crate::zeroslice) for more information.
+///
+/// # Examples
+///
+/// ```
+/// use zerovec::{ZeroVec, zerovec, ule::AsULE};
+///
+/// const SIGNATURE: ZeroVec<char> = zerovec!(char; <char as AsULE>::ULE::from_aligned; ['a', 'y', 'e', '✌']);
+/// assert!(!SIGNATURE.is_owned());
+///
+/// const EMPTY: ZeroVec<u32> = zerovec![];
+/// assert!(!EMPTY.is_owned());
+/// ```
+#[macro_export]
+macro_rules! zerovec {
+ () => (
+ $crate::ZeroVec::new()
+ );
+ ($aligned:ty; $convert:expr; [$($x:expr),+ $(,)?]) => (
+ $crate::zeroslice![$aligned; $convert; [$($x),+]].as_zerovec()
+ );
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/vendor/zerovec/src/zerovec/serde.rs b/vendor/zerovec/src/zerovec/serde.rs
index e3141071c..bb180d5a1 100644
--- a/vendor/zerovec/src/zerovec/serde.rs
+++ b/vendor/zerovec/src/zerovec/serde.rs
@@ -216,6 +216,6 @@ mod test {
let zerovec_orig: ZeroVec<u32> = ZeroVec::from_slice_or_alloc(&[119, 0xD800, 120]);
let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize");
let zerovec_result = bincode::deserialize::<ZeroVec<char>>(&bincode_buf);
- assert!(matches!(zerovec_result, Err(_)));
+ assert!(zerovec_result.is_err());
}
}
diff --git a/vendor/zerovec/src/zerovec/slice.rs b/vendor/zerovec/src/zerovec/slice.rs
index 52ddc184b..12d88deff 100644
--- a/vendor/zerovec/src/zerovec/slice.rs
+++ b/vendor/zerovec/src/zerovec/slice.rs
@@ -65,10 +65,10 @@ where
/// `bytes` need to be an output from [`ZeroSlice::as_bytes()`].
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
// &[u8] and &[T::ULE] are the same slice with different length metadata.
- Self::from_ule_slice(core::mem::transmute((
- bytes.as_ptr(),
+ Self::from_ule_slice(core::slice::from_raw_parts(
+ bytes.as_ptr() as *const T::ULE,
bytes.len() / core::mem::size_of::<T::ULE>(),
- )))
+ ))
}
/// Construct a `&ZeroSlice<T>` from a slice of ULEs.
@@ -169,7 +169,7 @@ impl<T> ZeroSlice<T>
where
T: AsULE,
{
- /// Gets the element at the specified index. Returns None if out of range.
+ /// Gets the element at the specified index. Returns `None` if out of range.
///
/// # Example
///
@@ -191,7 +191,7 @@ where
.map(T::from_unaligned)
}
- /// Gets the entire slice as an array of length `N`. Returns None if the slice
+ /// Gets the entire slice as an array of length `N`. Returns `None` if the slice
/// does not have exactly `N` elements.
///
/// # Example
@@ -212,7 +212,7 @@ where
Some(ule_array.map(|u| T::from_unaligned(u)))
}
- /// Gets a subslice of elements within a certain range. Returns None if the range
+ /// Gets a subslice of elements within a certain range. Returns `None` if the range
/// is out of bounds of this `ZeroSlice`.
///
/// # Example
@@ -307,7 +307,7 @@ where
Ok(ZeroSlice::from_ule_slice(new_slice))
}
- /// Gets the first element. Returns None if empty.
+ /// Gets the first element. Returns `None` if empty.
///
/// # Example
///
@@ -325,7 +325,7 @@ where
self.as_ule_slice().first().copied().map(T::from_unaligned)
}
- /// Gets the last element. Returns None if empty.
+ /// Gets the last element. Returns `None` if empty.
///
/// # Example
///
@@ -567,6 +567,7 @@ where
#[cfg(test)]
mod test {
use super::*;
+ use crate::zeroslice;
#[test]
fn test_split_first() {
@@ -577,20 +578,16 @@ mod test {
{
// single element slice
const DATA: &ZeroSlice<u16> =
- ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([211]));
- assert_eq!((211, ZeroSlice::new_empty()), DATA.split_first().unwrap());
+ zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [211]);
+ assert_eq!((211, zeroslice![]), DATA.split_first().unwrap());
}
{
// slice with many elements.
const DATA: &ZeroSlice<u16> =
- ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
- 211, 281, 421, 32973,
- ]));
+ zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [211, 281, 421, 32973]);
const EXPECTED_VALUE: (u16, &ZeroSlice<u16>) = (
211,
- ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
- 281, 421, 32973,
- ])),
+ zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [281, 421, 32973]),
);
assert_eq!(EXPECTED_VALUE, DATA.split_first().unwrap());