#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] mod async_iter { use std::{future::Future, intrinsics::transmute, marker::PhantomData, pin::Pin}; pub trait AsyncIter { type Item; type Next<'me>: Future> where Self: 'me; fn next(&mut self) -> Self::Next<'_>; } type ErasedData = (); pub struct DynAsyncIter { data: *mut ErasedData, vtable: &'static ErasedDynAsyncIterVtable, phantom: PhantomData Item>, } type DropFnType = unsafe fn(*mut ErasedData); type NextFnType = for<'a> unsafe fn( &'a mut *mut ErasedData, ) -> Pin> + 'a>>; // struct DynAsyncIterVtable { // drop_fn: DropFnType, // next_fn: NextFnType, // } struct ErasedDynAsyncIterVtable { drop_fn: usize, next_fn: usize, } impl AsyncIter for DynAsyncIter { type Item = Item; type Next<'me> where Item: 'me, = Pin> + 'me>>; fn next(&mut self) -> Self::Next<'_> { let next_fn: NextFnType = unsafe { transmute(self.vtable.next_fn) }; unsafe { next_fn(&mut self.data) } } } impl Drop for DynAsyncIter { fn drop(&mut self) { let drop_fn: DropFnType = unsafe { transmute(self.vtable.drop_fn) }; unsafe { drop_fn(self.data); } } } impl DynAsyncIter { pub fn new(value: T) -> DynAsyncIter where T: AsyncIter, { let boxed_value = Box::new(value); DynAsyncIter { data: Box::into_raw(boxed_value) as *mut (), vtable: dyn_async_iter_vtable::(), // we’ll cover this fn later phantom: PhantomData, } } } // Safety conditions: // // The `*mut ErasedData` is actually the raw form of a `Box` // that is valid for ‘a. unsafe fn next_wrapper<'a, T>( this: &'a mut *mut ErasedData, ) -> Pin> + 'a>> where T: AsyncIter + 'a, { let this_raw: *mut *mut ErasedData = this; let this_raw: *mut Box = this_raw as *mut Box; let unerased_this: &mut Box = &mut *this_raw; let future: T::Next<'_> = ::next(unerased_this); Box::pin(future) } // Safety conditions: // // The `*mut ErasedData` is actually the raw form of a `Box` // and this function is being given ownership of it. unsafe fn drop_wrapper(this: *mut ErasedData) where T: AsyncIter, { let unerased_this = Box::from_raw(this as *mut T); drop(unerased_this); // Execute destructor as normal } fn dyn_async_iter_vtable() -> &'static ErasedDynAsyncIterVtable where T: AsyncIter, { // FIXME: This would ideally be `&DynAsyncIterVtable`, // but we have to hide the types from the compiler, and even so // I can't convince it to promote this value to `'static`. Box::leak(Box::new(ErasedDynAsyncIterVtable { drop_fn: drop_wrapper:: as usize, next_fn: next_wrapper:: as usize, })) } } mod yielding_range { use crate::async_iter::AsyncIter; use std::future::Future; use tokio::task; pub struct YieldingRange { start: u32, stop: u32, } impl YieldingRange { pub fn new(start: u32, stop: u32) -> Self { Self { start, stop } } } impl AsyncIter for YieldingRange { type Item = u32; type Next<'me> = impl Future> + 'me; fn next(&mut self) -> Self::Next<'_> { async move { task::yield_now().await; if self.start == self.stop { None } else { let p = self.start; self.start += 1; Some(p) } } } } } use async_iter::AsyncIter; #[tokio::main] async fn main() { let range = yielding_range::YieldingRange::new(0, 10); let mut boxed_range = async_iter::DynAsyncIter::new(range); while let Some(v) = boxed_range.next().await { println!("v={}", v); } }