diff --git a/components/pattern/src/frontend/zerovec.rs b/components/pattern/src/frontend/zerovec.rs index 8e7580b6fee..13903965edc 100644 --- a/components/pattern/src/frontend/zerovec.rs +++ b/components/pattern/src/frontend/zerovec.rs @@ -36,6 +36,7 @@ where /// 5. The implementation of `from_bytes_unchecked()` returns a reference to the same data. /// 6. `parse_bytes()` is equivalent to `validate_bytes()` followed by `from_bytes_unchecked()`. /// 7. `Pattern` byte equality is semantic equality. +/// 8. There are no concrete methods with the same name as VarULE trait methods. unsafe impl VarULE for Pattern where B: PatternBackend, diff --git a/components/plurals/src/provider.rs b/components/plurals/src/provider.rs index 149dd5d619a..5656fca3957 100644 --- a/components/plurals/src/provider.rs +++ b/components/plurals/src/provider.rs @@ -441,6 +441,7 @@ impl ToOwned for PluralElementsPackedULE { // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. `parse_bytes()` is equivalent to `validate_bytes()` followed by `from_bytes_unchecked()` // 7. byte equality is semantic equality +// 8. Concrete methods with the same name as VarULE trait methods have the same behavior as the trait methods. unsafe impl VarULE for PluralElementsPackedULE where V: VarULE + ?Sized, @@ -478,6 +479,7 @@ where /// /// The bytes must be valid according to [`PluralElementsPackedULE::validate_bytes`]. pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { + // *Safety:* The behavior of this function is a VarULE safety requirement! // Safety: the bytes are valid by trait invariant, and we are transparent over bytes core::mem::transmute(bytes) } diff --git a/utils/potential_utf/src/ustr.rs b/utils/potential_utf/src/ustr.rs index 7e299c1b798..eace5497ba5 100644 --- a/utils/potential_utf/src/ustr.rs +++ b/utils/potential_utf/src/ustr.rs @@ -92,6 +92,7 @@ impl PotentialUtf8 { /// Get the bytes from a [`PotentialUtf8]. #[inline] pub const fn as_bytes(&self) -> &[u8] { + // *Safety:* The behavior of this function is a VarULE safety requirement! &self.0 } @@ -177,6 +178,7 @@ impl<'a> zerovec::maps::ZeroMapKV<'a> for PotentialUtf8 { // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data (returns the argument directly) // 6. All other methods are defaulted // 7. `[T]` byte equality is semantic equality (transparent over a ULE) +// 8. Concrete methods with the same name as VarULE trait methods have the same behavior as the trait methods. /// This impl requires enabling the optional `zerovec` Cargo feature #[cfg(feature = "zerovec")] unsafe impl zerovec::ule::VarULE for PotentialUtf8 { diff --git a/utils/zerotrie/src/zerotrie.rs b/utils/zerotrie/src/zerotrie.rs index 52528687440..769093bb4d2 100644 --- a/utils/zerotrie/src/zerotrie.rs +++ b/utils/zerotrie/src/zerotrie.rs @@ -347,6 +347,7 @@ macro_rules! impl_zerotrie_subtype { /// Returns the bytes contained in the underlying store. #[inline] pub fn as_bytes(&self) -> &[u8] { + // *Safety:* The behavior of this function is a VarULE safety requirement! self.store.as_ref() } /// Returns this trie as a reference transparent over a byte slice. @@ -657,6 +658,7 @@ macro_rules! impl_zerotrie_subtype { // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. `parse_bytes()` is left to its default impl // 7. byte equality is semantic equality + // 8. Concrete methods with the same name as VarULE trait methods have the same behavior as the trait methods. #[cfg(feature = "zerovec")] unsafe impl zerovec::ule::VarULE for $name where diff --git a/utils/zerovec/src/ule/mod.rs b/utils/zerovec/src/ule/mod.rs index b5f212029d2..111bfaab1f8 100644 --- a/utils/zerovec/src/ule/mod.rs +++ b/utils/zerovec/src/ule/mod.rs @@ -270,6 +270,8 @@ where /// 6. All other methods *must* be left with their default impl, or else implemented according to /// their respective safety guidelines. /// 7. Acknowledge the following note about the equality invariant. +/// 8. If the type implements any concrete methods with the same name as the methods on VarULE, +/// they have identical behavior to the corresponding VarULE methods. /// /// If the ULE type is a struct only containing other ULE/VarULE types (or other types which satisfy invariants 1 and 2, /// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(C, packed)]` or `#[repr(transparent)]`. diff --git a/utils/zerovec/src/ule/multi.rs b/utils/zerovec/src/ule/multi.rs index 26e4ca498e5..72c3936cd7f 100644 --- a/utils/zerovec/src/ule/multi.rs +++ b/utils/zerovec/src/ule/multi.rs @@ -95,12 +95,14 @@ impl MultiFieldsULE { /// - byte slice must be a valid VarZeroLengthlessSlice<[u8], Format> with length LEN #[inline] pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { + // *Safety:* The behavior of this function is a VarULE safety requirement! // &Self is transparent over &VZS<..> with the right format mem::transmute(>::from_bytes_unchecked(bytes)) } /// Get the bytes behind this value pub fn as_bytes(&self) -> &[u8] { + // *Safety:* The behavior of this function is a VarULE safety requirement! self.0.as_bytes() } } @@ -141,6 +143,7 @@ unsafe impl EncodeAsVarULE<[u8]> for BlankSliceEncoder { // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. All other methods are defaulted // 7. `MultiFieldsULE` byte equality is semantic equality (achieved by being transparent over a VarULE type) +// 8. Concrete methods with the same name as VarULE trait methods have the same behavior as the trait methods. unsafe impl VarULE for MultiFieldsULE { /// Note: MultiFieldsULE is usually used in cases where one should be calling .validate_field() directly for /// each field, rather than using the regular VarULE impl. diff --git a/utils/zerovec/src/ule/option.rs b/utils/zerovec/src/ule/option.rs index 353e4418158..1a06e5a7711 100644 --- a/utils/zerovec/src/ule/option.rs +++ b/utils/zerovec/src/ule/option.rs @@ -173,6 +173,7 @@ impl core::fmt::Debug for OptionVarULE // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. All other methods are defaulted // 7. OptionVarULE byte equality is semantic equality (achieved by being an aggregate) +// 8. There are no concrete methods with the same name as VarULE trait methods. unsafe impl VarULE for OptionVarULE { #[inline] fn validate_bytes(slice: &[u8]) -> Result<(), UleError> { diff --git a/utils/zerovec/src/ule/slices.rs b/utils/zerovec/src/ule/slices.rs index ace212a4e81..3475a4883a4 100644 --- a/utils/zerovec/src/ule/slices.rs +++ b/utils/zerovec/src/ule/slices.rs @@ -41,6 +41,8 @@ unsafe impl EqULE for [T; N] {} // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. `parse_bytes()` is equivalent to `validate_bytes()` followed by `from_bytes_unchecked()` // 7. str byte equality is semantic equality +// 8. The only function on `str` with the same name as a VarULE trait method is `as_bytes()`, +// and the VarULE method is implemented on top of the concrete function. unsafe impl VarULE for str { #[inline] fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> { @@ -58,6 +60,12 @@ unsafe impl VarULE for str { unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { core::str::from_utf8_unchecked(bytes) } + #[inline] + fn as_bytes(&self) -> &[u8] { + // Safety: str as_bytes() casts the incoming pointer. + // *Safety:* The behavior of this function is a VarULE safety requirement! + self.as_bytes() + } } /// Note: VarULE is well-defined for all `[T]` where `T: ULE`, but [`ZeroSlice`] is more ergonomic @@ -86,6 +94,10 @@ unsafe impl VarULE for str { // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. All other methods are defaulted // 7. `[T]` byte equality is semantic equality (achieved by being a slice of a ULE type) +// 8. There are no methods generically on [T] that have the same name as the VarULE functions. +// However, there are some functions on specific [T] that have the same name: +// - [AsciiChar]::as_bytes() has the correct behavior. +// - [MaybeUninit]::as_bytes() has the correct behavior, though the return value is different. unsafe impl VarULE for [T] where T: ULE, diff --git a/utils/zerovec/src/ule/tuplevar.rs b/utils/zerovec/src/ule/tuplevar.rs index f0c7fd40be9..bb42c5a9938 100644 --- a/utils/zerovec/src/ule/tuplevar.rs +++ b/utils/zerovec/src/ule/tuplevar.rs @@ -67,6 +67,7 @@ macro_rules! tuple_varule { // 5. `from_bytes_unchecked` returns a fat pointer to the bytes. // 6. All other methods are left at their default impl. // 7. The inner ULEs have byte equality, so this composition has byte equality. + // 8. There are no concrete methods with the same name as VarULE trait methods. unsafe impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> VarULE for $name<$($T,)+ Format> { fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> { diff --git a/utils/zerovec/src/ule/vartuple.rs b/utils/zerovec/src/ule/vartuple.rs index 7b05d3096a3..f7c6c0cba02 100644 --- a/utils/zerovec/src/ule/vartuple.rs +++ b/utils/zerovec/src/ule/vartuple.rs @@ -103,6 +103,7 @@ pub struct VarTupleULE { // 5. `from_bytes_unchecked` returns a fat pointer to the bytes. // 6. All other methods are left at their default impl. // 7. The two ULEs have byte equality, so this composition has byte equality. +// 8. There are no concrete methods with the same name as VarULE trait methods. unsafe impl VarULE for VarTupleULE where A: AsULE + 'static, diff --git a/utils/zerovec/src/varzerovec/slice.rs b/utils/zerovec/src/varzerovec/slice.rs index fc6dfb287b6..0e44d0b2c07 100644 --- a/utils/zerovec/src/varzerovec/slice.rs +++ b/utils/zerovec/src/varzerovec/slice.rs @@ -125,6 +125,7 @@ impl VarZeroSlice { /// /// `bytes` need to be an output from [`VarZeroSlice::as_bytes()`]. pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { + // *Safety:* The behavior of this function is a VarULE safety requirement! // self is really just a wrapper around a byte slice mem::transmute(bytes) } @@ -254,6 +255,7 @@ impl VarZeroSlice { /// ``` #[inline] pub const fn as_bytes(&self) -> &[u8] { + // *Safety:* The behavior of this function is a VarULE safety requirement! &self.entire_slice } @@ -269,6 +271,7 @@ impl VarZeroSlice { /// /// Slices of the right format can be obtained via [`VarZeroSlice::as_bytes()`] pub fn parse_bytes<'a>(slice: &'a [u8]) -> Result<&'a Self, UleError> { + // *Safety:* The behavior of this function is a VarULE safety requirement! ::parse_bytes(slice) } } @@ -441,6 +444,7 @@ where // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. `as_bytes()` is equivalent to a regular transmute of the underlying data // 7. VarZeroSlice byte equality is semantic equality (relying on the guideline of the underlying VarULE type) +// 8. Concrete methods with the same name as VarULE trait methods have the same behavior as the trait methods. unsafe impl VarULE for VarZeroSlice { fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> { let _: VarZeroVecComponents = diff --git a/utils/zerovec/src/zerovec/slice.rs b/utils/zerovec/src/zerovec/slice.rs index 31c8d58b341..735816de72a 100644 --- a/utils/zerovec/src/zerovec/slice.rs +++ b/utils/zerovec/src/zerovec/slice.rs @@ -56,6 +56,7 @@ where /// Attempt to construct a `&ZeroSlice` from a byte slice, returning an error /// if it's not a valid byte sequence pub fn parse_bytes(bytes: &[u8]) -> Result<&Self, UleError> { + // *Safety:* The behavior of this function is a VarULE safety requirement! T::ULE::parse_bytes_to_slice(bytes).map(Self::from_ule_slice) } @@ -65,6 +66,7 @@ where /// /// `bytes` need to be an output from [`ZeroSlice::as_bytes()`]. pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { + // *Safety:* The behavior of this function is a VarULE safety requirement! // &[u8] and &[T::ULE] are the same slice with different length metadata. Self::from_ule_slice(core::slice::from_raw_parts( bytes.as_ptr() as *const T::ULE, @@ -115,6 +117,7 @@ where /// ``` #[inline] pub fn as_bytes(&self) -> &[u8] { + // *Safety:* The behavior of this function is a VarULE safety requirement! T::ULE::slice_as_bytes(self.as_ule_slice()) } @@ -498,6 +501,7 @@ where // 5. The impl of `from_bytes_unchecked()` returns a reference to the same data. // 6. `as_bytes()` and `parse_bytes()` are defaulted // 7. `[T::ULE]` byte equality is semantic equality (relying on the guideline of the underlying `ULE` type) +// 8. Concrete methods with the same name as VarULE trait methods have the same behavior as the trait methods. unsafe impl VarULE for ZeroSlice { #[inline] fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {