Skip to content

Commit

Permalink
[pointer] Support Box and Arc
Browse files Browse the repository at this point in the history
gherrit-pr-id: I7fe90063e148d89e2f75b6fa63a960ad8b1dd432
  • Loading branch information
joshlf committed Oct 18, 2024
1 parent de22597 commit 869ca81
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 71 deletions.
8 changes: 4 additions & 4 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
}

#[inline]
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool {
fn is_bit_valid<A: invariant::ReadFoo>(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 @@ -1124,15 +1124,15 @@ mod tests {

pub(super) trait TestIsBitValidShared<T: ?Sized> {
#[allow(clippy::needless_lifetimes)]
fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>(
fn test_is_bit_valid_shared<'ptr, A: invariant::ReadFoo>(
&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::Reference>(
fn test_is_bit_valid_shared<'ptr, A: invariant::ReadFoo>(
&self,
candidate: Maybe<'ptr, T, A>,
) -> Option<bool> {
Expand Down Expand Up @@ -1222,7 +1222,7 @@ mod tests {
#[allow(unused, non_local_definitions)]
impl AutorefWrapper<$ty> {
#[allow(clippy::needless_lifetimes)]
fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>(
fn test_is_bit_valid_shared<'ptr, A: invariant::ReadFoo>(
&mut self,
candidate: Maybe<'ptr, $ty, A>,
) -> Option<bool> {
Expand Down
28 changes: 18 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1320,7 +1320,7 @@ pub unsafe trait TryFromBytes {
/// [`UnsafeCell`]: core::cell::UnsafeCell
/// [`Shared`]: invariant::Shared
#[doc(hidden)]
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool;
fn is_bit_valid<A: invariant::ReadFoo>(candidate: Maybe<'_, Self, A>) -> bool;

/// Attempts to interpret the given `source` as a `&Self`.
///
Expand Down Expand Up @@ -3458,10 +3458,22 @@ pub unsafe trait FromBytes: FromZeros {
where
Self: KnownLayout + Immutable,
{
static_assert_dst_is_not_zst!(Self);
match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) {
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()),
Err(err) => Err(err.map_src(|src| src.as_ref())),
Self::from_bytes(source)
}

#[must_use = "has no side effects"]
#[inline]
fn from_bytes<'a, P: pointer::Pointer<'a, Self>, R>(
source: P::To<'a, [u8]>,
) -> Result<P, CastError<P::To<'a, [u8]>, Self>>
where
Self: 'a + KnownLayout + invariant::Read<P::Aliasing, R>,
{
match Ptr::<'_, _, (P::Aliasing, _, _)>::from_pointer(source)
.try_cast_into_no_leftover::<_, R>(None)
{
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().into_pointer()),
Err(err) => Err(err.map_src(|src| src.into_pointer())),
}
}

Expand Down Expand Up @@ -3694,11 +3706,7 @@ pub unsafe trait FromBytes: FromZeros {
where
Self: IntoBytes + KnownLayout,
{
static_assert_dst_is_not_zst!(Self);
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()),
Err(err) => Err(err.map_src(|src| src.as_mut())),
}
Self::from_bytes(source)
}

/// Interprets the prefix of the given `source` as a `&mut Self` without
Expand Down
3 changes: 2 additions & 1 deletion src/pointer/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ mod _def {
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
///
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
pub(crate) struct PtrInner<'a, T>
#[allow(missing_debug_implementations)]
pub struct PtrInner<'a, T>
where
T: ?Sized,
{
Expand Down
138 changes: 102 additions & 36 deletions src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`])
//! triples implementing the [`Invariants`] trait.
use super::*;

/// The invariants of a [`Ptr`][super::Ptr].
pub trait Invariants: Sealed {
type Aliasing: Aliasing;
Expand Down Expand Up @@ -82,6 +80,15 @@ pub trait Aliasing:
/// Aliasing>::Variance<'a, T>` to inherit this variance.
#[doc(hidden)]
type Variance<'a, T: 'a + ?Sized>;

// #[doc(hidden)]
// type Applied<'a, T: 'a + ?Sized>;

// #[doc(hidden)]
// fn into_ptr<'a, T: 'a + ?Sized>(ptr: Self::Applied<'a, T>) -> PtrInner<'a, T>;

// #[doc(hidden)]
// unsafe fn from_ptr<'a, T: 'a + ?Sized>(ptr: PtrInner<'a, T>) -> Self::Applied<'a, T>;
}

#[doc(hidden)]
Expand Down Expand Up @@ -136,14 +143,7 @@ impl<
///
/// Given `A: Reference`, callers may assume that either `A = Shared` or `A =
/// Exclusive`.
pub trait Reference: Aliasing + Sealed {
fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, shared: S, exclusive: E) -> O
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Self>,
S: FnOnce(Ptr<'a, T, I::WithAliasing<Shared>>) -> O,
E: FnOnce(Ptr<'a, T, I::WithAliasing<Exclusive>>) -> O;
}
pub trait Reference: ReadFoo + Sealed {}

/// It is unknown whether any invariant holds.
pub enum Unknown {}
Expand Down Expand Up @@ -189,18 +189,7 @@ impl Aliasing for Shared {
const IS_EXCLUSIVE: bool = false;
type Variance<'a, T: 'a + ?Sized> = &'a T;
}
impl Reference for Shared {
#[inline(always)]
fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, shared: S, _exclusive: E) -> O
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Shared>,
S: FnOnce(Ptr<'a, T, I::WithAliasing<Shared>>) -> O,
E: FnOnce(Ptr<'a, T, I::WithAliasing<Exclusive>>) -> O,
{
shared(ptr.unify_invariants())
}
}
impl Reference for Shared {}

/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`.
///
Expand All @@ -215,16 +204,41 @@ impl Aliasing for Exclusive {
const IS_EXCLUSIVE: bool = true;
type Variance<'a, T: 'a + ?Sized> = &'a mut T;
}
impl Reference for Exclusive {
#[inline(always)]
fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, _shared: S, exclusive: E) -> O
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Exclusive>,
S: FnOnce(Ptr<'a, T, I::WithAliasing<Shared>>) -> O,
E: FnOnce(Ptr<'a, T, I::WithAliasing<Exclusive>>) -> O,
{
exclusive(ptr.unify_invariants())
impl Reference for Exclusive {}

#[cfg(feature = "alloc")]
pub use _alloc::*;
#[cfg(feature = "alloc")]
mod _alloc {
use alloc::boxed::Box as Bx;

use super::*;

pub enum Box {}
impl AliasingInner for Box {
// type MappedTo<M: AliasingMapping> = M::FromBox;
}
impl Aliasing for Box {
const IS_EXCLUSIVE: bool = true;
type Variance<'a, T: 'a + ?Sized> = Bx<T>;
}
}

#[cfg(feature = "std")]
pub use _std::*;
#[cfg(feature = "std")]
mod _std {
use std::sync::Arc as Ac;

use super::*;

pub enum Arc {}
impl AliasingInner for Arc {
// type MappedTo<M: AliasingMapping> = M::FromArc;
}
impl Aliasing for Arc {
const IS_EXCLUSIVE: bool = true;
type Variance<'a, T: 'a + ?Sized> = Ac<T>;
}
}

Expand Down Expand Up @@ -279,6 +293,27 @@ impl ValidityInner for Valid {
type MappedTo<M: ValidityMapping> = M::FromValid;
}

// Aliasing modes that permit reading at all (ie, everything but Inaccessible).
pub trait ReadFoo: Aliasing {}
impl ReadFoo for Shared {}
impl ReadFoo for Exclusive {}
#[cfg(feature = "alloc")]
impl ReadFoo for Box {}
#[cfg(feature = "std")]
impl ReadFoo for Arc {}

// Shared, Arc, etc
pub trait SharedFoo: Aliasing {}
impl SharedFoo for Shared {}
#[cfg(feature = "std")]
impl SharedFoo for Arc {}

// Exclusive, Box, etc
pub trait ExclusiveFoo: Aliasing {}
impl ExclusiveFoo for Exclusive {}
#[cfg(feature = "alloc")]
impl ExclusiveFoo for Box {}

/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
///
/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
Expand All @@ -303,8 +338,7 @@ define_because!(
#[doc(hidden)]
pub BecauseExclusive
);
// SAFETY: The aliasing parameter is `Exclusive`.
unsafe impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
unsafe impl<A: ExclusiveFoo, T: ?Sized> Read<A, BecauseExclusive> for T {}

define_because!(
/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s
Expand All @@ -313,7 +347,7 @@ define_because!(
pub BecauseImmutable
);
// SAFETY: `T: Immutable`.
unsafe impl<A: Reference, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
unsafe impl<A: ReadFoo, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}

use sealed::Sealed;
mod sealed {
Expand All @@ -326,6 +360,10 @@ mod sealed {
// impl Sealed for Inaccessible {}
impl Sealed for Shared {}
impl Sealed for Exclusive {}
#[cfg(feature = "alloc")]
impl Sealed for Box {}
#[cfg(feature = "std")]
impl Sealed for Arc {}

impl Sealed for Aligned {}

Expand Down Expand Up @@ -386,6 +424,10 @@ mod mapping {
// type FromInaccessible: Aliasing;
type FromShared: Aliasing;
type FromExclusive: Aliasing;
#[cfg(feature = "alloc")]
type FromBox: Aliasing;
#[cfg(feature = "std")]
type FromArc: Aliasing;
}

/// A mapping from one [`Alignment`] type to another.
Expand Down Expand Up @@ -454,38 +496,62 @@ mod mapping {
// // type FromInaccessible = FromInaccessible;
// type FromShared = FromShared;
// type FromExclusive = FromExclusive;
// #[cfg(feature = "alloc")]
// type FromBox = Inaccessible;
// #[cfg(feature = "std")]
// type FromArc = Inaccessible;
// }

// impl AliasingMapping for Inaccessible {
// type FromInaccessible = Inaccessible;
// type FromShared = Inaccessible;
// type FromExclusive = Inaccessible;
// #[cfg(feature = "alloc")]
// type FromBox = Inaccessible;
// #[cfg(feature = "std")]
// type FromArc = Inaccessible;
// }

// pub enum UnsafeCellMismatch {}

// impl AliasingMapping for UnsafeCellMismatch {
// // type FromInaccessible = Inaccessible;
// type FromInaccessible = Inaccessible;
// type FromShared = Inaccessible;
// type FromExclusive = Exclusive;
// #[cfg(feature = "alloc")]
// type FromBox = Box;
// #[cfg(feature = "std")]
// type FromArc = Inaccessible;
// }

// impl AliasingMapping for Preserved {
// // type FromInaccessible = Inaccessible;
// type FromShared = Shared;
// type FromExclusive = Exclusive;
// #[cfg(feature = "alloc")]
// type FromBox = Box;
// #[cfg(feature = "std")]
// type FromArc = Arc;
// }

// impl AliasingMapping for Shared {
// // type FromInaccessible = Shared;
// type FromShared = Shared;
// type FromExclusive = Shared;
// #[cfg(feature = "alloc")]
// type FromBox = Shared;
// #[cfg(feature = "std")]
// type FromArc = Shared;
// }

// impl AliasingMapping for Exclusive {
// // type FromInaccessible = Exclusive;
// type FromShared = Exclusive;
// type FromExclusive = Exclusive;
// #[cfg(feature = "alloc")]
// type FromBox = Exclusive;
// #[cfg(feature = "std")]
// type FromArc = Exclusive;
// }

impl<FromUnknown: Alignment, FromAligned: Alignment> AlignmentMapping
Expand Down
Loading

0 comments on commit 869ca81

Please sign in to comment.