Skip to content

Commit 3c81371

Browse files
committed
Initial commit of Ptr pointer type
`Ptr` is like `NonNull`, but has many restrictions which make it so that using a `Ptr` in unsafe code requires much simpler soundness proofs. Notably, it supports a `try_cast_into<U>` method where `U: ?Sized + KnownLayout`, which is a building block of `TryFromBytes`.
1 parent 9041ec1 commit 3c81371

3 files changed

Lines changed: 494 additions & 14 deletions

File tree

src/lib.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,17 +195,27 @@ use core::{
195195
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
196196
},
197197
ops::{Deref, DerefMut},
198-
ptr, slice,
198+
ptr::{self, NonNull},
199+
slice,
199200
};
200201

201202
#[cfg(feature = "alloc")]
202203
extern crate alloc;
203204
#[cfg(feature = "alloc")]
204205
use {
205206
alloc::{boxed::Box, vec::Vec},
206-
core::{alloc::Layout, ptr::NonNull},
207+
core::alloc::Layout,
207208
};
208209

210+
// For each polyfill, as soon as the corresponding feature is stable, the
211+
// polyfill import will be unused because method/function resolution will prefer
212+
// the inherent method/function over a trait method/function. Thus, we suppress
213+
// the `unused_imports` warning.
214+
//
215+
// See the documentation on `util::polyfills` for more information.
216+
#[allow(unused_imports)]
217+
use crate::util::polyfills::{NonNullExt as _, NonNullSliceExt as _};
218+
209219
// This is a hack to allow zerocopy-derive derives to work in this crate. They
210220
// assume that zerocopy is linked as an extern crate, so they access items from
211221
// it as `zerocopy::Xxx`. This makes that still work.
@@ -300,8 +310,11 @@ impl SizeInfo {
300310
}
301311
}
302312

303-
#[cfg_attr(test, derive(Copy, Clone, Debug))]
304-
enum _CastType {
313+
#[doc(hidden)]
314+
#[derive(Copy, Clone)]
315+
#[cfg_attr(test, derive(Debug))]
316+
#[allow(missing_debug_implementations)]
317+
pub enum _CastType {
305318
_Prefix,
306319
_Suffix,
307320
}
@@ -406,6 +419,9 @@ impl DstLayout {
406419
///
407420
/// # Panics
408421
///
422+
/// `validate_cast_and_convert_metadata` will panic if `self` describes a
423+
/// DST whose trailing slice element is zero-sized.
424+
///
409425
/// If `addr + bytes_len` overflows `usize`,
410426
/// `validate_cast_and_convert_metadata` may panic, or it may return
411427
/// incorrect results. No guarantees are made about when
@@ -573,12 +589,27 @@ impl DstLayout {
573589
pub unsafe trait KnownLayout: sealed::KnownLayoutSealed {
574590
#[doc(hidden)]
575591
const LAYOUT: DstLayout;
592+
593+
/// SAFETY: The returned pointer has the same address and provenance as
594+
/// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
595+
/// elements in its trailing slice. If `Self` is sized, `elems` is ignored.
596+
#[doc(hidden)]
597+
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self>;
576598
}
577599

578600
impl<T: KnownLayout> sealed::KnownLayoutSealed for [T] {}
579601
// SAFETY: Delegates safety to `DstLayout::for_slice`.
580602
unsafe impl<T: KnownLayout> KnownLayout for [T] {
581603
const LAYOUT: DstLayout = DstLayout::for_slice::<T>();
604+
605+
// SAFETY: `.cast` preserves address and provenance. The returned pointer
606+
// refers to an object with `elems` elements by construction.
607+
#[inline(always)]
608+
fn raw_from_ptr_len(data: NonNull<u8>, elems: usize) -> NonNull<Self> {
609+
// TODO(#67): Remove this allow. See NonNullExt for more details.
610+
#[allow(unstable_name_collisions)]
611+
NonNull::slice_from_raw_parts(data.cast::<T>(), elems)
612+
}
582613
}
583614

584615
#[rustfmt::skip]

src/macros.rs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,21 @@ macro_rules! impl_known_layout {
204204
};
205205
($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* };
206206
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => {
207-
impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> sealed::KnownLayoutSealed for $ty {}
208-
// SAFETY: Delegates safety to `DstLayout::for_type`.
209-
unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
210-
const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();
211-
}
207+
const _: () = {
208+
use core::ptr::NonNull;
209+
210+
impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> sealed::KnownLayoutSealed for $ty {}
211+
// SAFETY: Delegates safety to `DstLayout::for_type`.
212+
unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
213+
const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();
214+
215+
// SAFETY: `.cast` preserves address and provenance.
216+
#[inline(always)]
217+
fn raw_from_ptr_len(bytes: NonNull<u8>, _elems: usize) -> NonNull<Self> {
218+
bytes.cast::<Self>()
219+
}
220+
}
221+
};
212222
};
213223
}
214224

@@ -225,10 +235,25 @@ macro_rules! impl_known_layout {
225235
/// and this operation must preserve referent size (ie, `size_of_val_raw`).
226236
macro_rules! unsafe_impl_known_layout {
227237
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
228-
impl<$($tyvar: ?Sized + KnownLayout)?> sealed::KnownLayoutSealed for $ty {}
229-
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
230-
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
231-
}
238+
const _: () = {
239+
use core::ptr::NonNull;
240+
241+
impl<$($tyvar: ?Sized + KnownLayout)?> sealed::KnownLayoutSealed for $ty {}
242+
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
243+
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
244+
245+
// SAFETY: All operations preserve address and provenance. Caller
246+
// has promised that the `as` cast preserves size.
247+
#[inline(always)]
248+
#[allow(unused_qualifications)] // for `core::ptr::NonNull`
249+
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self> {
250+
#[allow(clippy::as_conversions)]
251+
let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self;
252+
// SAFETY: `ptr` was converted from `bytes`, which is non-null.
253+
unsafe { NonNull::new_unchecked(ptr) }
254+
}
255+
}
256+
};
232257
};
233258
}
234259

0 commit comments

Comments
 (0)