diff --git a/utils/yoke/derive/examples/derive.rs b/utils/yoke/derive/examples/derive.rs index 6fe1851f0de..dbcaa890e26 100644 --- a/utils/yoke/derive/examples/derive.rs +++ b/utils/yoke/derive/examples/derive.rs @@ -23,7 +23,7 @@ pub struct CowExample<'a> { #[derive(Yokeable, ZeroCopyFrom)] pub struct ZeroVecExample<'a> { - var: VarZeroVec<'a, String>, + var: VarZeroVec<'a, str>, vec: ZeroVec<'a, u16>, } @@ -34,7 +34,7 @@ pub struct ZeroVecExample<'a> { #[derive(Yokeable)] #[yoke(prove_covariance_manually)] pub struct ZeroMapExample<'a> { - map: ZeroMap<'a, String, u16>, + map: ZeroMap<'a, str, u16>, } fn main() {} diff --git a/utils/zerovec/README.md b/utils/zerovec/README.md index 67729a9db18..29136504b94 100644 --- a/utils/zerovec/README.md +++ b/utils/zerovec/README.md @@ -57,12 +57,12 @@ pub struct DataStruct<'data> { #[serde(borrow)] nums: ZeroVec<'data, u32>, #[serde(borrow)] - strs: VarZeroVec<'data, String>, + strs: VarZeroVec<'data, str>, } let data = DataStruct { nums: ZeroVec::from_slice(&[211, 281, 421, 461]), - strs: VarZeroVec::from(&["hello".to_string(), "world".to_string()] as &[_]), + strs: VarZeroVec::from(&["hello", "world"] as &[_]), }; let bincode_bytes = bincode::serialize(&data) .expect("Serialization should be successful"); diff --git a/utils/zerovec/benches/vzv.rs b/utils/zerovec/benches/vzv.rs index fd5c80e88f7..01181fdbfc8 100644 --- a/utils/zerovec/benches/vzv.rs +++ b/utils/zerovec/benches/vzv.rs @@ -45,8 +45,9 @@ fn overview_bench(c: &mut Criterion) { // Same as vzv/char_count/vzv but with different inputs let seed = 42; let (string_vec, _) = random_alphanums(2..=10, 100, seed); - let bytes: Vec = VarZeroVec::get_serializable_bytes(string_vec.as_slice()).unwrap(); - let vzv = VarZeroVec::::parse_byte_slice(black_box(bytes.as_slice())).unwrap(); + let bytes: Vec = + VarZeroVec::::get_serializable_bytes::(string_vec.as_slice()).unwrap(); + let vzv = VarZeroVec::::parse_byte_slice(black_box(bytes.as_slice())).unwrap(); c.bench_function("vzv/overview", |b| { b.iter(|| { @@ -72,8 +73,9 @@ fn overview_bench(c: &mut Criterion) { fn char_count_benches(c: &mut Criterion) { let seed = 2021; let (string_vec, _) = random_alphanums(2..=20, 100, seed); - let bytes: Vec = VarZeroVec::get_serializable_bytes(string_vec.as_slice()).unwrap(); - let vzv = VarZeroVec::::parse_byte_slice(black_box(bytes.as_slice())).unwrap(); + let bytes: Vec = + VarZeroVec::::get_serializable_bytes::(string_vec.as_slice()).unwrap(); + let vzv = VarZeroVec::::parse_byte_slice(black_box(bytes.as_slice())).unwrap(); // *** Count chars in vec of 100 strings *** c.bench_function("vzv/char_count/slice", |b| { @@ -99,8 +101,9 @@ fn binary_search_benches(c: &mut Criterion) { let seed = 2021; let (string_vec, seed) = random_alphanums(2..=20, 500, seed); let (needles, _) = random_alphanums(2..=20, 10, seed); - let bytes: Vec = VarZeroVec::get_serializable_bytes(string_vec.as_slice()).unwrap(); - let vzv = VarZeroVec::::parse_byte_slice(black_box(bytes.as_slice())).unwrap(); + let bytes: Vec = + VarZeroVec::::get_serializable_bytes::(string_vec.as_slice()).unwrap(); + let vzv = VarZeroVec::::parse_byte_slice(black_box(bytes.as_slice())).unwrap(); let single_needle = "lmnop".to_string(); // *** Binary search vec of 500 strings 10 times *** @@ -139,7 +142,7 @@ fn serde_benches(c: &mut Criterion) { let seed = 2021; let (string_vec, _) = random_alphanums(2..=20, 100, seed); let bincode_vec = bincode::serialize(&string_vec).unwrap(); - let vzv = VarZeroVec::from(&*string_vec); + let vzv: VarZeroVec = VarZeroVec::from(&*string_vec); let bincode_vzv = bincode::serialize(&vzv).unwrap(); // *** Deserialize vec of 100 strings *** @@ -154,7 +157,7 @@ fn serde_benches(c: &mut Criterion) { // *** Deserialize vec of 100 strings *** c.bench_function("vzv/deserialize/string/vzv", |b| { - b.iter(|| bincode::deserialize::>(black_box(&bincode_vzv))); + b.iter(|| bincode::deserialize::>(black_box(&bincode_vzv))); }); } diff --git a/utils/zerovec/src/lib.rs b/utils/zerovec/src/lib.rs index 508aba2c837..5e8b0a3ab96 100644 --- a/utils/zerovec/src/lib.rs +++ b/utils/zerovec/src/lib.rs @@ -60,12 +60,12 @@ //! #[serde(borrow)] //! nums: ZeroVec<'data, u32>, //! #[serde(borrow)] -//! strs: VarZeroVec<'data, String>, +//! strs: VarZeroVec<'data, str>, //! } //! //! let data = DataStruct { //! nums: ZeroVec::from_slice(&[211, 281, 421, 461]), -//! strs: VarZeroVec::from(&["hello".to_string(), "world".to_string()] as &[_]), +//! strs: VarZeroVec::from(&["hello", "world"] as &[_]), //! }; //! let bincode_bytes = bincode::serialize(&data) //! .expect("Serialization should be successful"); diff --git a/utils/zerovec/src/map/kv.rs b/utils/zerovec/src/map/kv.rs index e263bc301fb..1b642d30963 100644 --- a/utils/zerovec/src/map/kv.rs +++ b/utils/zerovec/src/map/kv.rs @@ -6,32 +6,41 @@ use super::vecs::ZeroVecLike; use crate::ule::*; use crate::VarZeroVec; use crate::ZeroVec; -use alloc::string::String; -use alloc::vec::Vec; +use alloc::boxed::Box; use core::cmp::Ordering; /// Trait marking types which are allowed to be keys or values in [`ZeroMap`](super::ZeroMap). /// /// Users should not be calling methods of this trait directly, however if you are -/// implementing your own [`AsULE`] or [`AsVarULE`] type you may wish to implement +/// implementing your own [`AsULE`] or [`VarULE`] type you may wish to implement /// this trait. // this lifetime should be a GAT on Container once that is possible #[allow(clippy::upper_case_acronyms)] // KV is not an acronym -pub trait ZeroMapKV<'a>: Sized { +pub trait ZeroMapKV<'a> { /// The container that can be used with this type: [`ZeroVec`] or [`VarZeroVec`]. - type Container: ZeroVecLike<'a, Self, NeedleType = Self::NeedleType, GetType = Self::GetType> - + Sized; + type Container: ZeroVecLike< + 'a, + Self, + NeedleType = Self::NeedleType, + GetType = Self::GetType, + OwnedType = Self::OwnedType, + > + Sized; /// The type to use with `Container::binary_search()` /// /// This type will be predetermined by the choice of `Self::Container` type NeedleType: ?Sized; - /// The type produces by `Container::get()` + /// The type produced by `Container::get()` /// /// This type will be predetermined by the choice of `Self::Container` type GetType: ?Sized; /// The type to use whilst serializing. This may not necessarily be `Self`, however it /// must serialize to the exact same thing as `Self` type SerializeType: ?Sized; + /// The type produced by `Container::replace()` and `Container::remove()`, + /// also used during deserialization. If `Self` is human readable serialized, + /// deserializing to `Self::OwnedType` should produce the same value once + /// passed through `Self::owned_as_self()` + type OwnedType; /// Convert to a needle for searching fn as_needle(&self) -> &Self::NeedleType; /// Compare this type with a `Self::GetType`. This must produce the same result as @@ -42,6 +51,9 @@ pub trait ZeroMapKV<'a>: Sized { /// This uses a callback because it's not possible to return owned-or-borrowed /// types without GATs fn with_ser(g: &Self::GetType, f: impl FnOnce(&Self::SerializeType) -> R) -> R; + + /// Convert an owned value to a borrowed Self + fn owned_as_self(o: &Self::OwnedType) -> &Self; } macro_rules! impl_sized_kv { @@ -51,16 +63,27 @@ macro_rules! impl_sized_kv { type NeedleType = $ty; type GetType = <$ty as AsULE>::ULE; type SerializeType = $ty; + type OwnedType = $ty; + + #[inline] fn as_needle(&self) -> &Self { self } + + #[inline] fn cmp_get(&self, g: &Self::GetType) -> Ordering { self.cmp(&$ty::from_unaligned(g)) } + #[inline] fn with_ser(g: &Self::GetType, f: impl FnOnce(&Self) -> R) -> R { f(&Self::from_unaligned(g)) } + + #[inline] + fn owned_as_self(o: &Self::OwnedType) -> &Self { + o + } } }; } @@ -75,36 +98,58 @@ impl_sized_kv!(i64); impl_sized_kv!(i128); impl_sized_kv!(char); -impl<'a> ZeroMapKV<'a> for String { - type Container = VarZeroVec<'a, String>; +impl<'a> ZeroMapKV<'a> for str { + type Container = VarZeroVec<'a, str>; type NeedleType = str; type GetType = str; type SerializeType = str; + type OwnedType = Box; + + #[inline] fn as_needle(&self) -> &str { self } + + #[inline] fn cmp_get(&self, g: &str) -> Ordering { - (&**self).cmp(g) + (&*self).cmp(g) } + #[inline] fn with_ser(g: &str, f: impl FnOnce(&str) -> R) -> R { f(g) } + + #[inline] + fn owned_as_self(o: &Self::OwnedType) -> &Self { + o + } } -impl<'a> ZeroMapKV<'a> for Vec { - type Container = VarZeroVec<'a, Vec>; +impl<'a> ZeroMapKV<'a> for [u8] { + type Container = VarZeroVec<'a, [u8]>; type NeedleType = [u8]; type GetType = [u8]; type SerializeType = [u8]; + type OwnedType = Box<[u8]>; + + #[inline] fn as_needle(&self) -> &[u8] { self } + + #[inline] fn cmp_get(&self, g: &[u8]) -> Ordering { - (&**self).cmp(g) + (&*self).cmp(g) } + #[inline] fn with_ser(g: &[u8], f: impl FnOnce(&[u8]) -> R) -> R { f(g) } + + #[inline] + fn owned_as_self(o: &Self::OwnedType) -> &Self { + o + } } diff --git a/utils/zerovec/src/map/mod.rs b/utils/zerovec/src/map/mod.rs index 13f523d4f4b..03b867f18c1 100644 --- a/utils/zerovec/src/map/mod.rs +++ b/utils/zerovec/src/map/mod.rs @@ -39,7 +39,7 @@ pub use vecs::ZeroVecLike; /// ]; /// /// // Deserializing to ZeroMap requires no heap allocations. -/// let zero_map: ZeroMap = bincode::deserialize(BINCODE_BYTES) +/// let zero_map: ZeroMap = bincode::deserialize(BINCODE_BYTES) /// .expect("Should deserialize successfully"); /// assert_eq!(zero_map.get(&1), Some("one")); /// ``` @@ -49,6 +49,8 @@ pub struct ZeroMap<'a, K, V> where K: ZeroMapKV<'a>, V: ZeroMapKV<'a>, + K: ?Sized, + V: ?Sized, { pub(crate) keys: K::Container, pub(crate) values: V::Container, @@ -58,6 +60,8 @@ impl<'a, K, V> Default for ZeroMap<'a, K, V> where K: ZeroMapKV<'a>, V: ZeroMapKV<'a>, + K: ?Sized, + V: ?Sized, { fn default() -> Self { Self { @@ -71,6 +75,8 @@ impl<'a, K, V> ZeroMap<'a, K, V> where K: ZeroMapKV<'a>, V: ZeroMapKV<'a>, + K: ?Sized, + V: ?Sized, { /// Construct a new [`ZeroMap`] pub fn new() -> Self { @@ -116,8 +122,8 @@ where /// use zerovec::ZeroMap; /// /// let mut map = ZeroMap::new(); - /// map.insert(1, "one".to_owned()); - /// map.insert(2, "two".to_owned()); + /// map.insert(&1, "one"); + /// map.insert(&2, "two"); /// assert_eq!(map.get(&1), Some("one")); /// assert_eq!(map.get(&3), None); /// ``` @@ -132,8 +138,8 @@ where /// use zerovec::ZeroMap; /// /// let mut map = ZeroMap::new(); - /// map.insert(1, "one".to_owned()); - /// map.insert(2, "two".to_owned()); + /// map.insert(&1, "one"); + /// map.insert(&2, "two"); /// assert_eq!(map.contains_key(&1), true); /// assert_eq!(map.contains_key(&3), false); /// ``` @@ -147,12 +153,12 @@ where /// use zerovec::ZeroMap; /// /// let mut map = ZeroMap::new(); - /// map.insert(1, "one".to_owned()); - /// map.insert(2, "two".to_owned()); + /// map.insert(&1, "one"); + /// map.insert(&2, "two"); /// assert_eq!(map.get(&1), Some("one")); /// assert_eq!(map.get(&3), None); /// ``` - pub fn insert(&mut self, key: K, value: V) -> Option { + pub fn insert(&mut self, key: &K, value: &V) -> Option { let key_needle = key.as_needle(); match self.keys.binary_search(key_needle) { Ok(index) => Some(self.values.replace(index, value)), @@ -170,12 +176,12 @@ where /// use zerovec::ZeroMap; /// /// let mut map = ZeroMap::new(); - /// map.insert(1, "one".to_owned()); - /// map.insert(2, "two".to_owned()); - /// assert_eq!(map.remove(&1), Some("one".to_owned())); + /// map.insert(&1, "one"); + /// map.insert(&2, "two"); + /// assert_eq!(map.remove(&1), Some("one".to_owned().into_boxed_str())); /// assert_eq!(map.get(&1), None); /// ``` - pub fn remove(&mut self, key: &K::NeedleType) -> Option { + pub fn remove(&mut self, key: &K::NeedleType) -> Option { let idx = self.keys.binary_search(key).ok()?; self.keys.remove(idx); Some(self.values.remove(idx)) @@ -188,13 +194,13 @@ where /// use zerovec::ZeroMap; /// /// let mut map = ZeroMap::new(); - /// assert!(map.try_append(1, "uno".to_owned()).is_none()); - /// assert!(map.try_append(3, "tres".to_owned()).is_none()); + /// assert!(map.try_append(&1, "uno").is_none()); + /// assert!(map.try_append(&3, "tres").is_none()); /// - /// let unsuccessful = map.try_append(3, "tres-updated".to_owned()); + /// let unsuccessful = map.try_append(&3, "tres-updated"); /// assert!(unsuccessful.is_some(), "append duplicate of last key"); /// - /// let unsuccessful = map.try_append(2, "dos".to_owned()); + /// let unsuccessful = map.try_append(&2, "dos"); /// assert!(unsuccessful.is_some(), "append out of order"); /// /// assert_eq!(map.get(&1), Some("uno")); @@ -206,7 +212,7 @@ where /// assert_eq!(map.get(&2), None); /// ``` #[must_use] - pub fn try_append(&mut self, key: K, value: V) -> Option<(K, V)> { + pub fn try_append<'b>(&mut self, key: &'b K, value: &'b V) -> Option<(&'b K, &'b V)> { if self.keys.len() != 0 { if let Some(last) = self.keys.get(self.keys.len() - 1) { if key.cmp_get(last) != Ordering::Greater { diff --git a/utils/zerovec/src/map/serde.rs b/utils/zerovec/src/map/serde.rs index ede86717a86..18ed4a6f2a1 100644 --- a/utils/zerovec/src/map/serde.rs +++ b/utils/zerovec/src/map/serde.rs @@ -3,6 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use super::{ZeroMap, ZeroMapKV, ZeroVecLike}; +use alloc::boxed::Box; use core::fmt; use core::marker::PhantomData; use serde::de::{self, MapAccess, Visitor}; @@ -14,6 +15,8 @@ impl<'a, K, V> Serialize for ZeroMap<'a, K, V> where K: ZeroMapKV<'a>, V: ZeroMapKV<'a>, + K: ?Sized, + V: ?Sized, K::Container: Serialize, V::Container: Serialize, K::SerializeType: Serialize, @@ -37,11 +40,12 @@ where } /// Modified example from https://serde.rs/deserialize-map.html -struct ZeroMapMapVisitor { - marker: PhantomData (K, V)>, +struct ZeroMapMapVisitor { + #[allow(clippy::type_complexity)] // it's a marker type, complexity doesn't matter + marker: PhantomData (Box, Box)>, } -impl ZeroMapMapVisitor { +impl ZeroMapMapVisitor { fn new() -> Self { ZeroMapMapVisitor { marker: PhantomData, @@ -49,12 +53,13 @@ impl ZeroMapMapVisitor { } } -impl<'de, K, V> Visitor<'de> for ZeroMapMapVisitor +impl<'de, K: ?Sized, V: ?Sized> Visitor<'de> for ZeroMapMapVisitor where - K: Deserialize<'de> + Ord, - V: Deserialize<'de>, + K: Ord, K: ZeroMapKV<'de>, V: ZeroMapKV<'de>, + K::OwnedType: Deserialize<'de>, + V::OwnedType: Deserialize<'de>, { type Value = ZeroMap<'de, K, V>; @@ -70,11 +75,14 @@ where // While there are entries remaining in the input, add them // into our map. - while let Some((key, value)) = access.next_entry()? { + while let Some((key, value)) = access.next_entry::()? { // Try to append it at the end, hoping for a sorted map. // If not sorted, return an error // a serialized map that came from another ZeroMap - if map.try_append(key, value).is_some() { + if map + .try_append(K::owned_as_self(&key), V::owned_as_self(&value)) + .is_some() + { return Err(de::Error::custom( "ZeroMap's keys must be sorted while deserializing", )); @@ -86,14 +94,15 @@ where } /// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate -impl<'de, K, V> Deserialize<'de> for ZeroMap<'de, K, V> +impl<'de, K: ?Sized, V: ?Sized> Deserialize<'de> for ZeroMap<'de, K, V> where - K: Deserialize<'de> + Ord, - V: Deserialize<'de>, + K: Ord, K::Container: Deserialize<'de>, V::Container: Deserialize<'de>, K: ZeroMapKV<'de>, V: ZeroMapKV<'de>, + K::OwnedType: Deserialize<'de>, + V::OwnedType: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where @@ -127,11 +136,11 @@ mod test { 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 117, 110, 111, 100, 111, 115, 116, 114, 101, 115, ]; - fn make_map() -> ZeroMap<'static, u32, String> { + fn make_map() -> ZeroMap<'static, u32, str> { let mut map = ZeroMap::new(); - map.insert(1, "uno".to_owned()); - map.insert(2, "dos".to_owned()); - map.insert(3, "tres".to_owned()); + map.insert(&1, "uno"); + map.insert(&2, "dos"); + map.insert(&3, "tres"); map } #[test] @@ -139,7 +148,7 @@ mod test { let map = make_map(); let json_str = serde_json::to_string(&map).expect("serialize"); assert_eq!(JSON_STR, json_str); - let new_map: ZeroMap = serde_json::from_str(&json_str).expect("deserialize"); + let new_map: ZeroMap = serde_json::from_str(&json_str).expect("deserialize"); assert_eq!( new_map.iter().collect::>(), map.iter().collect::>() @@ -151,8 +160,7 @@ mod test { let map = make_map(); let bincode_bytes = bincode::serialize(&map).expect("serialize"); assert_eq!(BINCODE_BYTES, bincode_bytes); - let new_map: ZeroMap = - bincode::deserialize(&bincode_bytes).expect("deserialize"); + let new_map: ZeroMap = bincode::deserialize(&bincode_bytes).expect("deserialize"); assert_eq!( new_map.iter().collect::>(), map.iter().collect::>() diff --git a/utils/zerovec/src/map/vecs.rs b/utils/zerovec/src/map/vecs.rs index c70cef81bd9..e7df76536ac 100644 --- a/utils/zerovec/src/map/vecs.rs +++ b/utils/zerovec/src/map/vecs.rs @@ -6,17 +6,20 @@ use crate::ule::*; use crate::varzerovec::owned::VarZeroVecOwned; use crate::VarZeroVec; use crate::ZeroVec; +use alloc::boxed::Box; use alloc::vec::Vec; use core::cmp::Ordering; use core::mem; /// Trait abstracting over [`ZeroVec`] and [`VarZeroVec`], for use in [`ZeroMap`](super::ZeroMap). You /// should not be implementing or calling this trait directly. -pub trait ZeroVecLike<'a, T> { +pub trait ZeroVecLike<'a, T: ?Sized> { /// The type received by `Self::binary_search()` type NeedleType: ?Sized; /// The type returned by `Self::get()` type GetType: ?Sized; + /// The type returned by `Self::remove()` and `Self::replace()` + type OwnedType; /// Search for a key in a sorted vector, returns `Ok(index)` if found, /// returns `Err(insert_index)` if not found, where `insert_index` is the /// index where it should be inserted to maintain sort order. @@ -24,13 +27,13 @@ pub trait ZeroVecLike<'a, T> { /// Get element at `index` fn get(&self, index: usize) -> Option<&Self::GetType>; /// Insert an element at `index` - fn insert(&mut self, index: usize, value: T); + fn insert(&mut self, index: usize, value: &T); /// Remove the element at `index` (panicking if nonexistant) - fn remove(&mut self, index: usize) -> T; + fn remove(&mut self, index: usize) -> Self::OwnedType; /// Replace the element at `index` with another one, returning the old element - fn replace(&mut self, index: usize, value: T) -> T; + fn replace(&mut self, index: usize, value: &T) -> Self::OwnedType; /// Push an element to the end of this vector - fn push(&mut self, value: T); + fn push(&mut self, value: &T); /// The length of this vector fn len(&self) -> usize; /// Create a new, empty vector @@ -55,23 +58,24 @@ where { type NeedleType = T; type GetType = T::ULE; + type OwnedType = T; fn binary_search(&self, k: &T) -> Result { self.binary_search(k) } fn get(&self, index: usize) -> Option<&T::ULE> { self.get_ule_ref(index) } - fn insert(&mut self, index: usize, value: T) { + fn insert(&mut self, index: usize, value: &T) { self.to_mut().insert(index, value.as_unaligned()) } fn remove(&mut self, index: usize) -> T { T::from_unaligned(&self.to_mut().remove(index)) } - fn replace(&mut self, index: usize, value: T) -> T { + fn replace(&mut self, index: usize, value: &T) -> T { let vec = self.to_mut(); T::from_unaligned(&mem::replace(&mut vec[index], value.as_unaligned())) } - fn push(&mut self, value: T) { + fn push(&mut self, value: &T) { self.to_mut().push(value.as_unaligned()) } fn len(&self) -> usize { @@ -98,35 +102,37 @@ where impl<'a, T> ZeroVecLike<'a, T> for VarZeroVec<'a, T> where - T: AsVarULE + Clone, - T::VarULE: Ord, + T: VarULE, + T: Ord, + T: ?Sized, { - type NeedleType = T::VarULE; - type GetType = T::VarULE; - fn binary_search(&self, k: &T::VarULE) -> Result { + type NeedleType = T; + type GetType = T; + type OwnedType = Box; + fn binary_search(&self, k: &T) -> Result { self.binary_search(k) } - fn get(&self, index: usize) -> Option<&T::VarULE> { + fn get(&self, index: usize) -> Option<&T> { self.get(index) } - fn insert(&mut self, index: usize, value: T) { - self.make_mut().insert(index, &value) + fn insert(&mut self, index: usize, value: &T) { + self.make_mut().insert(index, value) } - fn remove(&mut self, index: usize) -> T { + fn remove(&mut self, index: usize) -> Box { let vec = self.make_mut(); - let old = T::from_unaligned(vec.get(index).expect("invalid index")); + let old = vec.get(index).expect("invalid index").to_boxed(); vec.remove(index); old } - fn replace(&mut self, index: usize, value: T) -> T { + fn replace(&mut self, index: usize, value: &T) -> Box { let vec = self.make_mut(); - let old = T::from_unaligned(vec.get(index).expect("invalid index")); + let old = vec.get(index).expect("invalid index").to_boxed(); vec.replace(index, value); old } - fn push(&mut self, value: T) { + fn push(&mut self, value: &T) { let len = self.len(); - self.make_mut().insert(len, &value) + self.make_mut().insert(len, value) } fn len(&self) -> usize { self.len() diff --git a/utils/zerovec/src/ule/mod.rs b/utils/zerovec/src/ule/mod.rs index aa74f31a752..0340884f017 100644 --- a/utils/zerovec/src/ule/mod.rs +++ b/utils/zerovec/src/ule/mod.rs @@ -13,6 +13,9 @@ mod vec; pub use chars::CharULE; pub use plain::PlainOldULE; +use alloc::alloc::Layout; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; use core::{fmt, mem, slice}; /// Fixed-width, byte-aligned data that can be cast to and from a little-endian byte slice. @@ -204,39 +207,14 @@ where } } -/// A trait for any type that has a 1:1 mapping with an variable-width unaligned little-endian (VarULE) type. -/// -/// One such type is `String`, which can be handled as an [`str`], which has no alignment or endianness requirements. -pub trait AsVarULE { - /// The VarULE type corresponding to `Self`. - type VarULE: VarULE + ?Sized; - - /// Converts from `&Self` to `Self::ULE`. - /// - /// This function will almost always be a `Deref` or similar. - /// - /// For best performance, mark your implementation of this function `#[inline]`. - fn as_unaligned(&self) -> &Self::VarULE; - - /// Converts from `&Self::ULE` to an owned `Self`. - /// - /// This function may involve allocation. - /// - /// For best performance, mark your implementation of this function `#[inline]`. - /// - /// # Safety - /// - /// This function is infallible because bit validation should have occured when `Self::ULE` - /// was first constructed. An implementation may therefore involve an `unsafe{}` block, like - /// `from_bytes_unchecked()`. - fn from_unaligned(unaligned: &Self::VarULE) -> Self; -} - /// Variable-width, byte-aligned data that can be cast to and from a little-endian byte slice. /// /// This trait is mostly for unsized types like `str` and `[T]`. It can be implemented on sized types, /// however it is much more preferable to use [`ULE`] for that purpose. /// +/// If deserialization with `VarZeroVec` is desired is recommended to implement `Deserialize` for +/// `Box` (serde does not do this automatically for unsized `T`). +/// /// # Safety /// /// There must be no padding bytes involved in this type: [`Self::as_byte_slice()`] MUST return @@ -325,4 +303,20 @@ pub unsafe trait VarULE: 'static { fn as_byte_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(self as *const Self as *const u8, mem::size_of_val(self)) } } + + /// Allocate on the heap as a `Box` + #[inline] + fn to_boxed(&self) -> Box { + let bytesvec = self.as_byte_slice().to_owned().into_boxed_slice(); + 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); + // Transmute the pointer to an owned pointer + Box::from_raw(ptr) + } + } } diff --git a/utils/zerovec/src/ule/string.rs b/utils/zerovec/src/ule/string.rs index 04721ee9724..64c46f0a158 100644 --- a/utils/zerovec/src/ule/string.rs +++ b/utils/zerovec/src/ule/string.rs @@ -3,21 +3,8 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::ule::*; -use alloc::string::String; use core::str; -impl AsVarULE for String { - type VarULE = str; - #[inline] - fn as_unaligned(&self) -> &str { - self - } - #[inline] - fn from_unaligned(unaligned: &str) -> Self { - unaligned.into() - } -} - // This is safe to implement because from_byte_slice_unchecked returns // the same value as parse_byte_slice unsafe impl VarULE for str { diff --git a/utils/zerovec/src/ule/vec.rs b/utils/zerovec/src/ule/vec.rs index e374a6fafd7..b43df708fe5 100644 --- a/utils/zerovec/src/ule/vec.rs +++ b/utils/zerovec/src/ule/vec.rs @@ -3,39 +3,6 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::ule::*; -use crate::ZeroVec; -use alloc::vec::Vec; - -impl AsVarULE for Vec -where - T: ULE + Clone, -{ - type VarULE = [T]; - #[inline] - fn as_unaligned(&self) -> &[T] { - self - } - #[inline] - fn from_unaligned(unaligned: &[T]) -> Self { - unaligned.into() - } -} - -impl AsVarULE for ZeroVec<'static, T> -where - T: AsULE, - T::ULE: Clone, -{ - type VarULE = [T::ULE]; - #[inline] - fn as_unaligned(&self) -> &[T::ULE] { - self.as_slice() - } - #[inline] - fn from_unaligned(unaligned: &[T::ULE]) -> Self { - ZeroVec::Owned(unaligned.into()) - } -} // This is safe to implement because from_byte_slice_unchecked returns // the same value as parse_byte_slice diff --git a/utils/zerovec/src/varzerovec/components.rs b/utils/zerovec/src/varzerovec/components.rs index aaf06e920cf..b39507bce99 100644 --- a/utils/zerovec/src/varzerovec/components.rs +++ b/utils/zerovec/src/varzerovec/components.rs @@ -3,6 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use super::*; +use alloc::boxed::Box; use alloc::format; use alloc::string::String; use alloc::vec::Vec; @@ -19,20 +20,20 @@ fn usizeify(x: PlainOldULE<4>) -> usize { /// This is where the actual work involved in VarZeroVec happens /// /// See [`SliceComponents::parse_byte_slice()`] for information on the internal invariants involved -pub struct SliceComponents<'a, T> { +pub struct SliceComponents<'a, T: ?Sized> { /// The list of indices into the `things` slice indices: &'a [PlainOldULE<4>], /// The contiguous list of `T::VarULE`s things: &'a [u8], /// The original slice this was constructed from entire_slice: &'a [u8], - marker: PhantomData<&'a [T]>, + marker: PhantomData<&'a T>, } // #[derive()] won't work here since we do not want it to be // bound on T: Copy -impl<'a, T> Copy for SliceComponents<'a, T> {} -impl<'a, T> Clone for SliceComponents<'a, T> { +impl<'a, T: ?Sized> Copy for SliceComponents<'a, T> {} +impl<'a, T: ?Sized> Clone for SliceComponents<'a, T> { fn clone(&self) -> Self { SliceComponents { indices: self.indices, @@ -43,7 +44,7 @@ impl<'a, T> Clone for SliceComponents<'a, T> { } } -impl<'a, T: AsVarULE> SliceComponents<'a, T> { +impl<'a, T: VarULE + ?Sized> SliceComponents<'a, T> { /// Construct a new SliceComponents, 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) @@ -140,7 +141,7 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { /// Get the idx'th element out of this slice. Returns `None` if out of bounds. #[inline] - pub fn get(self, idx: usize) -> Option<&'a T::VarULE> { + pub fn get(self, idx: usize) -> Option<&'a T> { if idx >= self.len() { return None; } @@ -152,7 +153,7 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { /// Safety: /// - `idx` must be in bounds (`idx < self.len()`) #[inline] - unsafe fn get_unchecked(self, idx: usize) -> &'a T::VarULE { + unsafe fn get_unchecked(self, idx: usize) -> &'a T { let start = usizeify(*self.indices.get_unchecked(idx)); let end = if idx + 1 == self.len() { self.things.len() @@ -161,7 +162,7 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { }; debug_assert!(start <= end); let things_slice = self.things.get_unchecked(start..end); - T::VarULE::from_byte_slice_unchecked(things_slice) + T::from_byte_slice_unchecked(things_slice) } /// Create an iterator over the Ts contained in SliceComponents, checking internal invariants: @@ -175,7 +176,7 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { /// This method is NOT allowed to call any other methods on SliceComponents since all other methods /// assume that the slice has been passed through iter_checked #[inline] - fn iter_checked(self) -> impl Iterator>> { + fn iter_checked(self) -> impl Iterator>> { let last = iter::from_fn(move || { if !self.is_empty() { let start = usizeify(self.indices[self.len() - 1]); @@ -201,12 +202,12 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { .ok_or(VarZeroVecError::FormatError) }) .chain(last) - .map(|s| s.and_then(|s| T::VarULE::parse_byte_slice(s).map_err(|e| e.into()))) + .map(|s| s.and_then(|s| T::parse_byte_slice(s).map_err(|e| e.into()))) } /// Create an iterator over the Ts contained in SliceComponents #[inline] - pub fn iter(self) -> impl Iterator { + pub fn iter(self) -> impl Iterator { let last = iter::from_fn(move || { if !self.is_empty() { let start = usizeify(self.indices[self.len() - 1]); @@ -225,14 +226,11 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { unsafe { self.things.get_unchecked(start..end) } }) .chain(last) - .map(|s| unsafe { T::VarULE::from_byte_slice_unchecked(s) }) + .map(|s| unsafe { T::from_byte_slice_unchecked(s) }) } - pub fn to_vec(self) -> Vec - where - T: Clone, - { - self.iter().map(T::from_unaligned).collect() + pub fn to_vec(self) -> Vec> { + self.iter().map(T::to_boxed).collect() } // Dump a debuggable representation of this type @@ -249,10 +247,11 @@ impl<'a, T: AsVarULE> SliceComponents<'a, T> { impl<'a, T> SliceComponents<'a, T> where - T: AsVarULE, - T::VarULE: Ord, + T: VarULE, + T: ?Sized, + T: Ord, { - pub fn binary_search(&self, needle: &T::VarULE) -> Result { + pub fn binary_search(&self, needle: &T) -> Result { // This code is an absolute atrocity. This code is not a place of honor. This // code is known to the State of California to cause cancer. // @@ -287,14 +286,14 @@ where } } -pub fn get_serializable_bytes(elements: &[T]) -> Option> { +pub fn get_serializable_bytes>(elements: &[A]) -> Option> { let mut vec = Vec::with_capacity(4 + 4 * elements.len()); let len_u32: u32 = elements.len().try_into().ok()?; vec.extend(&len_u32.as_unaligned().0); let mut offset: u32 = 0; for element in elements { vec.extend(&offset.as_unaligned().0); - let ule = element.as_unaligned(); + let ule = element.as_ref(); let slice = ule.as_byte_slice(); debug_assert_eq!(mem::size_of_val(ule), mem::size_of_val(slice)); let len_u32: u32 = slice.len().try_into().ok()?; @@ -302,7 +301,7 @@ pub fn get_serializable_bytes(elements: &[T]) -> Option> { } vec.reserve(offset as usize); for element in elements { - vec.extend(element.as_unaligned().as_byte_slice()) + vec.extend(element.as_ref().as_byte_slice()) } Some(vec) } diff --git a/utils/zerovec/src/varzerovec/mod.rs b/utils/zerovec/src/varzerovec/mod.rs index 8c74e38e593..a9dbe8b1f25 100644 --- a/utils/zerovec/src/varzerovec/mod.rs +++ b/utils/zerovec/src/varzerovec/mod.rs @@ -3,6 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::ule::*; +use alloc::boxed::Box; use alloc::vec::Vec; use components::SliceComponents; use core::fmt::{self, Display}; @@ -23,10 +24,8 @@ pub use ule::VarZeroVecULE; /// desirable to borrow data from an unaligned byte slice, such as zero-copy deserialization, and /// where `T`'s data is variable-length (e.g. `String`) /// -/// `T` must implement [`AsVarULE`], which is already implemented for [`String`] and `Vec` where -/// `T` implements [`ULE`]. It is also implemented on `VarZeroVec<'static, T>` if the inconvenience of -/// converting to/from ULE is not desired. References are obtained -/// as its [`AsVarULE::VarULE`] type, which in the case of [`String`] is [`str`]. +/// `T` must implement [`VarULE`], which is already implemented for [`str`] and `[T]` where +/// `T` implements [`ULE`]. It is also implemented on `VarZeroVecULE` for nesting. /// /// `VarZeroVec` behaves much like [`std::borrow::Cow`], where it can be constructed from owned data /// but can also borrow from some buffer. @@ -63,14 +62,14 @@ pub use ule::VarZeroVecULE; /// 6, 0, 0, 0, 119, 207, 137, 230, 150, 135, 240, 145, 132, 131, /// ]; /// -/// let zerovec: VarZeroVec = VarZeroVec::parse_byte_slice(bytes)?; +/// let zerovec: VarZeroVec = VarZeroVec::parse_byte_slice(bytes)?; /// /// assert_eq!(zerovec.get(2), Some("文")); /// assert_eq!(zerovec, &*strings); /// # Ok::<(), VarZeroVecError>(()) /// ``` /// -/// Here's another example with `Vec` and `ZeroVec<'static, T>`: +/// Here's another example with `[T]`: /// /// ```rust /// # use std::str::Utf8Error; @@ -91,11 +90,9 @@ pub use ule::VarZeroVecULE; /// 0, 0, 42, 0, 0, 0, 3, 217, 0, 0, 57, 48, 0, 0, 49, 212, 0, 0, /// 9, 0, 0, 0]; /// -/// let zerovec: VarZeroVec>> = VarZeroVec::parse_byte_slice(bytes)?; -/// let zerovec2: VarZeroVec> = VarZeroVec::parse_byte_slice(bytes)?; +/// let zerovec: VarZeroVec<[PlainOldULE<4>]> = VarZeroVec::parse_byte_slice(bytes)?; /// /// assert_eq!(zerovec.get(2).and_then(|v| v.get(1)), Some(&55555.into())); -/// assert_eq!(zerovec2.get(2).and_then(|v| v.get(1)), Some(&55555.into())); /// assert_eq!(zerovec, &*numbers); /// for (zv, v) in zerovec.iter().zip(numbers.iter()) { /// assert_eq!(zv, v); @@ -109,7 +106,7 @@ pub use ule::VarZeroVecULE; /// /// [`ule`]: crate::ule #[derive(Clone)] -pub struct VarZeroVec<'a, T>(VarZeroVecInner<'a, T>); +pub struct VarZeroVec<'a, T: ?Sized>(VarZeroVecInner<'a, T>); /// Implementation details of VarZeroVec /// @@ -132,7 +129,7 @@ pub struct VarZeroVec<'a, T>(VarZeroVecInner<'a, T>); /// /// The actual implementation details of this can be found in the `components` module #[derive(Clone)] -enum VarZeroVecInner<'a, T> { +enum VarZeroVecInner<'a, T: ?Sized> { Owned(VarZeroVecOwned), /// This is *basically* an `&'a [u8]` to a zero copy buffer, but split out into /// the buffer components. Logically this is capable of behaving as @@ -156,16 +153,16 @@ impl Display for VarZeroVecError { } } -impl fmt::Debug for VarZeroVec<'_, T> +impl fmt::Debug for VarZeroVec<'_, T> where - T::VarULE: fmt::Debug, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } -pub type ParseErrorFor = VarZeroVecError<<::VarULE as VarULE>::Error>; +pub type ParseErrorFor = VarZeroVecError<::Error>; impl From for VarZeroVecError { fn from(e: E) -> Self { @@ -173,27 +170,28 @@ impl From for VarZeroVecError { } } -impl<'a, T> From> for VarZeroVec<'a, T> { +impl<'a, T: ?Sized> From> for VarZeroVec<'a, T> { #[inline] fn from(other: VarZeroVecInner<'a, T>) -> Self { Self(other) } } -impl<'a, T> From> for VarZeroVec<'a, T> { +impl<'a, T: ?Sized> From> for VarZeroVec<'a, T> { #[inline] fn from(other: VarZeroVecOwned) -> Self { VarZeroVecInner::Owned(other).into() } } -impl<'a, T: AsVarULE> VarZeroVec<'a, T> { +impl<'a, T: VarULE + ?Sized> VarZeroVec<'a, T> { fn get_components<'b>(&'b self) -> SliceComponents<'b, T> { match self.0 { VarZeroVecInner::Owned(ref owned) => owned.get_components(), VarZeroVecInner::Borrowed(components) => components, } } + /// Get the number of elements in this vector /// /// # Example @@ -205,9 +203,9 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), /// "baz".to_owned(), "quux".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); /// - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// assert_eq!(vec.len(), 4); /// # Ok::<(), VarZeroVecError>(()) /// ``` @@ -225,9 +223,9 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// # use zerovec::VarZeroVec; /// /// let strings: Vec = vec![]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); /// - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// assert!(vec.is_empty()); /// # Ok::<(), VarZeroVecError>(()) /// ``` @@ -237,7 +235,7 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// Parse a VarZeroVec from a slice of the appropriate format /// - /// Slices of the right format can be obtained via [`VarZeroVec::get_serializable_bytes()`] + /// Slices of the right format can be obtained via [`VarZeroVec::::get_serializable_bytes()`] /// or [`VarZeroVec::get_encoded_slice()`] /// /// # Example @@ -249,9 +247,9 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), /// "baz".to_owned(), "quux".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); /// - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// assert_eq!(&vec[0], "foo"); /// assert_eq!(&vec[1], "bar"); /// assert_eq!(&vec[2], "baz"); @@ -280,8 +278,8 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), /// "baz".to_owned(), "quux".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// /// let mut iter_results: Vec<&str> = vec.iter().collect(); /// assert_eq!(iter_results[0], "foo"); @@ -290,7 +288,7 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// assert_eq!(iter_results[3], "quux"); /// # Ok::<(), VarZeroVecError>(()) /// ``` - pub fn iter<'b: 'a>(&'b self) -> impl Iterator { + pub fn iter<'b: 'a>(&'b self) -> impl Iterator { self.get_components().iter() } @@ -305,8 +303,8 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), /// "baz".to_owned(), "quux".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// /// let mut iter_results: Vec<&str> = vec.iter().collect(); /// assert_eq!(vec.get(0), Some("foo")); @@ -316,7 +314,7 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// assert_eq!(vec.get(4), None); /// # Ok::<(), VarZeroVecError>(()) /// ``` - pub fn get(&self, idx: usize) -> Option<&T::VarULE> { + pub fn get(&self, idx: usize) -> Option<&T> { self.get_components().get(idx) } @@ -332,8 +330,8 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), /// "baz".to_owned(), "quux".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// /// assert_eq!(vec.len(), 4); /// let mutvec = vec.make_mut(); @@ -349,10 +347,7 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { // // This function is crate-public for now since we don't yet want to stabilize // the internal implementation details - pub(crate) fn make_mut(&mut self) -> &mut VarZeroVecOwned - where - T: Clone, - { + pub(crate) fn make_mut(&mut self) -> &mut VarZeroVecOwned { match self.0 { VarZeroVecInner::Owned(ref mut vec) => vec, VarZeroVecInner::Borrowed(components) => { @@ -375,18 +370,15 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), /// "baz".to_owned(), "quux".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// /// assert_eq!(vec.len(), 4); /// // has 'static lifetime /// let owned = vec.into_owned(); /// # Ok::<(), VarZeroVecError>(()) /// ``` - pub fn into_owned(mut self) -> VarZeroVec<'static, T> - where - T: Clone, - { + pub fn into_owned(mut self) -> VarZeroVec<'static, T> { self.make_mut(); match self.0 { VarZeroVecInner::Owned(vec) => vec.into(), @@ -394,14 +386,25 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { } } - /// Obtain an owned `Vec` out of this - pub fn to_vec(&self) -> Vec - where - T: Clone, - { + /// Obtain this `VarZeroVec` as a [`VarZeroVecULE`] + pub fn as_ule(&self) -> &VarZeroVecULE { + let slice = self.get_encoded_slice(); + unsafe { + // safety: the slice is known to come from a valid parsed VZV + VarZeroVecULE::from_byte_slice_unchecked(slice) + } + } + + /// Obtain an owned `Vec>` out of this + pub fn to_vec(&self) -> Vec> { self.get_components().to_vec() } + /// Get a [`VarZeroVec`] that borrows from this one + pub fn as_borrowed<'b>(&'b self) -> VarZeroVec<'b, T> { + VarZeroVecInner::Borrowed(self.get_components()).into() + } + /// Obtain the internal encoded slice /// /// This can be passed back to [`Self::parse_byte_slice()`] @@ -426,15 +429,15 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { /// # use zerovec::VarZeroVec; /// /// let strings = vec!["foo".to_owned(), "bar".to_owned(), "baz".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); /// - /// let mut borrowed: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let mut borrowed: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// assert_eq!(borrowed, &*strings); /// /// # Ok::<(), VarZeroVecError>(()) /// ``` /// - pub fn get_serializable_bytes(elements: &[T]) -> Option> { + pub fn get_serializable_bytes>(elements: &[A]) -> Option> { components::get_serializable_bytes(elements) } @@ -451,8 +454,9 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { impl<'a, T> VarZeroVec<'a, T> where - T: AsVarULE, - T::VarULE: Ord, + T: VarULE, + T: ?Sized, + T: Ord, { /// Binary searches a sorted `VarZeroVec` for the given element. For more information, see /// the primitive function [`binary_search`]. @@ -466,8 +470,8 @@ where /// /// let strings = vec!["a".to_owned(), "b".to_owned(), /// "f".to_owned(), "g".to_owned()]; - /// let bytes = VarZeroVec::get_serializable_bytes(&strings).unwrap(); - /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; + /// let bytes = VarZeroVec::::get_serializable_bytes(&strings).unwrap(); + /// let mut vec: VarZeroVec = VarZeroVec::parse_byte_slice(&bytes)?; /// /// assert_eq!(vec.binary_search("f"), Ok(2)); /// assert_eq!(vec.binary_search("e"), Err(2)); @@ -476,31 +480,34 @@ where /// /// [`binary_search`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search #[inline] - pub fn binary_search(&self, x: &T::VarULE) -> Result { + pub fn binary_search(&self, x: &T) -> Result { self.get_components().binary_search(x) } } -impl<'a, T: AsVarULE> Index for VarZeroVec<'a, T> { - type Output = T::VarULE; +impl<'a, T: VarULE + ?Sized> Index for VarZeroVec<'a, T> { + type Output = T; fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("Indexing VarZeroVec out of bounds") } } -impl<'a, T> From<&'_ [T]> for VarZeroVec<'a, T> +impl<'a, A, T> From<&'_ [A]> for VarZeroVec<'a, T> where - T: AsVarULE, + T: VarULE, + T: ?Sized, + A: AsRef, { - fn from(other: &'_ [T]) -> Self { + fn from(other: &'_ [A]) -> Self { VarZeroVecOwned::from_elements(other).into() } } impl<'a, 'b, T> PartialEq> for VarZeroVec<'a, T> where - T: AsVarULE, - T::VarULE: PartialEq, + T: VarULE, + T: ?Sized, + T: PartialEq, { #[inline] fn eq(&self, other: &VarZeroVec<'b, T>) -> bool { @@ -510,13 +517,14 @@ where } } -impl PartialEq<&[T]> for VarZeroVec<'_, T> +impl PartialEq<&'_ [A]> for VarZeroVec<'_, T> where - T: AsVarULE, - T::VarULE: PartialEq, + T: VarULE + ?Sized, + T: PartialEq, + A: AsRef, { #[inline] - fn eq(&self, other: &&[T]) -> bool { - self.iter().eq(other.iter().map(|t| t.as_unaligned())) + fn eq(&self, other: &&[A]) -> bool { + self.iter().eq(other.iter().map(|t| t.as_ref())) } } diff --git a/utils/zerovec/src/varzerovec/owned.rs b/utils/zerovec/src/varzerovec/owned.rs index 13233b190e8..10fb2cf6452 100644 --- a/utils/zerovec/src/varzerovec/owned.rs +++ b/utils/zerovec/src/varzerovec/owned.rs @@ -2,6 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use alloc::boxed::Box; use alloc::vec::Vec; use super::*; @@ -12,8 +13,8 @@ use core::ptr; use core::slice; #[derive(Clone)] -pub struct VarZeroVecOwned { - marker: PhantomData<[T]>, +pub struct VarZeroVecOwned { + marker: PhantomData>, // safety invariant: must parse into a valid SliceComponents entire_slice: Vec, } @@ -26,7 +27,7 @@ enum ShiftType { Remove, } -impl VarZeroVecOwned { +impl VarZeroVecOwned { /// Construct an empty VarZeroVecOwned pub fn new() -> Self { Self { @@ -43,7 +44,7 @@ impl VarZeroVecOwned { } /// Construct a VarZeroVecOwned from a list of elements - pub fn from_elements(elements: &[T]) -> Self { + pub fn from_elements>(elements: &[A]) -> Self { Self { marker: PhantomData, entire_slice: components::get_serializable_bytes(elements).expect( @@ -89,12 +90,12 @@ impl VarZeroVecOwned { } /// Obtain an iterator over VarZeroVecOwned's elements - pub fn iter<'b>(&'b self) -> impl Iterator { + pub fn iter<'b>(&'b self) -> impl Iterator { self.get_components().iter() } /// Get one of VarZeroVecOwned's elements, returning None if the index is out of bounds - pub fn get(&self, idx: usize) -> Option<&T::VarULE> { + pub fn get(&self, idx: usize) -> Option<&T> { self.get_components().get(idx) } @@ -193,10 +194,7 @@ impl VarZeroVecOwned { self.entire_slice.clear() } - pub fn to_vec(&self) -> Vec - where - T: Clone, - { + pub fn to_vec(&self) -> Vec> { self.get_components().to_vec() } @@ -384,18 +382,19 @@ impl VarZeroVecOwned { ); } + let value = element.as_byte_slice(); + if len == 0 { - // If there is no data, just construct it with the existing procedure - // for constructing an entire slice - self.entire_slice = components::get_serializable_bytes(slice::from_ref(element)) - .expect( - "attempted to insert an element too large to be encoded\ - in a VarZeroVec", - ); + // 4 bytes for length, 4 bytes for the index, remaining for element + self.reserve(8 + value.len()); + let len_u32 = 1u32; + let index_u32 = 0u32; + self.entire_slice.extend(&len_u32.as_unaligned().0); + self.entire_slice.extend(&index_u32.as_unaligned().0); + self.entire_slice.extend(value); return; } - let value = element.as_unaligned().as_byte_slice(); assert!(value.len() < u32::MAX as usize); unsafe { self.shift(index, value.len() as u32, ShiftType::Insert) @@ -421,7 +420,7 @@ impl VarZeroVecOwned { } } - pub fn replace(&mut self, index: usize, value: T) { + pub fn replace(&mut self, index: usize, value: &T) { let len = self.len(); if index >= len { panic!( @@ -430,7 +429,7 @@ impl VarZeroVecOwned { ); } - let value = value.as_unaligned().as_byte_slice(); + let value = value.as_byte_slice(); assert!(value.len() < u32::MAX as usize); unsafe { self.shift(index, value.len() as u32, ShiftType::Replace) @@ -441,80 +440,82 @@ impl VarZeroVecOwned { impl VarZeroVecOwned where - T: AsVarULE, - T::VarULE: Ord, + T: VarULE, + T: ?Sized, + T: Ord, { /// Binary searches a sorted `VarZeroVecOwned` for the given element. FoGeneralr more information, see /// the primitive function [`binary_search`]. /// /// [`binary_search`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search #[inline] - pub fn binary_search(&self, x: &T::VarULE) -> Result { + pub fn binary_search(&self, x: &T) -> Result { self.get_components().binary_search(x) } } -impl PartialEq<&[T]> for VarZeroVecOwned -where - T: AsVarULE, - T::VarULE: PartialEq, -{ - #[inline] - fn eq(&self, other: &&[T]) -> bool { - self.iter().eq(other.iter().map(|t| t.as_unaligned())) - } -} - -impl Index for VarZeroVecOwned { - type Output = T::VarULE; +impl Index for VarZeroVecOwned { + type Output = T; fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("Indexing VarZeroVec out of bounds") } } -impl fmt::Debug for VarZeroVecOwned +impl fmt::Debug for VarZeroVecOwned where - T::VarULE: fmt::Debug, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } -impl Default for VarZeroVecOwned { +impl Default for VarZeroVecOwned { fn default() -> Self { Self::new() } } +impl PartialEq<&'_ [A]> for VarZeroVecOwned +where + T: VarULE + ?Sized, + T: PartialEq, + A: AsRef, +{ + #[inline] + fn eq(&self, other: &&[A]) -> bool { + self.iter().eq(other.iter().map(|t| t.as_ref())) + } +} + #[cfg(test)] mod test { use super::VarZeroVecOwned; #[test] fn test_insert_integrity() { let mut items: Vec = Vec::new(); - let mut zerovec = VarZeroVecOwned::new(); + let mut zerovec = VarZeroVecOwned::::new(); // Insert into an empty vec. items.insert(0, "1234567890".into()); - zerovec.insert(0, &"1234567890".into()); + zerovec.insert(0, "1234567890"); assert_eq!(zerovec, &*items); - zerovec.insert(1, &"foo3".into()); + zerovec.insert(1, "foo3"); items.insert(1, "foo3".into()); assert_eq!(zerovec, &*items); // Insert at the end. items.insert(items.len(), "qwertyuiop".into()); - zerovec.insert(zerovec.len(), &"qwertyuiop".into()); + zerovec.insert(zerovec.len(), "qwertyuiop"); assert_eq!(zerovec, &*items); items.insert(0, "asdfghjkl;".into()); - zerovec.insert(0, &"asdfghjkl;".into()); + zerovec.insert(0, "asdfghjkl;"); assert_eq!(zerovec, &*items); items.insert(2, "".into()); - zerovec.insert(2, &"".into()); + zerovec.insert(2, ""); assert_eq!(zerovec, &*items); } @@ -523,14 +524,14 @@ mod test { // Tests that insert() works even when there // is not enough space for the new index in entire_slice.len() let mut items: Vec = Vec::new(); - let mut zerovec = VarZeroVecOwned::new(); + let mut zerovec = VarZeroVecOwned::::new(); // Insert into an empty vec. items.insert(0, "abc".into()); - zerovec.insert(0, &"abc".into()); + zerovec.insert(0, "abc"); assert_eq!(zerovec, &*items); - zerovec.insert(1, &"def".into()); + zerovec.insert(1, "def"); items.insert(1, "def".into()); assert_eq!(zerovec, &*items); } @@ -538,7 +539,7 @@ mod test { #[test] #[should_panic] fn test_insert_past_end() { - VarZeroVecOwned::::new().insert(1, &"".into()); + VarZeroVecOwned::::new().insert(1, ""); } #[test] @@ -552,7 +553,7 @@ mod test { "five".into(), "".into(), ]; - let mut zerovec = VarZeroVecOwned::from_elements(&items); + let mut zerovec = VarZeroVecOwned::::from_elements(&items); for index in [0, 2, 4, 0, 1, 1, 0] { items.remove(index); @@ -563,7 +564,7 @@ mod test { #[test] fn test_removing_last_element_clears() { - let mut zerovec = VarZeroVecOwned::from_elements(&["buy some apples".to_string()]); + let mut zerovec = VarZeroVecOwned::::from_elements(&["buy some apples".to_string()]); assert!(!zerovec.get_components().entire_slice().is_empty()); zerovec.remove(0); assert!(zerovec.get_components().entire_slice().is_empty()); @@ -572,7 +573,7 @@ mod test { #[test] #[should_panic] fn test_remove_past_end() { - VarZeroVecOwned::::new().remove(0); + VarZeroVecOwned::::new().remove(0); } #[test] @@ -586,37 +587,37 @@ mod test { "five".into(), "".into(), ]; - let mut zerovec = VarZeroVecOwned::from_elements(&items); + let mut zerovec = VarZeroVecOwned::::from_elements(&items); // Replace with an element of the same size (and the first element) items[0] = "blablah".into(); - zerovec.replace(0, "blablah".into()); + zerovec.replace(0, "blablah"); assert_eq!(zerovec, &*items); // Replace with a smaller element items[1] = "twily".into(); - zerovec.replace(1, "twily".into()); + zerovec.replace(1, "twily"); assert_eq!(zerovec, &*items); // Replace an empty element items[3] = "aoeuidhtns".into(); - zerovec.replace(3, "aoeuidhtns".into()); + zerovec.replace(3, "aoeuidhtns"); assert_eq!(zerovec, &*items); // Replace the last element items[6] = "0123456789".into(); - zerovec.replace(6, "0123456789".into()); + zerovec.replace(6, "0123456789"); assert_eq!(zerovec, &*items); // Replace with an empty element items[2] = "".into(); - zerovec.replace(2, "".into()); + zerovec.replace(2, ""); assert_eq!(zerovec, &*items); } #[test] #[should_panic] fn test_replace_past_end() { - VarZeroVecOwned::::new().replace(0, "".into()); + VarZeroVecOwned::::new().replace(0, ""); } } diff --git a/utils/zerovec/src/varzerovec/serde.rs b/utils/zerovec/src/varzerovec/serde.rs index 89e4949c33a..ebdaca27a26 100644 --- a/utils/zerovec/src/varzerovec/serde.rs +++ b/utils/zerovec/src/varzerovec/serde.rs @@ -4,17 +4,18 @@ use super::VarZeroVec; use crate::ule::*; +use alloc::boxed::Box; use alloc::vec::Vec; use core::fmt; use core::marker::PhantomData; use serde::de::{self, Deserialize, Deserializer, SeqAccess, Visitor}; use serde::ser::{Serialize, SerializeSeq, Serializer}; -struct VarZeroVecVisitor { - marker: PhantomData T>, +struct VarZeroVecVisitor { + marker: PhantomData Box>, } -impl Default for VarZeroVecVisitor { +impl Default for VarZeroVecVisitor { fn default() -> Self { Self { marker: PhantomData, @@ -24,7 +25,8 @@ impl Default for VarZeroVecVisitor { impl<'de, T> Visitor<'de> for VarZeroVecVisitor where - T: 'de + Deserialize<'de> + AsVarULE, + T: VarULE + ?Sized, + Box: Deserialize<'de>, { type Value = VarZeroVec<'de, T>; @@ -43,12 +45,12 @@ where where A: SeqAccess<'de>, { - let mut vec: Vec = if let Some(capacity) = seq.size_hint() { + let mut vec: Vec> = if let Some(capacity) = seq.size_hint() { Vec::with_capacity(capacity) } else { Vec::new() }; - while let Some(value) = seq.next_element::()? { + while let Some(value) = seq.next_element::>()? { vec.push(value); } Ok((&*vec).into()) @@ -58,7 +60,8 @@ where /// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate impl<'de, 'a, T> Deserialize<'de> for VarZeroVec<'a, T> where - T: 'de + Deserialize<'de> + AsVarULE, + T: VarULE + ?Sized, + Box: Deserialize<'de>, 'de: 'a, { fn deserialize(deserializer: D) -> Result @@ -77,7 +80,7 @@ where /// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate impl Serialize for VarZeroVec<'_, T> where - T: Serialize + AsVarULE + Clone, + T: Serialize + VarULE + ?Sized, { fn serialize(&self, serializer: S) -> Result where @@ -86,12 +89,7 @@ where if serializer.is_human_readable() { let mut seq = serializer.serialize_seq(Some(self.len()))?; for value in self.iter() { - // In the case of T=String this creates an unnecessary - // allocation just to throw it away, but we cannot use this guarantee - // for all T. We could potentially add a `serialize_unaligned_element` - // method to AsVarULE, but since serialization performance is not - // critical, this is currently not done. - seq.serialize_element(&T::from_unaligned(value))?; + seq.serialize_element(value)?; } seq.end() } else { @@ -125,14 +123,14 @@ mod test { ]; #[test] fn test_serde_json() { - let zerovec_orig: VarZeroVec = VarZeroVec::parse_byte_slice(BYTES).expect("parse"); + let zerovec_orig: VarZeroVec = VarZeroVec::parse_byte_slice(BYTES).expect("parse"); let json_str = serde_json::to_string(&zerovec_orig).expect("serialize"); assert_eq!(JSON_STR, json_str); // VarZeroVec should deserialize from JSON to either Vec or VarZeroVec - let vec_new: Vec = + let vec_new: Vec> = serde_json::from_str(&json_str).expect("deserialize from buffer to Vec"); assert_eq!(zerovec_orig.to_vec(), vec_new); - let zerovec_new: VarZeroVec = + let zerovec_new: VarZeroVec = serde_json::from_str(&json_str).expect("deserialize from buffer to VarZeroVec"); assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec()); assert!(zerovec_new.is_owned()); @@ -140,10 +138,10 @@ mod test { #[test] fn test_serde_bincode() { - let zerovec_orig: VarZeroVec = VarZeroVec::parse_byte_slice(BYTES).expect("parse"); + let zerovec_orig: VarZeroVec = VarZeroVec::parse_byte_slice(BYTES).expect("parse"); let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); assert_eq!(BINCODE_BUF, bincode_buf); - let zerovec_new: VarZeroVec = + let zerovec_new: VarZeroVec = bincode::deserialize(&bincode_buf).expect("deserialize from buffer to VarZeroVec"); assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec()); assert!(!zerovec_new.is_owned()); @@ -154,21 +152,21 @@ mod test { let src_vec = NONASCII_STR .iter() .copied() - .map(String::from) + .map(Box::::from) .collect::>(); - let mut zerovec: VarZeroVec = + let mut zerovec: VarZeroVec = VarZeroVec::parse_byte_slice(NONASCII_BYTES).expect("parse"); assert_eq!(zerovec.to_vec(), src_vec); let bincode_buf = bincode::serialize(&zerovec).expect("serialize"); let zerovec_result = - bincode::deserialize::>(&bincode_buf).expect("deserialize"); + bincode::deserialize::>(&bincode_buf).expect("deserialize"); assert_eq!(zerovec_result.to_vec(), src_vec); // try again with owned zerovec zerovec.make_mut(); let bincode_buf = bincode::serialize(&zerovec).expect("serialize"); let zerovec_result = - bincode::deserialize::>(&bincode_buf).expect("deserialize"); + bincode::deserialize::>(&bincode_buf).expect("deserialize"); assert_eq!(zerovec_result.to_vec(), src_vec); } } diff --git a/utils/zerovec/src/varzerovec/ule.rs b/utils/zerovec/src/varzerovec/ule.rs index 8b8e69f91d4..65f6aedf9df 100644 --- a/utils/zerovec/src/varzerovec/ule.rs +++ b/utils/zerovec/src/varzerovec/ule.rs @@ -22,35 +22,36 @@ use core::mem; /// let strings_34 = vec![strings_3.clone(), strings_4.clone()]; /// let all_strings = vec![strings_12, strings_34]; /// -/// let vzv_1 = VarZeroVec::from(&*strings_1); -/// let vzv_2 = VarZeroVec::from(&*strings_2); -/// let vzv_3 = VarZeroVec::from(&*strings_3); -/// let vzv_4 = VarZeroVec::from(&*strings_4); -/// let vzv_12 = VarZeroVec::from(&[vzv_1, vzv_2] as &[_]); -/// let vzv_34 = VarZeroVec::from(&[vzv_3, vzv_4] as &[_]); -/// let vzv_all = VarZeroVec::from(&[vzv_12, vzv_34] as &[_]); +/// let vzv_1: VarZeroVec = VarZeroVec::from(&*strings_1); +/// let vzv_2: VarZeroVec = VarZeroVec::from(&*strings_2); +/// let vzv_3: VarZeroVec = VarZeroVec::from(&*strings_3); +/// let vzv_4: VarZeroVec = VarZeroVec::from(&*strings_4); +/// let vzv_12 = VarZeroVec::from(&[vzv_1.as_ule(), vzv_2.as_ule()] as &[_]); +/// let vzv_34 = VarZeroVec::from(&[vzv_3.as_ule(), vzv_4.as_ule()] as &[_]); +/// let vzv_all = VarZeroVec::from(&[vzv_12.as_ule(), vzv_34.as_ule()] as &[_]); /// -/// let reconstructed = vzv_all.iter() -/// .map(|v: &VarZeroVecULE<_>| { -/// v.iter().map(|x: &VarZeroVecULE<_>| x.as_varzerovec().to_vec()).collect::>() +/// let reconstructed: Vec>> = vzv_all.iter() +/// .map(|v: &VarZeroVecULE>| { +/// v.iter().map(|x: &VarZeroVecULE<_>| x.as_varzerovec().iter().map(|s| s.to_owned()).collect::>()) +/// .collect::>() /// }).collect::>(); /// assert_eq!(reconstructed, all_strings); /// /// let bytes = vzv_all.get_encoded_slice(); -/// let vzv_from_bytes: VarZeroVec>> = VarZeroVec::parse_byte_slice(bytes).unwrap(); +/// let vzv_from_bytes: VarZeroVec>> = VarZeroVec::parse_byte_slice(bytes).unwrap(); /// assert_eq!(vzv_from_bytes, vzv_all); /// ``` // // safety invariant: The slice MUST be one which parses to // a valid SliceComponents #[repr(transparent)] -pub struct VarZeroVecULE { - marker: PhantomData<[T]>, +pub struct VarZeroVecULE { + marker: PhantomData, /// The original slice this was constructed from entire_slice: [u8], } -impl VarZeroVecULE { +impl VarZeroVecULE { #[inline] fn get_components<'a>(&'a self) -> SliceComponents<'a, T> { unsafe { @@ -70,12 +71,12 @@ impl VarZeroVecULE { } /// Obtain an iterator over VarZeroVecULE's elements - pub fn iter<'b>(&'b self) -> impl Iterator { + pub fn iter<'b>(&'b self) -> impl Iterator { self.get_components().iter() } /// Get one of VarZeroVecULE's elements, returning None if the index is out of bounds - pub fn get(&self, idx: usize) -> Option<&T::VarULE> { + pub fn get(&self, idx: usize) -> Option<&T> { self.get_components().get(idx) } @@ -90,19 +91,20 @@ impl VarZeroVecULE { impl VarZeroVecULE where - T: AsVarULE, - T::VarULE: Ord, + T: VarULE, + T: ?Sized, + T: Ord, { /// Binary searches a sorted `VarZeroVecULE` for the given element. For more information, see /// the primitive function [`binary_search`]. /// /// [`binary_search`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search #[inline] - pub fn binary_search(&self, x: &T::VarULE) -> Result { + pub fn binary_search(&self, x: &T) -> Result { self.get_components().binary_search(x) } } -unsafe impl VarULE for VarZeroVecULE { +unsafe impl VarULE for VarZeroVecULE { type Error = ParseErrorFor; fn validate_byte_slice(bytes: &[u8]) -> Result<(), Self::Error> { @@ -120,30 +122,11 @@ unsafe impl VarULE for VarZeroVecULE { } } -impl AsVarULE for VarZeroVec<'static, T> -where - T: AsVarULE, - T: Clone, -{ - type VarULE = VarZeroVecULE; - #[inline] - fn as_unaligned(&self) -> &VarZeroVecULE { - let slice = self.get_encoded_slice(); - unsafe { - // safety: the slice is known to come from a valid parsed VZV - VarZeroVecULE::from_byte_slice_unchecked(slice) - } - } - #[inline] - fn from_unaligned(unaligned: &VarZeroVecULE) -> Self { - unaligned.as_varzerovec().into_owned() - } -} - impl PartialEq> for VarZeroVecULE where - T: AsVarULE, - T::VarULE: PartialEq, + T: VarULE, + T: ?Sized, + T: PartialEq, { #[inline] fn eq(&self, other: &VarZeroVecULE) -> bool { @@ -153,11 +136,17 @@ where } } -impl fmt::Debug for VarZeroVecULE +impl fmt::Debug for VarZeroVecULE where - T::VarULE: fmt::Debug, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } + +impl AsRef> for VarZeroVecULE { + fn as_ref(&self) -> &VarZeroVecULE { + self + } +} diff --git a/utils/zerovec/src/yoke_impls.rs b/utils/zerovec/src/yoke_impls.rs index 2b1ce8de168..23523908f6c 100644 --- a/utils/zerovec/src/yoke_impls.rs +++ b/utils/zerovec/src/yoke_impls.rs @@ -35,7 +35,7 @@ unsafe impl<'a, T: 'static + AsULE + ?Sized> Yokeable<'a> for ZeroVec<'static, T // This impl is similar to the impl on Cow and is safe for the same reasons /// This impl can be made available by enabling the optional `yoke` feature of the `zerovec` crate -unsafe impl<'a, T: 'static + AsVarULE> Yokeable<'a> for VarZeroVec<'static, T> { +unsafe impl<'a, T: 'static + VarULE + ?Sized> Yokeable<'a> for VarZeroVec<'static, T> { type Output = VarZeroVec<'a, T>; fn transform(&'a self) -> &'a VarZeroVec<'a, T> { self @@ -62,8 +62,8 @@ unsafe impl<'a, T: 'static + AsVarULE> Yokeable<'a> for VarZeroVec<'static, T> { #[allow(clippy::transmute_ptr_to_ptr)] unsafe impl<'a, K, V> Yokeable<'a> for ZeroMap<'static, K, V> where - K: 'static + for<'b> ZeroMapKV<'b>, - V: 'static + for<'b> ZeroMapKV<'b>, + K: 'static + for<'b> ZeroMapKV<'b> + ?Sized, + V: 'static + for<'b> ZeroMapKV<'b> + ?Sized, { type Output = ZeroMap<'a, K, V>; fn transform(&'a self) -> &'a ZeroMap<'a, K, V> { @@ -105,18 +105,16 @@ impl<'a, T: 'static + AsULE + ?Sized> ZeroCopyFrom> for ZeroVec<' } } -impl<'a, T: 'static + AsVarULE + Clone> ZeroCopyFrom> for VarZeroVec<'static, T> { +impl<'a, T: 'static + VarULE + ?Sized> ZeroCopyFrom> for VarZeroVec<'static, T> { fn zero_copy_from<'b>(cart: &'b VarZeroVec<'a, T>) -> VarZeroVec<'b, T> { - // the owned variant is not compatible with the borrowed one - // clones are shallow for the borrowed variant anyway - Clone::clone(cart) + cart.as_borrowed() } } impl<'a, K, V> ZeroCopyFrom> for ZeroMap<'static, K, V> where - K: 'static + for<'b> ZeroMapKV<'b>, - V: 'static + for<'b> ZeroMapKV<'b>, + K: 'static + for<'b> ZeroMapKV<'b> + ?Sized, + V: 'static + for<'b> ZeroMapKV<'b> + ?Sized, >::Container: for<'b> ZeroCopyFrom<>::Container>, >::Container: for<'b> ZeroCopyFrom<>::Container>, >::Container: