Skip to content

Instantly share code, notes, and snippets.

@CAD97
Created April 26, 2023 03:46
Show Gist options
  • Save CAD97/224024aa084350308392f02329698791 to your computer and use it in GitHub Desktop.
Save CAD97/224024aa084350308392f02329698791 to your computer and use it in GitHub Desktop.
dynit, another experimental stable dyn*-alike
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