Skip to content

Stdlib proposal: AsPtr, IntoRawPtr, FromRawPtr #75846

@Lucretiel

Description

@Lucretiel

I'd like to propose some new conversion traits for core::convert: AsPtr, IntoRawPtr, FromRawPtr. These would be defined like so:

trait AsPtr {
    type Inner: ?Sized;
    fn as_ptr(&self) -> *const Self::Inner;
}

trait IntoRawPtr: Sized {
    type Inner: ?Sized;
    fn into_raw(self) -> *mut Self::Inner;
}

trait FromRawPtr: IntoRawPtr {
    // Safety: this must ONLY be called on a pointer that was received
    // through `into_raw`, and that pointer must immediately be discarded
    // afterwards
    unsafe fn from_raw(*mut Self::Inner) -> Self
}

These traits would be implemented for raw pointer types, as well as for smart pointer types like Box, Arc, Weak, etc.

The purpose of these traits would, obviously, be to facilitate conversion of a type into and back out of a pointer. The motivating practical use case is to make it easier to create RawWakers and associated implementations, especially through intermediate Handle types. Consider this example:

#[derive(Clone)]
struct MyWaker {
    state: Arc<State>,
}

impl MyWaker {
    fn wake(&self) { ... }
}

This would be relatively easy to create a RawWaker for, since we can directly convert the state Arc into and out of the requisite *const(), and write the vtable methods to convert it back into an Arc. However, now consider this example:

// Crate A:
#[derive(Clone)]
struct Unparker {
    state: Arc<State>
}

impl Unparker {
    fn unpark(&self) { ... }
}

// Crate B:
#[derive(Clone)]
struct MyWaker {
    state: Unparker
}

impl MyWaker {
    fn wake(&self) { self.state.unpark(); }
}

This would be impossible to create a RawWaker for, without:

  • Boxing or Arcing the Unparker (adds an unnecessary level of indirection)
  • transmuting the Unparker to and from *const() (unsafe, since it now depends on the private implementation details of Unparker).

However, with the proposed traits, if Unparker wanted to opt-in to being used in this way, it could:

impl IntoRawPtr for Unparker {
    type Inner = ();
    fn into_raw(self) -> *mut () {
        self.state.into_raw() as *mut()
    }
}

impl FromRawPtr for Unparker {
    unsafe fn from_raw(ptr: *mut ()) -> Self {
        Self { state: Arc::from_raw(ptr as *mut State) }
    }
}

This would allow the Unparker to declare its "pointer-ness" as part of its public API (without actually exposing any implementation details), enabling its use in RawWaker (and other raw pointer APIs, such as C FFI).

Alternatives:

Third party

These traits could, of course, be provided as a 3rd party crate, but I believe these traits are sufficiently "fundamental" (similar to Into/From, AsRef, etc) to warrant inclusion directly into the standard library. This would also help different, independent libraries to coordinate with each other through this trait, which is possible but more difficult (due to potential ecosystem fragmentation) with a third party crate. It's also the sort of thing that seems "too simple" to require an entire dependency crate.

Existing traits

While we could use Into / From, I don't think that those provide a strong enough contract to ensure the correct use of these, especially IntoRawPtr and FromRawPtr. Additionally, a type should only be able to be converted through a single pointer type, so having a dedicated trait with an associated type makes the most sense.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions