You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The core goal is to make async fn in trait and other RPITIT usable with dynamic dispatch via a proc macro, in a way similar to how it works with async_trait, but while continuing to allow static dispatch.
The ErasedAsyncIter trait is used to have the compiler generate a vtable for each concrete type that is used to create a DynAsyncIter. It is not part of the public interface. *mut dyn ErasedAsyncIter is a fat pointer.
Note the use of Ref and RefMut wrapper types (which would go in some support library) so that we can also have DynAsyncIter::from_ref and DynAsyncIter::from_ref_mut. These wrappers are slightly verbose, but due to their deref impls, can be reborrowed to create &DynMyTrait and &mut DynMyTrait respectively.
This code uses GATs instead of RPITIT in the original trait, since those weren't stable yet, but the same ideas should apply.
This code makes use of a union to do bit-twiddling on the data pointer, as a way of marking whether the underlying value is owned. This is not well-defined and should not be necessary, because we can instead have Ref<DynAsyncIter>'s field be ManuallyDrop<DynAsyncIter> EDIT: Actually we probably do need something like this if we have RefMut which gives out &mut DynAsyncIter; we just need to make it well-defined by using std pointer APIs.
The text was updated successfully, but these errors were encountered:
The core goal is to make
async fn
in trait and other RPITIT usable with dynamic dispatch via a proc macro, in a way similar to how it works with async_trait, but while continuing to allow static dispatch.It core idea of how it works is described here: https://rust-lang.github.io/async-fundamentals-initiative/explainer/async_fn_in_dyn_trait/hardcoding_box.html
Given a trait like
Instead of using a type like
Box<dyn MyTrait>
which wouldn't compile today, we would have the proc macro create a typeDynMyTrait
with this interface:The struct itself would look something like this. A full explanation is in the links and in the exposition below.
A full example including macro output is here: https://github.com/nikomatsakis/dyner/blob/main/src/async_iter.rs. Notes:
ErasedAsyncIter
trait is used to have the compiler generate a vtable for each concrete type that is used to create aDynAsyncIter
. It is not part of the public interface.*mut dyn ErasedAsyncIter
is a fat pointer.Ref
andRefMut
wrapper types (which would go in some support library) so that we can also haveDynAsyncIter::from_ref
andDynAsyncIter::from_ref_mut
. These wrappers are slightly verbose, but due to their deref impls, can be reborrowed to create&DynMyTrait
and&mut DynMyTrait
respectively.and should not be necessary, because we can instead haveEDIT: Actually we probably do need something like this if we haveRef<DynAsyncIter>
's field beManuallyDrop<DynAsyncIter>
RefMut
which gives out&mut DynAsyncIter
; we just need to make it well-defined by using std pointer APIs.The text was updated successfully, but these errors were encountered: