Created
April 26, 2023 03:46
-
-
Save CAD97/224024aa084350308392f02329698791 to your computer and use it in GitHub Desktop.
dynit, another experimental stable dyn*-alike
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::future::Future; | |
use std::marker::PhantomData; | |
use std::ops::{Deref, DerefMut}; | |
use std::pin::Pin; | |
use std::ptr::{drop_in_place, NonNull}; | |
use std::task::{Context, Poll}; | |
// example | |
fn main() { | |
fn takes_all<'a>(x: impl IntoDynRef<'a, dyn Future<Output = ()> + 'a>) { | |
let toy = x.into_dyn_ref(); | |
_ = &*toy; | |
} | |
struct DbgDrop(&'static str); | |
impl Drop for DbgDrop { | |
fn drop(&mut self) { dbg!(self.0); } | |
} | |
let fut = |x| { | |
let dd = DbgDrop(x); | |
async move { | |
drop(dd); | |
} | |
}; | |
takes_all(Box::new(fut("Box"))); | |
takes_all(&fut("&")); | |
takes_all(&mut fut("&mut")); | |
} | |
// types | |
pub struct Dynit<P: Ptr>(PhantomData<P>) | |
where | |
P::Pointee: Sized; | |
impl<P: Ptr> Drop for Dynit<P> | |
where | |
P::Pointee: Sized, | |
{ | |
fn drop(&mut self) { | |
drop(unsafe { P::from_raw_ptr(self.as_mut_ptr()) }); | |
} | |
} | |
pub struct DynRef<'a, Dyn: ?Sized> { | |
ptr: NonNull<Dyn>, | |
phantom: PhantomData<&'a Dyn>, | |
} | |
impl<Dyn: ?Sized> Drop for DynRef<'_, Dyn> { | |
fn drop(&mut self) { | |
unsafe { drop_in_place(self.ptr.as_ptr()) }; | |
} | |
} | |
pub struct DynMut<'a, Dyn: ?Sized> { | |
ptr: NonNull<Dyn>, | |
phantom: PhantomData<&'a mut Dyn>, | |
} | |
impl<Dyn: ?Sized> Drop for DynMut<'_, Dyn> { | |
fn drop(&mut self) { | |
unsafe { drop_in_place(self.ptr.as_ptr()) }; | |
} | |
} | |
pub type DynBox<Dyn> = DynMut<'static, Dyn>; | |
pub type DynObj<Dyn> = DynRef<'static, Dyn>; | |
// traits | |
pub unsafe trait Ptr: Sized { | |
type Pointee: ?Sized; | |
fn into_raw_ptr(self) -> *mut Self::Pointee; | |
unsafe fn from_raw_ptr(ptr: *mut Self::Pointee) -> Self; | |
} | |
pub unsafe trait CoercePtr<U: ?Sized> { | |
fn coerce_ptr(ptr: *const Self) -> *const U; | |
#[inline] | |
fn coerce_mut_ptr(ptr: *mut Self) -> *mut U { | |
Self::coerce_ptr(ptr) as *mut _ | |
} | |
} | |
pub unsafe trait Coerce<'a>: Ptr { | |
type Coerced<U: ?Sized + 'a>: Coerce<'a> + Ptr<Pointee = U>; | |
#[inline] | |
fn coerce<U: ?Sized>(self) -> Self::Coerced<U> | |
where | |
Self::Pointee: CoercePtr<U>, | |
{ | |
let raw = self.into_raw_ptr(); | |
let raw = CoercePtr::coerce_mut_ptr(raw); | |
unsafe { Self::Coerced::<U>::from_raw_ptr(raw) } | |
} | |
} | |
pub unsafe trait IntoDynit: Ptr { | |
fn into_dynit(self) -> *mut Self::Pointee; | |
} | |
// hook a trait into dynit | |
type AsDynFuture<'a, F> = dyn Future<Output = <F as Future>::Output> + 'a; | |
unsafe impl<'a, F> CoercePtr<AsDynFuture<'a, F>> for F | |
where | |
F: Future + 'a, | |
{ | |
#[inline] | |
fn coerce_ptr(ptr: *const Self) -> *const AsDynFuture<'a, F> { | |
ptr as *const _ | |
} | |
} | |
impl<P> Future for Dynit<P> | |
where | |
P: Ptr, | |
P::Pointee: Future + Sized, | |
{ | |
type Output = <P::Pointee as Future>::Output; | |
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | |
self.as_pin_mut().poll(cx) | |
} | |
} | |
// extension traits | |
#[inline] | |
fn launder<P>(ptr: P) -> P | |
where | |
P: Ptr, | |
P::Pointee: Sized, | |
{ | |
let addr = ptr.into_raw_ptr() as usize; | |
unsafe { Ptr::from_raw_ptr(addr as *mut _) } | |
} | |
pub trait IntoDynRef<'a, Dyn: ?Sized>: Coerce<'a> { | |
fn into_dyn_ref(self) -> DynRef<'a, Dyn>; | |
} | |
impl<'a, P, Dyn: ?Sized> IntoDynRef<'a, Dyn> for P | |
where | |
P: Coerce<'a> + Deref, | |
P::Pointee: CoercePtr<Dyn> + Sized, | |
Dynit<P>: CoercePtr<Dyn>, | |
{ | |
#[inline] | |
fn into_dyn_ref(self) -> DynRef<'a, Dyn> { | |
let this: *mut Dynit<P> = self.into_raw_ptr().cast(); | |
unsafe { DynRef::from_dynit(launder(this).coerce()) } | |
} | |
} | |
pub trait IntoDynMut<'a, Dyn: ?Sized>: Coerce<'a> { | |
fn into_dyn_mut(self) -> DynMut<'a, Dyn>; | |
} | |
impl<'a, P, Dyn: ?Sized> IntoDynMut<'a, Dyn> for P | |
where | |
P: Coerce<'a> + DerefMut, | |
P::Pointee: CoercePtr<Dyn> + Sized, | |
Dynit<P>: CoercePtr<Dyn>, | |
{ | |
#[inline] | |
fn into_dyn_mut(self) -> DynMut<'a, Dyn> { | |
let this: *mut Dynit<P> = self.into_raw_ptr().cast(); | |
unsafe { DynMut::from_dynit(launder(this).coerce()) } | |
} | |
} | |
// own trait impls | |
unsafe impl<T: ?Sized> Ptr for Box<T> { | |
type Pointee = T; | |
#[inline] | |
fn into_raw_ptr(self) -> *mut T { | |
Self::into_raw(self) | |
} | |
#[inline] | |
unsafe fn from_raw_ptr(ptr: *mut T) -> Self { | |
Self::from_raw(ptr) | |
} | |
} | |
unsafe impl<'a, T: ?Sized> Coerce<'a> for Box<T> { | |
type Coerced<U: ?Sized + 'a> = Box<U>; | |
} | |
unsafe impl<'a, T: ?Sized> Ptr for &'a T { | |
type Pointee = T; | |
#[inline] | |
fn into_raw_ptr(self) -> *mut T { | |
self as *const _ as *mut _ | |
} | |
#[inline] | |
unsafe fn from_raw_ptr(ptr: *mut T) -> Self { | |
&*ptr | |
} | |
} | |
unsafe impl<'a, 'u, T: ?Sized> Coerce<'u> for &'a T { | |
type Coerced<U: ?Sized + 'u> = &'u U; | |
} | |
unsafe impl<'a, T: ?Sized> Ptr for &'a mut T { | |
type Pointee = T; | |
#[inline] | |
fn into_raw_ptr(self) -> *mut T { | |
self | |
} | |
#[inline] | |
unsafe fn from_raw_ptr(ptr: *mut T) -> Self { | |
&mut *ptr | |
} | |
} | |
unsafe impl<'a, 'u, T: ?Sized> Coerce<'u> for &'a mut T { | |
type Coerced<U: ?Sized + 'u> = &'u mut U; | |
} | |
unsafe impl<T: ?Sized> Ptr for *const T { | |
type Pointee = T; | |
#[inline] | |
fn into_raw_ptr(self) -> *mut T { | |
self as *mut _ | |
} | |
#[inline] | |
unsafe fn from_raw_ptr(ptr: *mut T) -> Self { | |
ptr as *const _ | |
} | |
} | |
unsafe impl<'a, T: ?Sized> Coerce<'a> for *const T { | |
type Coerced<U: ?Sized + 'a> = &'a U; | |
} | |
unsafe impl<T: ?Sized> Ptr for *mut T { | |
type Pointee = T; | |
#[inline] | |
fn into_raw_ptr(self) -> *mut T { | |
self | |
} | |
#[inline] | |
unsafe fn from_raw_ptr(ptr: *mut T) -> Self { | |
ptr | |
} | |
} | |
unsafe impl<'a, T: ?Sized> Coerce<'a> for *mut T { | |
type Coerced<U: ?Sized + 'a> = *mut U; | |
} | |
unsafe impl<T: ?Sized> CoercePtr<T> for T { | |
#[inline] | |
fn coerce_ptr(ptr: *const T) -> *const T { | |
ptr | |
} | |
} | |
// inherent impls | |
impl<P> Dynit<P> | |
where | |
P: Ptr, | |
P::Pointee: Sized, | |
{ | |
#[inline] | |
pub fn as_ref(&self) -> &P::Pointee { | |
unsafe { &*self.as_ptr() } | |
} | |
#[inline] | |
pub fn as_mut(&mut self) -> &mut P::Pointee { | |
unsafe { &mut *self.as_mut_ptr() } | |
} | |
#[inline] | |
pub fn as_pin_ref(self: Pin<&Self>) -> Pin<&P::Pointee> { | |
unsafe { self.map_unchecked(Self::as_ref) } | |
} | |
#[inline] | |
pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut P::Pointee> { | |
unsafe { self.map_unchecked_mut(Self::as_mut) } | |
} | |
#[inline] | |
pub fn as_ptr(&self) -> *const P::Pointee { | |
launder(self as *const _ as *const _) | |
} | |
#[inline] | |
pub fn as_mut_ptr(&mut self) -> *mut P::Pointee { | |
launder(self as *mut _ as *mut _) | |
} | |
} | |
impl<'a, Dyn: ?Sized> DynRef<'a, Dyn> { | |
#[inline] | |
unsafe fn from_dynit(ptr: *mut Dyn) -> Self { | |
Self { | |
ptr: unsafe { NonNull::new_unchecked(ptr) }, | |
phantom: PhantomData, | |
} | |
} | |
} | |
impl<'a, Dyn: ?Sized> DynMut<'a, Dyn> { | |
#[inline] | |
unsafe fn from_dynit(ptr: *mut Dyn) -> Self { | |
Self { | |
ptr: unsafe { NonNull::new_unchecked(ptr) }, | |
phantom: PhantomData, | |
} | |
} | |
} | |
// upstream trait impls | |
impl<Dyn: ?Sized> Deref for DynRef<'_, Dyn> { | |
type Target = Dyn; | |
#[inline] | |
fn deref(&self) -> &Dyn { | |
unsafe { self.ptr.as_ref() } | |
} | |
} | |
impl<Dyn: ?Sized> Deref for DynMut<'_, Dyn> { | |
type Target = Dyn; | |
#[inline] | |
fn deref(&self) -> &Dyn { | |
unsafe { self.ptr.as_ref() } | |
} | |
} | |
impl<Dyn: ?Sized> DerefMut for DynMut<'_, Dyn> { | |
#[inline] | |
fn deref_mut(&mut self) -> &mut Dyn { | |
unsafe { self.ptr.as_mut() } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment