diff --git a/utils/zerovec/src/varzerovec/mod.rs b/utils/zerovec/src/varzerovec/mod.rs index 151dfd010ae..9d5b68eae50 100644 --- a/utils/zerovec/src/varzerovec/mod.rs +++ b/utils/zerovec/src/varzerovec/mod.rs @@ -102,6 +102,10 @@ pub use ule::VarZeroVecULE; /// # Ok::<(), VarZeroVecError>(()) /// ``` /// +/// +/// [`VarZeroVec`]s can be nested infinitely, see the docs of [`VarZeroVecULE`] +/// for more information. +/// /// [`ule`]: crate::ule #[derive(Clone)] pub struct VarZeroVec<'a, T>(VarZeroVecInner<'a, T>); @@ -232,7 +236,8 @@ 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 /// @@ -396,8 +401,10 @@ impl<'a, T: AsVarULE> VarZeroVec<'a, T> { self.get_components().to_vec() } - /// If this is borrowed, get the borrowed slice - pub(crate) fn get_encoded_slice(&self) -> &[u8] { + /// Obtain the internal encoded slice + /// + /// This can be passed back to [`Self::try_from_bytes()`] + pub fn get_encoded_slice(&self) -> &[u8] { self.get_components().entire_slice() } diff --git a/utils/zerovec/src/varzerovec/ule.rs b/utils/zerovec/src/varzerovec/ule.rs index 257870e5f86..8f141144076 100644 --- a/utils/zerovec/src/varzerovec/ule.rs +++ b/utils/zerovec/src/varzerovec/ule.rs @@ -7,6 +7,40 @@ use super::*; use core::marker::PhantomData; use core::mem; +/// A VarULE version of VarZeroVec allowing for VarZeroVecs to be nested indefinitely +/// +/// ```rust +/// use zerovec::VarZeroVec; +/// use zerovec::ZeroVec; +/// use zerovec::varzerovec::VarZeroVecULE; +/// use zerovec::ule::*; +/// let strings_1: Vec = vec!["foo".into(), "bar".into(), "baz".into()]; +/// let strings_2: Vec = vec!["twelve".into(), "seventeen".into(), "forty two".into()]; +/// let strings_3: Vec = vec!["我".into(), "喜歡".into(), "烏龍茶".into()]; +/// let strings_4: Vec = vec!["w".into(), "ω".into(), "文".into(), "𑄃".into()]; +/// let strings_12 = vec![strings_1.clone(), strings_2.clone()]; +/// 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 reconstructed = vzv_all.iter() +/// .map(|v: &VarZeroVecULE<_>| { +/// v.iter().map(|x: &VarZeroVecULE<_>| x.as_varzerovec().to_vec()).collect::>() +/// }).collect::>(); +/// assert_eq!(reconstructed, all_strings); +/// +/// let bytes = vzv_all.get_encoded_slice(); +/// let vzv_from_bytes: VarZeroVec>> = VarZeroVec::try_from_bytes(bytes).unwrap(); +/// assert_eq!(vzv_from_bytes, vzv_all); +/// ``` +// // safety invariant: The slice MUST be one which parses to // a valid SliceComponents #[repr(transparent)] @@ -104,3 +138,24 @@ where unaligned.as_varzerovec().into_owned() } } + +impl PartialEq> for VarZeroVecULE +where + T: AsVarULE, + T::VarULE: PartialEq, +{ + #[inline] + fn eq(&self, other: &VarZeroVecULE) -> bool { + // Note: T implements PartialEq but not T::ULE + self.iter().eq(other.iter()) + } +} + +impl fmt::Debug for VarZeroVecULE +where + T::VarULE: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +}