Skip to content

Commit

Permalink
Merge pull request #44 from spastorino/async-and-non-async
Browse files Browse the repository at this point in the history
Properly handle functions that do not return RPITs
  • Loading branch information
tmandry authored Feb 3, 2025
2 parents 0779254 + 804e762 commit 591a72c
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 144 deletions.
9 changes: 9 additions & 0 deletions dynosaur/tests/pass/async-and-non-async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use dynosaur::dynosaur;

#[dynosaur(DynJobQueue)]
pub trait JobQueue {
fn len(&self) -> usize;
async fn dispatch(&self);
}

fn main() {}
73 changes: 73 additions & 0 deletions dynosaur/tests/pass/async-and-non-async.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use dynosaur::dynosaur;

pub trait JobQueue {
fn len(&self)
-> usize;
async fn dispatch(&self);
}
mod _dynosaur_macro_dynjobqueue {
use super::*;
pub trait ErasedJobQueue {
fn len(&self)
-> usize;
fn dispatch<'life0, 'dynosaur>(&'life0 self)
->
::core::pin::Pin<Box<dyn ::core::future::Future<Output = ()> +
'dynosaur>>
where
'life0: 'dynosaur,
Self: 'dynosaur;
}
impl<DYNOSAUR: JobQueue> ErasedJobQueue for DYNOSAUR {
fn len(&self) -> usize { <Self as JobQueue>::len(self) }
fn dispatch<'life0, 'dynosaur>(&'life0 self)
->
::core::pin::Pin<Box<dyn ::core::future::Future<Output = ()> +
'dynosaur>> where 'life0: 'dynosaur, Self: 'dynosaur {
Box::pin(<Self as JobQueue>::dispatch(self))
}
}
#[repr(transparent)]
pub struct DynJobQueue<'dynosaur_struct> {
ptr: dyn ErasedJobQueue + 'dynosaur_struct,
}
impl<'dynosaur_struct> JobQueue for DynJobQueue<'dynosaur_struct> {
fn len(&self) -> usize { self.ptr.len() }
fn dispatch(&self) -> impl ::core::future::Future<Output = ()> {
let fut:
::core::pin::Pin<Box<dyn ::core::future::Future<Output =
()> + '_>> = self.ptr.dispatch();
let fut:
::core::pin::Pin<Box<dyn ::core::future::Future<Output =
()> + 'static>> = unsafe { ::core::mem::transmute(fut) };
fut
}
}
impl<'dynosaur_struct> DynJobQueue<'dynosaur_struct> {
pub fn boxed(value: impl JobQueue + 'dynosaur_struct)
-> Box<DynJobQueue<'dynosaur_struct>> {
let value = Box::new(value);
let value: Box<dyn ErasedJobQueue + 'dynosaur_struct> = value;
unsafe { ::core::mem::transmute(value) }
}
pub fn from_ref(value: &(impl JobQueue + 'dynosaur_struct))
-> &DynJobQueue<'dynosaur_struct> {
let value: &(dyn ErasedJobQueue + 'dynosaur_struct) = &*value;
unsafe { ::core::mem::transmute(value) }
}
pub fn from_mut(value: &mut (impl JobQueue + 'dynosaur_struct))
-> &mut DynJobQueue<'dynosaur_struct> {
let value: &mut (dyn ErasedJobQueue + 'dynosaur_struct) =
&mut *value;
unsafe { ::core::mem::transmute(value) }
}
}
}
pub use _dynosaur_macro_dynjobqueue::DynJobQueue;

fn main() {}
63 changes: 26 additions & 37 deletions dynosaur_derive/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ use syn::punctuated::Punctuated;
use syn::token::RArrow;
use syn::visit_mut::VisitMut;
use syn::{
parse_quote, parse_quote_spanned, Error, FnArg, GenericParam, Generics, ItemTrait, Lifetime,
LifetimeParam, ReturnType, Signature, Token, TraitItem, TraitItemFn, Type, TypeImplTrait,
WhereClause,
parse_quote, parse_quote_spanned, Error, FnArg, GenericParam, Generics, Lifetime,
LifetimeParam, ReturnType, Signature, Token, TraitItemFn, Type, TypeImplTrait, WhereClause,
};

/// Expands the signature of each function on the trait, converting async fn into fn with return
Expand All @@ -36,57 +35,47 @@ use syn::{
/// Self: 'dynosaur;
/// }
/// ```
pub fn expand_trait_async_fns_to_dyn(item_trait: &ItemTrait) -> ItemTrait {
let mut item_trait = item_trait.clone();

for trait_item_fn in impl_trait_fns_iter(&mut item_trait.items) {
expand_async_fn_input(&item_trait.generics, trait_item_fn);
expand_async_fn_output(trait_item_fn);
remove_asyncness_from_fn(&mut trait_item_fn.sig);
pub(crate) fn expand_fn(item_trait_generics: &Generics, trait_item_fn: &mut TraitItemFn) {
if is_async_or_rpit(trait_item_fn) {
expand_fn_input(item_trait_generics, trait_item_fn);
expand_fn_output(trait_item_fn);
remove_fn_asyncness(&mut trait_item_fn.sig);
}

item_trait
// Remove default method if any for the erased trait
trait_item_fn.default = None;
}

fn impl_trait_fns_iter(
item_trait_items: &mut Vec<TraitItem>,
) -> impl Iterator<Item = &mut TraitItemFn> {
item_trait_items.iter_mut().filter_map(|item| match item {
TraitItem::Fn(
trait_item_fn @ TraitItemFn {
sig: Signature {
asyncness: Some(_), ..
},
..
pub(crate) fn is_async_or_rpit(trait_item_fn: &TraitItemFn) -> bool {
match trait_item_fn {
TraitItemFn {
sig: Signature {
asyncness: Some(_), ..
},
) => Some(trait_item_fn),
TraitItem::Fn(TraitItemFn {
..
} => true,
TraitItemFn {
sig:
Signature {
asyncness: None,
output: ReturnType::Type(_, ret),
..
},
..
}) => {
if matches!(**ret, Type::ImplTrait(_)) {
if let TraitItem::Fn(trait_item_fn) = item {
return Some(trait_item_fn);
}
}
None
} => {
matches!(**ret, Type::ImplTrait(_))
}
_ => None,
})
_ => false,
}
}

pub fn remove_asyncness_from_fn(sig: &mut Signature) {
pub fn remove_fn_asyncness(sig: &mut Signature) {
if let Some(asyncness) = sig.asyncness.take() {
sig.fn_token.span = asyncness.span;
}
}

fn expand_async_fn_input(item_trait_generics: &Generics, trait_item_fn: &mut TraitItemFn) {
fn expand_fn_input(item_trait_generics: &Generics, trait_item_fn: &mut TraitItemFn) {
let sig = &mut trait_item_fn.sig;

let mut lifetimes = CollectLifetimes::new();
Expand Down Expand Up @@ -164,15 +153,15 @@ fn expand_async_fn_input(item_trait_generics: &Generics, trait_item_fn: &mut Tra
}
}

fn expand_async_fn_output(trait_item_fn: &mut TraitItemFn) {
pub(crate) fn expand_fn_output(trait_item_fn: &mut TraitItemFn) {
let sig = &mut trait_item_fn.sig;

let (ret_arrow, ret) = expand_async_ret_ty(sig);
let (ret_arrow, ret) = expand_ret_ty(sig);
trait_item_fn.sig.output =
parse_quote! { #ret_arrow ::core::pin::Pin<Box<dyn #ret + 'dynosaur>> };
}

pub fn expand_async_ret_ty(sig: &Signature) -> (RArrow, TokenStream) {
pub(crate) fn expand_ret_ty(sig: &Signature) -> (RArrow, TokenStream) {
let is_async = sig.asyncness.is_some();

if is_async {
Expand Down
Loading

0 comments on commit 591a72c

Please sign in to comment.