Skip to content

Commit 6af1036

Browse files
committed
[pointer] Support Box and Arc
gherrit-pr-id: I7fe90063e148d89e2f75b6fa63a960ad8b1dd432
1 parent 1bee133 commit 6af1036

File tree

6 files changed

+193
-17
lines changed

6 files changed

+193
-17
lines changed

src/impls.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
648648
}
649649

650650
#[inline]
651-
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool {
651+
fn is_bit_valid<A: invariant::Aliasing>(candidate: Maybe<'_, Self, A>) -> bool {
652652
// The only way to implement this function is using an exclusive-aliased
653653
// pointer. `UnsafeCell`s cannot be read via shared-aliased pointers
654654
// (other than by using `unsafe` code, which we can't use since we can't
@@ -1124,15 +1124,15 @@ mod tests {
11241124

11251125
pub(super) trait TestIsBitValidShared<T: ?Sized> {
11261126
#[allow(clippy::needless_lifetimes)]
1127-
fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>(
1127+
fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing>(
11281128
&self,
11291129
candidate: Maybe<'ptr, T, A>,
11301130
) -> Option<bool>;
11311131
}
11321132

11331133
impl<T: TryFromBytes + Immutable + ?Sized> TestIsBitValidShared<T> for AutorefWrapper<T> {
11341134
#[allow(clippy::needless_lifetimes)]
1135-
fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>(
1135+
fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing>(
11361136
&self,
11371137
candidate: Maybe<'ptr, T, A>,
11381138
) -> Option<bool> {
@@ -1222,7 +1222,7 @@ mod tests {
12221222
#[allow(unused, non_local_definitions)]
12231223
impl AutorefWrapper<$ty> {
12241224
#[allow(clippy::needless_lifetimes)]
1225-
fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>(
1225+
fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing>(
12261226
&mut self,
12271227
candidate: Maybe<'ptr, $ty, A>,
12281228
) -> Option<bool> {

src/lib.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3458,10 +3458,22 @@ pub unsafe trait FromBytes: FromZeros {
34583458
where
34593459
Self: KnownLayout + Immutable,
34603460
{
3461-
static_assert_dst_is_not_zst!(Self);
3462-
match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) {
3463-
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()),
3464-
Err(err) => Err(err.map_src(|src| src.as_ref())),
3461+
Self::from_bytes(source)
3462+
}
3463+
3464+
#[must_use = "has no side effects"]
3465+
#[inline]
3466+
fn from_bytes<'a, P: pointer::Pointer<'a, Self>, R>(
3467+
source: P::To<'a, [u8]>,
3468+
) -> Result<P, CastError<P::To<'a, [u8]>, Self>>
3469+
where
3470+
Self: 'a + KnownLayout + invariant::Read<P::Aliasing, R>,
3471+
{
3472+
match Ptr::<'_, _, (P::Aliasing, _, _)>::from_pointer(source)
3473+
.try_cast_into_no_leftover::<_, R>(None)
3474+
{
3475+
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().into_pointer()),
3476+
Err(err) => Err(err.map_src(|src| src.into_pointer())),
34653477
}
34663478
}
34673479

@@ -3694,11 +3706,7 @@ pub unsafe trait FromBytes: FromZeros {
36943706
where
36953707
Self: IntoBytes + KnownLayout,
36963708
{
3697-
static_assert_dst_is_not_zst!(Self);
3698-
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
3699-
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()),
3700-
Err(err) => Err(err.map_src(|src| src.as_mut())),
3701-
}
3709+
Self::from_bytes(source)
37023710
}
37033711

37043712
/// Interprets the prefix of the given `source` as a `&mut Self` without

src/pointer/inner.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ mod _def {
2525
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
2626
///
2727
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
28-
pub(crate) struct PtrInner<'a, T>
28+
#[allow(missing_debug_implementations)]
29+
pub struct PtrInner<'a, T>
2930
where
3031
T: ?Sized,
3132
{

src/pointer/invariant.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ pub trait Aliasing: Sealed {
6868
/// Aliasing>::Variance<'a, T>` to inherit this variance.
6969
#[doc(hidden)]
7070
type Variance<'a, T: 'a + ?Sized>;
71+
72+
// #[doc(hidden)]
73+
// type Applied<'a, T: 'a + ?Sized>;
74+
75+
// #[doc(hidden)]
76+
// fn into_ptr<'a, T: 'a + ?Sized>(ptr: Self::Applied<'a, T>) -> PtrInner<'a, T>;
77+
78+
// #[doc(hidden)]
79+
// unsafe fn from_ptr<'a, T: 'a + ?Sized>(ptr: PtrInner<'a, T>) -> Self::Applied<'a, T>;
7180
}
7281

7382
// NOTE: The `AlignmentInner`/`Alignment` distinction is required so that we can
@@ -165,6 +174,34 @@ impl Aliasing for Exclusive {
165174
}
166175
impl Reference for Exclusive {}
167176

177+
#[cfg(feature = "alloc")]
178+
mod _alloc {
179+
use alloc::boxed::Box as Bx;
180+
181+
use super::*;
182+
183+
pub enum Box {}
184+
impl Aliasing for Box {
185+
const IS_EXCLUSIVE: bool = false;
186+
type Variance<'a, T: 'a + ?Sized> = Bx<T>;
187+
}
188+
}
189+
190+
#[cfg(feature = "std")]
191+
pub use _std::*;
192+
#[cfg(feature = "std")]
193+
mod _std {
194+
use std::sync::Arc as Ac;
195+
196+
use super::*;
197+
198+
pub enum Arc {}
199+
impl Aliasing for Arc {
200+
const IS_EXCLUSIVE: bool = false;
201+
type Variance<'a, T: 'a + ?Sized> = Ac<T>;
202+
}
203+
}
204+
168205
/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
169206
/// of the `T`'s alignment.
170207
pub enum Aligned {}
@@ -216,6 +253,18 @@ impl ValidityInner for Valid {
216253
type MappedTo<M: ValidityMapping> = M::FromValid;
217254
}
218255

256+
// Shared, Arc, etc
257+
pub trait SharedFoo: Aliasing {}
258+
impl SharedFoo for Shared {}
259+
#[cfg(feature = "std")]
260+
impl SharedFoo for Arc {}
261+
262+
// Exclusive, Box, etc
263+
pub trait ExclusiveFoo: Aliasing {}
264+
impl ExclusiveFoo for Exclusive {}
265+
#[cfg(feature = "alloc")]
266+
impl ExclusiveFoo for Box {}
267+
219268
/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
220269
///
221270
/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
@@ -240,8 +289,7 @@ define_because!(
240289
#[doc(hidden)]
241290
pub BecauseExclusive
242291
);
243-
// SAFETY: The aliasing parameter is `Exclusive`.
244-
unsafe impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
292+
unsafe impl<A: ExclusiveFoo, T: ?Sized> Read<A, BecauseExclusive> for T {}
245293

246294
define_because!(
247295
/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s
@@ -262,6 +310,10 @@ mod sealed {
262310

263311
impl Sealed for Shared {}
264312
impl Sealed for Exclusive {}
313+
#[cfg(feature = "alloc")]
314+
impl Sealed for Box {}
315+
#[cfg(feature = "std")]
316+
impl Sealed for Arc {}
265317

266318
impl Sealed for Aligned {}
267319

src/pointer/mod.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,92 @@ where
8686
{
8787
ptr.as_bytes::<BecauseImmutable>().as_ref().iter().all(|&byte| byte == 0)
8888
}
89+
90+
pub use _pointer::*;
91+
mod _pointer {
92+
#[cfg(feature = "alloc")]
93+
use alloc::boxed::Box;
94+
#[cfg(feature = "std")]
95+
use std::sync::Arc;
96+
97+
use super::{inner::PtrInner, invariant::*};
98+
99+
pub unsafe trait Pointer<'t, T: ?Sized> {
100+
type To<'u, U: 'u + ?Sized>: Pointer<'u, U, Aliasing = Self::Aliasing>;
101+
102+
#[doc(hidden)]
103+
type Aliasing: Aliasing;
104+
105+
#[doc(hidden)]
106+
fn into_ptr(self) -> PtrInner<'t, T>;
107+
108+
#[doc(hidden)]
109+
unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Self;
110+
}
111+
112+
unsafe impl<'t, T: ?Sized> Pointer<'t, T> for &'t T {
113+
type To<'u, U: 'u + ?Sized> = &'u U;
114+
115+
type Aliasing = Shared;
116+
117+
#[inline(always)]
118+
fn into_ptr(self) -> PtrInner<'t, T> {
119+
PtrInner::from_ref(self)
120+
}
121+
122+
#[inline(always)]
123+
unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Self {
124+
unsafe { ptr.as_non_null().as_ref() }
125+
}
126+
}
127+
128+
unsafe impl<'t, T: ?Sized> Pointer<'t, T> for &'t mut T {
129+
type To<'u, U: 'u + ?Sized> = &'u mut U;
130+
131+
type Aliasing = Exclusive;
132+
133+
#[inline(always)]
134+
fn into_ptr(self) -> PtrInner<'t, T> {
135+
PtrInner::from_ref(self)
136+
}
137+
138+
#[inline(always)]
139+
unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Self {
140+
unsafe { ptr.as_non_null().as_mut() }
141+
}
142+
}
143+
144+
#[cfg(feature = "alloc")]
145+
unsafe impl<'t, T: ?Sized> Pointer<'t, T> for Box<T> {
146+
type To<'u, U: 'u + ?Sized> = Box<U>;
147+
148+
type Aliasing = super::invariant::Box;
149+
150+
#[inline(always)]
151+
fn into_ptr(self) -> PtrInner<'t, T> {
152+
PtrInner::from_box(self)
153+
}
154+
155+
#[inline(always)]
156+
unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Box<T> {
157+
unsafe { Box::from_raw(ptr.as_non_null().as_ptr()) }
158+
}
159+
}
160+
161+
#[cfg(feature = "std")]
162+
unsafe impl<'t, T: ?Sized> Pointer<'t, T> for Arc<T> {
163+
type To<'u, U: 'u + ?Sized> = Arc<U>;
164+
165+
type Aliasing = super::invariant::Arc;
166+
167+
#[inline(always)]
168+
fn into_ptr(self) -> PtrInner<'t, T> {
169+
PtrInner::from_arc(self)
170+
}
171+
172+
#[inline(always)]
173+
unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Arc<T> {
174+
unsafe { Arc::from_raw(ptr.as_non_null().as_ptr()) }
175+
}
176+
}
177+
}

src/pointer/ptr.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,30 @@ mod _external {
172172
/// Methods for converting to and from `Ptr` and Rust's safe reference types.
173173
mod _conversions {
174174
use super::*;
175-
use crate::pointer::transmute::TransmuteFromPtr;
175+
use crate::pointer::{transmute::TransmuteFromPtr, Pointer};
176+
177+
// TODO: How to make this a `From` impl without blanket impl conflicts?
178+
impl<'a, T, A> Ptr<'a, T, (A, Aligned, Valid)>
179+
where
180+
T: 'a + ?Sized,
181+
A: Aliasing,
182+
{
183+
/// Constructs a `Ptr` from an existing smart pointer or reference type.
184+
#[doc(hidden)]
185+
#[inline]
186+
pub fn from_pointer<P: Pointer<'a, T, Aliasing = A>>(ptr: P) -> Self {
187+
let ptr = P::into_ptr(ptr);
188+
unsafe { Self::from_inner(ptr) }
189+
}
190+
191+
/// Constructs `self` to a smart pointer or reference type.
192+
#[doc(hidden)]
193+
#[inline]
194+
#[must_use]
195+
pub fn into_pointer<P: Pointer<'a, T, Aliasing = A>>(self) -> P {
196+
unsafe { P::from_ptr(self.as_inner()) }
197+
}
198+
}
176199

177200
/// `&'a T` → `Ptr<'a, T>`
178201
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
@@ -899,6 +922,9 @@ mod _casts {
899922
/// - If this is a prefix cast, `ptr` has the same address as `self`.
900923
/// - If this is a suffix cast, `remainder` has the same address as
901924
/// `self`.
925+
// TODO: This is currently unsound - need to bound with `I::Aliasing:
926+
// Reference` in order to prove that splitting is okay (it isn't for
927+
// e.g. Box and Arc).
902928
pub(crate) fn try_cast_into<U, R>(
903929
self,
904930
cast_type: CastType,

0 commit comments

Comments
 (0)