Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,14 @@ pub unsafe trait FromBytes: FromZeros {
Some(ptr.bikeshed_recall_valid().as_ref())
}

fn ref_from_foo<'a, B: 'a + pointer::Pointer<'a, [u8]>>(bytes: B) -> Option<B::Pointer<Self>>
where
Self: KnownLayout + Immutable,
{
let ptr = Ptr::from_foo(bytes).try_cast_into_no_leftover()?;
Some(pointer::Pointer::from_ptr(ptr.bikeshed_recall_valid()))
}

/// Interprets the prefix of the given `bytes` as a `&Self` without copying.
///
/// This method returns both a reference to the first `size_of::<Self>()`
Expand Down
80 changes: 80 additions & 0 deletions src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod ptr;

pub use ptr::{invariant, Ptr};

use core::ptr::NonNull;

use crate::Unaligned;

/// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument
Expand Down Expand Up @@ -72,3 +74,81 @@ where
{
ptr.as_bytes().as_ref().iter().all(|&byte| byte == 0)
}

pub unsafe trait Pointer<'a, T: ?Sized> {
type Pointer<U: 'a + ?Sized>: Pointer<'a, U, Aliasing = Self::Aliasing>;
type Aliasing: invariant::Aliasing;

fn into_raw(self) -> NonNull<T>;

fn from_ptr<I>(ptr: Ptr<'a, T, I>) -> Self
where
I: invariant::Invariants<
Aliasing = Self::Aliasing,
Alignment = invariant::Aligned,
Validity = invariant::Valid,
>;
}

unsafe impl<'a, T: ?Sized> Pointer<'a, T> for &'a T {
type Pointer<U: 'a + ?Sized> = &'a U;
type Aliasing = invariant::Shared;

fn into_raw(self) -> NonNull<T> {
NonNull::from(self)
}

fn from_ptr<I>(ptr: Ptr<'a, T, I>) -> Self
where
I: invariant::Invariants<
Aliasing = invariant::Shared,
Alignment = invariant::Aligned,
Validity = invariant::Valid,
>,
{
ptr.as_ref()
}
}

unsafe impl<'a, T: ?Sized> Pointer<'a, T> for &'a mut T {
type Pointer<U: 'a + ?Sized> = &'a mut U;
type Aliasing = invariant::Exclusive;

fn into_raw(self) -> NonNull<T> {
NonNull::from(self)
}

fn from_ptr<I>(ptr: Ptr<'a, T, I>) -> Self
where
I: invariant::Invariants<
Aliasing = invariant::Exclusive,
Alignment = invariant::Aligned,
Validity = invariant::Valid,
>,
{
ptr.as_mut()
}
}

#[cfg(feature = "alloc")]
unsafe impl<T: ?Sized> Pointer<'static, T> for alloc::boxed::Box<T> {
type Pointer<U: 'static + ?Sized> = alloc::boxed::Box<U>;
type Aliasing = invariant::Owned;

fn into_raw(self) -> NonNull<T> {
let ptr = alloc::boxed::Box::into_raw(self);
// SAFETY: TODO
unsafe { NonNull::new_unchecked(ptr) }
}

fn from_ptr<I>(ptr: Ptr<'static, T, I>) -> Self
where
I: invariant::Invariants<
Aliasing = invariant::Owned,
Alignment = invariant::Aligned,
Validity = invariant::Valid,
>,
{
ptr.into_box()
}
}
35 changes: 33 additions & 2 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ pub mod invariant {
/// concurrently referenced by any other `Ptr`s or references,
/// and may not be accessed (read or written) other than via
/// this `Ptr`.
Exclusive,
Exclusive < Owned,

Owned,
}

/// The alignment invariant of a [`Ptr`][super::Ptr].
Expand Down Expand Up @@ -357,6 +359,18 @@ mod _conversions {
use super::*;
use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance};

impl<'a, T, Aliasing> Ptr<'a, T, (Aliasing, Aligned, Valid)>
where
T: 'a + ?Sized,
Aliasing: invariant::Aliasing,
{
pub fn from_foo<R: super::super::Pointer<'a, T, Aliasing = Aliasing>>(r: R) -> Self {
let ptr = r.into_raw();
// SAFETY: TODO
unsafe { Ptr::new(ptr) }
}
}

/// `&'a T` → `Ptr<'a, T>`
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
where
Expand Down Expand Up @@ -534,9 +548,10 @@ mod _conversions {
}

/// `Ptr<'a, T>` → `&'a mut T`
impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)>
impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Exclusive, Alignment = Aligned, Validity = Valid>,
{
/// Converts `self` to a mutable reference.
#[allow(clippy::wrong_self_convention)]
Expand Down Expand Up @@ -571,6 +586,22 @@ mod _conversions {
}
}

/// `Ptr<'a, T>` → `Box<T>`
#[cfg(feature = "alloc")]
impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Owned, Alignment = Aligned, Validity = Valid>,
{
/// Converts `self` to a box.
#[allow(clippy::wrong_self_convention)]
pub(crate) fn into_box(self) -> alloc::boxed::Box<T> {
let raw = self.as_non_null().as_ptr();
// SAFETY: TODO
Copy link

Copilot AI Apr 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unsafe block in the into_box method lacks a detailed safety justification; please add a clear explanation of the invariants that must be maintained.

Suggested change
// SAFETY: TODO
// SAFETY: The pointer `raw` is obtained from `self.as_non_null().as_ptr()`, which ensures that:
// - `raw` is non-null, as `NonNull::as_ptr` guarantees a non-null pointer.
// - `raw` is properly aligned, as `Ptr` ensures alignment invariants.
// - `raw` points to a valid allocation, as `Ptr` ensures validity invariants.
// Therefore, it is safe to convert `raw` into a `Box`.

Copilot uses AI. Check for mistakes.
unsafe { alloc::boxed::Box::from_raw(raw) }
}
}

/// `Ptr<'a, T = Wrapper<U>>` → `Ptr<'a, U>`
impl<'a, T, I> Ptr<'a, T, I>
where
Expand Down