Skip to content

Commit

Permalink
[pointer] Make "at least" machinery generic (#1166)
Browse files Browse the repository at this point in the history
This replaces `at_least::Xxx` with `AtLeast<Xxx>`, which in turn allows
us to write `AtLeast<T>` in a context where `T` is generic.

The use case in this commit is to relax the bound on `Copy` and `Clone`
to:

  Shared: AtLeast<I::Aliasing>

...which is equivalent to saying that `I::Aliasing` is at *most*
`Shared`. This permits both `Shared` and `Any` `Ptr`s to be copied or
cloned.

Co-authored-by: Jack Wrenn <[email protected]>
  • Loading branch information
joshlf and jswrenn authored May 2, 2024
1 parent 0fc6df9 commit 6209d6e
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 168 deletions.
20 changes: 15 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,9 @@ pub unsafe trait TryFromBytes {
/// [`UnsafeCell`]: core::cell::UnsafeCell
/// [`Shared`]: invariant::Shared
#[doc(hidden)]
fn is_bit_valid<A: invariant::at_least::Shared>(candidate: Maybe<'_, Self, A>) -> bool;
fn is_bit_valid<A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(
candidate: Maybe<'_, Self, A>,
) -> bool;

/// Attempts to interpret a byte slice as a `Self`.
///
Expand Down Expand Up @@ -3768,7 +3770,9 @@ unsafe impl<T: TryFromBytes> TryFromBytes for UnsafeCell<T> {
}

#[inline]
fn is_bit_valid<A: invariant::at_least::Shared>(candidate: Maybe<'_, Self, A>) -> bool {
fn is_bit_valid<A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(
candidate: Maybe<'_, Self, A>,
) -> bool {
// The only way to implement this function is using an exclusive-aliased
// pointer. `UnsafeCell`s cannot be read via shared-aliased pointers
// (other than by using `unsafe` code, which we can't use since we can't
Expand Down Expand Up @@ -7954,15 +7958,21 @@ mod tests {

pub(super) trait TestIsBitValidShared<T: ?Sized> {
#[allow(clippy::needless_lifetimes)]
fn test_is_bit_valid_shared<'ptr, A: invariant::at_least::Shared>(
fn test_is_bit_valid_shared<
'ptr,
A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>,
>(
&self,
candidate: Maybe<'ptr, T, A>,
) -> Option<bool>;
}

impl<T: TryFromBytes + Immutable + ?Sized> TestIsBitValidShared<T> for AutorefWrapper<T> {
#[allow(clippy::needless_lifetimes)]
fn test_is_bit_valid_shared<'ptr, A: invariant::at_least::Shared>(
fn test_is_bit_valid_shared<
'ptr,
A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>,
>(
&self,
candidate: Maybe<'ptr, T, A>,
) -> Option<bool> {
Expand Down Expand Up @@ -8066,7 +8076,7 @@ mod tests {
#[allow(unused, non_local_definitions)]
impl AutorefWrapper<$ty> {
#[allow(clippy::needless_lifetimes)]
fn test_is_bit_valid_shared<'ptr, A: invariant::at_least::Shared>(
fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(
&mut self,
candidate: Maybe<'ptr, $ty, A>,
) -> Option<bool> {
Expand Down
8 changes: 4 additions & 4 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ macro_rules! unsafe_impl {
fn only_derive_is_allowed_to_implement_this_trait() {}

#[inline]
fn is_bit_valid<AA: invariant::at_least::Shared>(candidate: Maybe<'_, Self, AA>) -> bool {
fn is_bit_valid<AA: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(candidate: Maybe<'_, Self, AA>) -> bool {
// SAFETY:
// - The argument to `cast_unsized` is `|p| p as *mut _` as required
// by that method's safety precondition.
Expand All @@ -162,7 +162,7 @@ macro_rules! unsafe_impl {
fn only_derive_is_allowed_to_implement_this_trait() {}

#[inline]
fn is_bit_valid<AA: invariant::at_least::Shared>(candidate: Maybe<'_, Self, AA>) -> bool {
fn is_bit_valid<AA: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(candidate: Maybe<'_, Self, AA>) -> bool {
// SAFETY:
// - The argument to `cast_unsized` is `|p| p as *mut _` as required
// by that method's safety precondition.
Expand All @@ -184,7 +184,7 @@ macro_rules! unsafe_impl {
(@method TryFromBytes) => {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)] fn is_bit_valid<A: invariant::at_least::Shared>(_: Maybe<'_, Self, A>) -> bool { true }
#[inline(always)] fn is_bit_valid<A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(_: Maybe<'_, Self, A>) -> bool { true }
};
(@method $trait:ident) => {
#[allow(clippy::missing_inline_in_public_items)]
Expand Down Expand Up @@ -357,7 +357,7 @@ macro_rules! impl_for_transparent_wrapper {
// TryFromBytes)` macro arm for an explanation of why this is a sound
// implementation of `is_bit_valid`.
#[inline]
fn is_bit_valid<A: crate::pointer::invariant::at_least::Shared>(candidate: Maybe<'_, Self, A>) -> bool {
fn is_bit_valid<A: crate::pointer::invariant::Aliasing + crate::pointer::invariant::AtLeast<invariant::Shared>>(candidate: Maybe<'_, Self, A>) -> bool {
TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner())
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant
impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment>
where
T: 'a + ?Sized,
Aliasing: invariant::at_least::Shared,
Aliasing: invariant::Aliasing + invariant::AtLeast<invariant::Shared>,
Alignment: invariant::Alignment,
{
/// Reads the value from `MaybeAligned`.
Expand Down Expand Up @@ -68,7 +68,7 @@ pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
where
T: crate::Immutable,
I: invariant::Invariants<Validity = invariant::Initialized>,
I::Aliasing: invariant::at_least::Shared,
I::Aliasing: invariant::AtLeast<invariant::Shared>,
{
ptr.as_bytes().as_ref().iter().all(|&byte| byte == 0)
}
Loading

0 comments on commit 6209d6e

Please sign in to comment.