-
-
Notifications
You must be signed in to change notification settings - Fork 14.5k
Description
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
Unparkerto and from*const()(unsafe, since it now depends on the private implementation details ofUnparker).
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.