Skip to content

Commit acadf8a

Browse files
committed
[pointer] Support Box and Arc
gherrit-pr-id: I70880ddd683a1edd8cfdf553f9238db2ae0f7149
1 parent f3a5e25 commit acadf8a

File tree

6 files changed

+192
-16
lines changed

6 files changed

+192
-16
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
@@ -3480,10 +3480,22 @@ pub unsafe trait FromBytes: FromZeros {
34803480
where
34813481
Self: KnownLayout + Immutable,
34823482
{
3483-
static_assert_dst_is_not_zst!(Self);
3484-
match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) {
3485-
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()),
3486-
Err(err) => Err(err.map_src(|src| src.as_ref())),
3483+
Self::from_bytes(source)
3484+
}
3485+
3486+
#[must_use = "has no side effects"]
3487+
#[inline]
3488+
fn from_bytes<'a, P: pointer::Pointer<'a, Self>, R>(
3489+
source: P::To<'a, [u8]>,
3490+
) -> Result<P, CastError<P::To<'a, [u8]>, Self>>
3491+
where
3492+
Self: 'a + KnownLayout + invariant::Read<P::Aliasing, R>,
3493+
{
3494+
match Ptr::<'_, _, (P::Aliasing, _, _)>::from_pointer(source)
3495+
.try_cast_into_no_leftover::<_, R>(None)
3496+
{
3497+
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().into_pointer()),
3498+
Err(err) => Err(err.map_src(|src| src.into_pointer())),
34873499
}
34883500
}
34893501

@@ -3716,11 +3728,7 @@ pub unsafe trait FromBytes: FromZeros {
37163728
where
37173729
Self: IntoBytes + KnownLayout,
37183730
{
3719-
static_assert_dst_is_not_zst!(Self);
3720-
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
3721-
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()),
3722-
Err(err) => Err(err.map_src(|src| src.as_mut())),
3723-
}
3731+
Self::from_bytes(source)
37243732
}
37253733

37263734
/// 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
@@ -89,6 +89,15 @@ pub trait Aliasing: Sealed {
8989
/// Aliasing>::Variance<'a, T>` to inherit this variance.
9090
#[doc(hidden)]
9191
type Variance<'a, T: 'a + ?Sized>;
92+
93+
// #[doc(hidden)]
94+
// type Applied<'a, T: 'a + ?Sized>;
95+
96+
// #[doc(hidden)]
97+
// fn into_ptr<'a, T: 'a + ?Sized>(ptr: Self::Applied<'a, T>) -> PtrInner<'a, T>;
98+
99+
// #[doc(hidden)]
100+
// unsafe fn from_ptr<'a, T: 'a + ?Sized>(ptr: PtrInner<'a, T>) -> Self::Applied<'a, T>;
92101
}
93102

94103
// NOTE: The `AlignmentInner`/`Alignment` distinction is required so that we can
@@ -186,6 +195,34 @@ impl Aliasing for Exclusive {
186195
}
187196
impl Reference for Exclusive {}
188197

198+
#[cfg(feature = "alloc")]
199+
mod _alloc {
200+
use alloc::boxed::Box as Bx;
201+
202+
use super::*;
203+
204+
pub enum Box {}
205+
impl Aliasing for Box {
206+
const IS_EXCLUSIVE: bool = false;
207+
type Variance<'a, T: 'a + ?Sized> = Bx<T>;
208+
}
209+
}
210+
211+
#[cfg(feature = "std")]
212+
pub use _std::*;
213+
#[cfg(feature = "std")]
214+
mod _std {
215+
use std::sync::Arc as Ac;
216+
217+
use super::*;
218+
219+
pub enum Arc {}
220+
impl Aliasing for Arc {
221+
const IS_EXCLUSIVE: bool = false;
222+
type Variance<'a, T: 'a + ?Sized> = Ac<T>;
223+
}
224+
}
225+
189226
/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
190227
/// of the `T`'s alignment.
191228
pub enum Aligned {}
@@ -237,6 +274,18 @@ impl ValidityInner for Valid {
237274
type MappedTo<M: ValidityMapping> = M::FromValid;
238275
}
239276

277+
// Shared, Arc, etc
278+
pub trait SharedFoo: Aliasing {}
279+
impl SharedFoo for Shared {}
280+
#[cfg(feature = "std")]
281+
impl SharedFoo for Arc {}
282+
283+
// Exclusive, Box, etc
284+
pub trait ExclusiveFoo: Aliasing {}
285+
impl ExclusiveFoo for Exclusive {}
286+
#[cfg(feature = "alloc")]
287+
impl ExclusiveFoo for Box {}
288+
240289
/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
241290
///
242291
/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
@@ -261,8 +310,7 @@ define_because!(
261310
#[doc(hidden)]
262311
pub BecauseExclusive
263312
);
264-
// SAFETY: The aliasing parameter is `Exclusive`.
265-
unsafe impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
313+
unsafe impl<A: ExclusiveFoo, T: ?Sized> Read<A, BecauseExclusive> for T {}
266314

267315
define_because!(
268316
/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s
@@ -283,6 +331,10 @@ mod sealed {
283331

284332
impl Sealed for Shared {}
285333
impl Sealed for Exclusive {}
334+
#[cfg(feature = "alloc")]
335+
impl Sealed for Box {}
336+
#[cfg(feature = "std")]
337+
impl Sealed for Arc {}
286338

287339
impl Sealed for Aligned {}
288340

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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,29 @@ mod _conversions {
176176
TransmuteFromAlignment, TransmuteFromPtr, TransmuteFromPtrOld,
177177
};
178178

179+
// TODO: How to make this a `From` impl without blanket impl conflicts?
180+
impl<'a, T, A> Ptr<'a, T, (A, Aligned, Valid)>
181+
where
182+
T: 'a + ?Sized,
183+
A: Aliasing,
184+
{
185+
/// Constructs a `Ptr` from an existing smart pointer or reference type.
186+
#[doc(hidden)]
187+
#[inline]
188+
pub fn from_pointer<P: Pointer<'a, T, Aliasing = A>>(ptr: P) -> Self {
189+
let ptr = P::into_ptr(ptr);
190+
unsafe { Self::from_inner(ptr) }
191+
}
192+
193+
/// Constructs `self` to a smart pointer or reference type.
194+
#[doc(hidden)]
195+
#[inline]
196+
#[must_use]
197+
pub fn into_pointer<P: Pointer<'a, T, Aliasing = A>>(self) -> P {
198+
unsafe { P::from_ptr(self.as_inner()) }
199+
}
200+
}
201+
179202
/// `&'a T` → `Ptr<'a, T>`
180203
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
181204
where
@@ -927,6 +950,9 @@ mod _casts {
927950
/// - If this is a prefix cast, `ptr` has the same address as `self`.
928951
/// - If this is a suffix cast, `remainder` has the same address as
929952
/// `self`.
953+
// TODO: This is currently unsound - need to bound with `I::Aliasing:
954+
// Reference` in order to prove that splitting is okay (it isn't for
955+
// e.g. Box and Arc).
930956
#[inline(always)]
931957
pub(crate) fn try_cast_into<U, R>(
932958
self,

0 commit comments

Comments
 (0)