├── .gitignore ├── examples ├── test.rs ├── no_self.rs ├── self_by_value.rs ├── self_by_mut_ref.rs ├── generic_arguments.rs ├── any_type_self.rs ├── ass_type.rs ├── generic_return.rs ├── self_by_mut_value.rs ├── self_by_ref.rs └── test_ritit.rs ├── Cargo.toml ├── src ├── lib.rs ├── parse.rs ├── async_trait.rs └── ritit.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /examples/test.rs: -------------------------------------------------------------------------------- 1 | #![feature(type_alias_impl_trait)] 2 | #![feature(generic_associated_types)] 3 | 4 | 5 | fn main() {} -------------------------------------------------------------------------------- /examples/no_self.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | 8 | #[async_trait] 9 | trait AsyncFnTrait { 10 | async fn run(); 11 | } 12 | 13 | struct AsyncStruct; 14 | 15 | async fn hello() -> u8 { 16 | 1 17 | } 18 | 19 | #[async_trait] 20 | impl AsyncFnTrait for AsyncStruct { 21 | async fn run() { 22 | hello().await; 23 | } 24 | } 25 | 26 | fn main() {} 27 | -------------------------------------------------------------------------------- /examples/self_by_value.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | 8 | #[async_trait] 9 | trait AsyncFnTrait { 10 | async fn run(self); 11 | } 12 | 13 | struct AsyncStruct; 14 | 15 | impl AsyncStruct { 16 | async fn hello(&self) -> u8 { 17 | 1 18 | } 19 | } 20 | 21 | #[async_trait] 22 | impl AsyncFnTrait for AsyncStruct { 23 | async fn run(self) { 24 | self.hello().await; 25 | } 26 | } 27 | 28 | fn main() {} 29 | -------------------------------------------------------------------------------- /examples/self_by_mut_ref.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | 8 | #[async_trait] 9 | trait AsyncFnTrait { 10 | async fn run(&mut self); 11 | } 12 | 13 | struct AsyncStruct; 14 | 15 | impl AsyncStruct { 16 | async fn hello(&self) -> u8 { 17 | 1 18 | } 19 | } 20 | 21 | #[async_trait] 22 | impl AsyncFnTrait for AsyncStruct { 23 | async fn run(&mut self) { 24 | self.hello().await; 25 | } 26 | } 27 | 28 | fn main() {} 29 | -------------------------------------------------------------------------------- /examples/generic_arguments.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | 8 | #[async_trait] 9 | trait AsyncFnTrait { 10 | async fn run(&self, t: T); 11 | } 12 | 13 | struct AsyncStruct; 14 | 15 | impl AsyncStruct { 16 | async fn hello(&self) -> u8 { 17 | 1 18 | } 19 | } 20 | 21 | #[async_trait] 22 | impl AsyncFnTrait for AsyncStruct { 23 | async fn run(&self, t: T) { 24 | self.hello().await; 25 | } 26 | } 27 | 28 | fn main() {} 29 | -------------------------------------------------------------------------------- /examples/any_type_self.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | use std::boxed::Box; 8 | 9 | #[async_trait] 10 | trait AsyncFnTrait { 11 | async fn run(s: Box); 12 | } 13 | 14 | struct AsyncStruct; 15 | 16 | impl AsyncStruct { 17 | async fn hello(&self) -> u8 { 18 | 1 19 | } 20 | } 21 | 22 | #[async_trait] 23 | impl AsyncFnTrait for AsyncStruct { 24 | async fn run(s: Box) { 25 | s.hello().await; 26 | } 27 | } 28 | 29 | fn main() {} 30 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-trait-static" 3 | version = "0.1.4" 4 | authors = ["tiannian "] 5 | edition = "2018" 6 | description = "async fn in trait for no_std" 7 | license = "MIT" 8 | readme = "README.md" 9 | repository = "https://github.com/tiannian/async-trait-static" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | syn = { version = "1.0", features = ["full", "visit-mut", "extra-traits", "parsing"] } 15 | quote = "1.0" 16 | proc-macro2 = "1.0" 17 | convert_case = "0.4.0" 18 | 19 | [lib] 20 | proc-macro = true 21 | 22 | -------------------------------------------------------------------------------- /examples/ass_type.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | 8 | #[async_trait] 9 | trait AsyncFnTrait { 10 | type A; 11 | async fn run(self, a: Self::A) -> Self::A; 12 | } 13 | 14 | struct AsyncStruct; 15 | 16 | impl AsyncStruct { 17 | async fn hello(&self) -> u8 { 18 | 1 19 | } 20 | } 21 | 22 | #[async_trait] 23 | impl AsyncFnTrait for AsyncStruct { 24 | type A = u8; 25 | async fn run(self, a: Self::A) -> Self::A { 26 | self.hello().await; 27 | a 28 | } 29 | } 30 | 31 | fn main() {} 32 | -------------------------------------------------------------------------------- /examples/generic_return.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | use core::fmt::Display; 8 | 9 | #[async_trait] 10 | trait AsyncFnTrait { 11 | async fn run(&self, t: T) -> T; 12 | } 13 | 14 | struct AsyncStruct; 15 | 16 | impl AsyncStruct { 17 | async fn hello(&self) -> u8 { 18 | 1 19 | } 20 | } 21 | 22 | #[async_trait] 23 | impl AsyncFnTrait for AsyncStruct { 24 | async fn run(&self, t: T) -> T { 25 | self.hello().await; 26 | t 27 | } 28 | } 29 | 30 | fn main() {} 31 | -------------------------------------------------------------------------------- /examples/self_by_mut_value.rs: -------------------------------------------------------------------------------- 1 | // Can't compile. 2 | // Due to `#[deny(patterns_in_fns_without_body)]` 3 | 4 | #![feature(type_alias_impl_trait)] 5 | #![feature(generic_associated_types)] 6 | 7 | // use async_trait_static::async_trait; 8 | 9 | // #[async_trait] 10 | // trait AsyncFnTrait { 11 | // async fn run(mut self); 12 | // } 13 | 14 | // struct AsyncStruct; 15 | 16 | // impl AsyncStruct { 17 | // async fn hello(self) -> u8 { 18 | // 1 19 | // } 20 | // } 21 | 22 | // #[async_trait] 23 | // impl AsyncFnTrait for AsyncStruct { 24 | // async fn run(mut self) { 25 | // self.hello().await; 26 | // } 27 | // } 28 | 29 | fn main() {} 30 | -------------------------------------------------------------------------------- /examples/self_by_ref.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::async_trait; 7 | 8 | #[async_trait] 9 | trait AsyncFnTrait { 10 | async fn run(&self) -> &u8; 11 | 12 | async fn deff(&self) -> u8 { 13 | 1 14 | } 15 | 16 | // async fn ret_value(&self) -> &[u8]; 17 | } 18 | 19 | struct AsyncStruct; 20 | 21 | impl AsyncStruct { 22 | async fn hello(&self) -> u8 { 23 | 1 24 | } 25 | } 26 | 27 | #[async_trait] 28 | impl AsyncFnTrait for AsyncStruct { 29 | async fn run(&self) -> &u8 { 30 | self.hello().await; 31 | &0 32 | } 33 | } 34 | 35 | fn main() {} 36 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod async_trait; 2 | mod parse; 3 | mod ritit; 4 | // mod selector; 5 | 6 | use parse::Item; 7 | use proc_macro::TokenStream; 8 | use quote::quote; 9 | use syn::parse_macro_input; 10 | 11 | #[proc_macro_attribute] 12 | pub fn async_trait(_arg: TokenStream, input: TokenStream) -> TokenStream { 13 | let mut item = parse_macro_input!(input as Item); 14 | async_trait::expand(&mut item); 15 | let tk = quote! { 16 | #item 17 | }; 18 | let impl_tk = TokenStream::from(tk); 19 | ritit(_arg, impl_tk) 20 | } 21 | 22 | #[proc_macro_attribute] 23 | pub fn ritit(_arg: TokenStream, input: TokenStream) -> TokenStream { 24 | let item = parse_macro_input!(input as Item); 25 | ritit::expand(item) 26 | } 27 | -------------------------------------------------------------------------------- /examples/test_ritit.rs: -------------------------------------------------------------------------------- 1 | //Compiled 2 | 3 | #![feature(type_alias_impl_trait)] 4 | #![feature(generic_associated_types)] 5 | 6 | use async_trait_static::ritit; 7 | 8 | #[ritit] 9 | trait AsyncFnTrait { 10 | fn run(&self, t: T) -> impl core::future::Future; 11 | fn deff(&self) -> impl core::future::Future { 12 | async move { 1 } 13 | } 14 | } 15 | 16 | struct AsyncStruct; 17 | 18 | impl AsyncStruct { 19 | async fn hello(&self) -> u8 { 20 | 1 21 | } 22 | } 23 | 24 | #[ritit] 25 | impl AsyncFnTrait for AsyncStruct { 26 | fn run(&self, t: T) -> impl core::future::Future { 27 | async move { 28 | self.hello().await; 29 | } 30 | } 31 | } 32 | 33 | fn main() {} 34 | -------------------------------------------------------------------------------- /src/parse.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Span, TokenStream}; 2 | use quote::ToTokens; 3 | use syn::parse::{Error, Parse, ParseStream, Result}; 4 | use syn::{Attribute, ItemImpl, ItemTrait, Token}; 5 | 6 | pub struct Nothing; 7 | 8 | impl Parse for Nothing { 9 | fn parse(_input: ParseStream) -> Result { 10 | Ok(Nothing) 11 | } 12 | } 13 | 14 | pub enum Item { 15 | Trait(ItemTrait), 16 | Impl(ItemImpl), 17 | } 18 | 19 | impl Parse for Item { 20 | fn parse(input: ParseStream) -> Result { 21 | let attrs = input.call(Attribute::parse_outer)?; 22 | let mut lookahead = input.lookahead1(); 23 | if lookahead.peek(Token![unsafe]) { 24 | let ahead = input.fork(); 25 | ahead.parse::()?; 26 | lookahead = ahead.lookahead1(); 27 | } 28 | if lookahead.peek(Token![pub]) || lookahead.peek(Token![trait]) { 29 | let mut item: ItemTrait = input.parse()?; 30 | item.attrs = attrs; 31 | Ok(Item::Trait(item)) 32 | } else if lookahead.peek(Token![impl]) { 33 | let mut item: ItemImpl = input.parse()?; 34 | if item.trait_.is_none() { 35 | return Err(Error::new(Span::call_site(), "expected a trait impl")); 36 | } 37 | item.attrs = attrs; 38 | Ok(Item::Impl(item)) 39 | } else { 40 | Err(lookahead.error()) 41 | } 42 | } 43 | } 44 | 45 | impl ToTokens for Item { 46 | fn to_tokens(&self, tokens: &mut TokenStream) { 47 | match self { 48 | Item::Trait(item) => item.to_tokens(tokens), 49 | Item::Impl(item) => item.to_tokens(tokens), 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/async_trait.rs: -------------------------------------------------------------------------------- 1 | use crate::Item; 2 | use syn::parse_quote; 3 | use syn::{ImplItem, ImplItemMethod, ReturnType, TraitItem, TraitItemMethod, Type}; 4 | 5 | fn process_signature_return(return_type: &mut ReturnType) { 6 | match return_type { 7 | ReturnType::Default => { 8 | *return_type = parse_quote! { 9 | -> impl core::future::Future 10 | } 11 | } 12 | ReturnType::Type(_rarrow, ty) => { 13 | if let Type::Reference(t) = &mut **ty { 14 | if t.lifetime.is_none() { 15 | t.lifetime = Some(parse_quote!('_async_lifetime)); 16 | *return_type = parse_quote! { 17 | -> impl core::future::Future 18 | } 19 | } 20 | } else { 21 | *return_type = parse_quote! { 22 | -> impl core::future::Future 23 | } 24 | } 25 | } 26 | } 27 | } 28 | 29 | fn process_trait_method(item: &mut TraitItemMethod) { 30 | item.sig.asyncness = None; 31 | process_signature_return(&mut item.sig.output); 32 | if let Some(block) = &mut item.default { 33 | *block = parse_quote! { 34 | { 35 | async move #block 36 | } 37 | } 38 | } 39 | } 40 | 41 | fn process_impl_method(item: &mut ImplItemMethod) { 42 | item.sig.asyncness = None; 43 | process_signature_return(&mut item.sig.output); 44 | let block = item.block.clone(); 45 | item.block = parse_quote! { 46 | { 47 | async move #block 48 | } 49 | } 50 | } 51 | 52 | pub fn expand(input: &mut Item) { 53 | match input { 54 | Item::Trait(input) => { 55 | for item in &mut input.items { 56 | match item { 57 | TraitItem::Method(method) => process_trait_method(method), 58 | _ => (), 59 | }; 60 | } 61 | } 62 | Item::Impl(input) => { 63 | for item in &mut input.items { 64 | match item { 65 | ImplItem::Method(method) => process_impl_method(method), 66 | _ => (), 67 | } 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Async trait methods for `no_std` 2 | 3 | Features like `async-trait`, avoid using `Box` and `dyn`. You can use async keywork in trait without alloc. 4 | 5 | Thanks to crate [async-trait](https://github.com/dtolnay/async-trait), some code from these. 6 | 7 | WARNING: This crate use some unstable even incomplete feature. You will get some warning from compiler. 8 | 9 | If you want to use crate, please add `#![feature(type_alias_impl_trait)]` and `#![feature(generic_associated_types)]` 10 | to you crate's root file. 11 | 12 | This crate support `async` in trait through `#[async_trait]` and sup 13 | 14 | ## Support syntax 15 | 16 | - `async` in trait. `#[async_trait]`. 17 | - `impl trait` as return in trait. `#[ritit]`. 18 | 19 | ## Features Status 20 | 21 | - [X] `Self` 22 | - [X] `Self` by reference. 23 | - [X] `Self` by value. 24 | - [X] `Self` by mut reference. 25 | - [X] no `Self`. 26 | - [X] any type of `Self`. (need test) 27 | - [ ] `Self` by mut value. (It seems unimplementable) 28 | - [X] Any number of arguments, any return value. 29 | - [X] Arguments. 30 | - [X] As value. 31 | - [X] As reference without lifetime. 32 | - [X] Return value expect reference (return reference at `Lifetime return`). (need test) 33 | - [ ] Lifetime parameters. (need test) 34 | - [ ] Lifetime arguments. 35 | - [ ] Lifetime return. 36 | - [X] Associated types support. (need test) 37 | - [X] Having async and non-async functions in the same trait. 38 | - [X] support default `async fn` implementations in trait. 39 | - [X] Generic type parameters. 40 | - [X] Generic arguments. 41 | - [X] Generic return. 42 | - [ ] `impl trait` in arguments. (need implement) 43 | 44 | ## Usage 45 | 46 | Please enable feature `type_alias_impl_trait` and `generic_associated_types`; 47 | 48 | ### async_trait 49 | 50 | ```rust 51 | #![feature(type_alias_impl_trait)] 52 | #![feature(generic_associated_types)] 53 | 54 | use async_trait_static::async_trait; 55 | 56 | async fn hello() -> u8 { 57 | 1 58 | } 59 | 60 | #[async_trait] 61 | trait AsyncFnTrait { 62 | async fn run(&self); 63 | } 64 | 65 | struct AsyncStruct; 66 | 67 | #[async_trait] 68 | impl AsyncFnTrait for AsyncStruct { 69 | async fn run(&self) { 70 | hello().await; 71 | } 72 | } 73 | 74 | ``` 75 | 76 | ### ritit 77 | ```rust 78 | #![feature(type_alias_impl_trait)] 79 | #![feature(generic_associated_types)] 80 | 81 | use async_trait_static::ritit; 82 | 83 | #[ritit] 84 | trait AsyncFnTrait { 85 | fn run(&self, t: T) -> impl core::future::Future; 86 | fn deff(&self) -> impl core::future::Future { 87 | async move { 1 } 88 | } 89 | } 90 | 91 | struct AsyncStruct; 92 | 93 | impl AsyncStruct { 94 | async fn hello(&self) -> u8 { 95 | 1 96 | } 97 | } 98 | 99 | #[ritit] 100 | impl AsyncFnTrait for AsyncStruct { 101 | fn run(&self, t: T) -> impl core::future::Future { 102 | async move { 103 | self.hello().await; 104 | } 105 | } 106 | } 107 | ``` 108 | 109 | -------------------------------------------------------------------------------- /src/ritit.rs: -------------------------------------------------------------------------------- 1 | use crate::Item; 2 | use proc_macro::TokenStream; 3 | use quote::quote; 4 | use syn::punctuated::Punctuated; 5 | // use syn::token::Add; 6 | use convert_case::{Case, Casing}; 7 | use proc_macro2::Span; 8 | use syn::{ 9 | parse_quote, FnArg, GenericParam, Ident, ImplItem, ItemImpl, ItemTrait, ReturnType, Signature, 10 | Token, TraitItem, TraitItemType, Type, TypeParamBound, Stmt 11 | }; 12 | 13 | fn get_return_bounds(return_type: &ReturnType) -> Option> { 14 | if let ReturnType::Type(_rarrow, ty) = return_type { 15 | if let Type::ImplTrait(impl_trait) = &**ty { 16 | return Some(impl_trait.bounds.clone()); 17 | } 18 | } 19 | None 20 | } 21 | 22 | fn get_generics(sig: &Signature) -> Punctuated { 23 | let mut generics = Punctuated::::new(); 24 | 25 | for generic in &sig.generics.params { 26 | if let GenericParam::Type(tp) = generic { 27 | let ident = &tp.ident; 28 | let gp: GenericParam = parse_quote!(#ident); 29 | generics.push(gp); 30 | } 31 | 32 | if let GenericParam::Lifetime(_) = generic { 33 | generics.push(generic.clone()); 34 | } 35 | } 36 | 37 | generics 38 | } 39 | 40 | fn modify_receiver(sig: &mut Signature) { 41 | let receiver = sig.receiver(); 42 | if receiver.is_some() { 43 | let mut rr = receiver.unwrap().clone(); 44 | if let FnArg::Receiver(r) = &mut rr { 45 | if r.reference.is_some() { 46 | r.reference.as_mut().unwrap().1 = parse_quote!('_async_lifetime); 47 | sig.inputs[0] = rr; 48 | } 49 | } 50 | } 51 | } 52 | 53 | fn process_trait(mut input: ItemTrait) -> TokenStream { 54 | let mut asses = Vec::new(); 55 | let mut funcs = Vec::new(); 56 | let mut stmts = Vec::new(); 57 | for item in &mut input.items { 58 | if let TraitItem::Method(method) = item { 59 | if let Some(bounds) = get_return_bounds(&method.sig.output) { 60 | let name = String::from("RititReturn") 61 | + &method.sig.ident.to_string().to_case(Case::Pascal); 62 | let type_name = Ident::new(&name, Span::call_site()); 63 | 64 | let generics = get_generics(&method.sig); 65 | 66 | modify_receiver(&mut method.sig); 67 | 68 | let mut func = method.clone(); 69 | 70 | let associated_type: TraitItemType = parse_quote! { 71 | type #type_name<'_async_lifetime, #generics>: #bounds; 72 | }; 73 | 74 | if let Some(_) = &method.default { 75 | if func.sig.generics.where_clause.is_none() { 76 | func.sig.generics.where_clause = parse_quote!(where Self: Sized); 77 | } else { 78 | func.sig.generics.where_clause.as_mut().unwrap().predicates.push(parse_quote!(Self: Sized)); 79 | } 80 | let stmt: Stmt = parse_quote!(type #type_name<'_async_lifetime, RititS, #generics> = impl #bounds;); 81 | stmts.push(stmt); 82 | func.sig.output = parse_quote!(-> #type_name<'_async_lifetime, Self, #generics>); 83 | 84 | } else { 85 | func.sig.output = parse_quote!(-> Self::#type_name<'_async_lifetime, #generics>); 86 | asses.push(TraitItem::Type(associated_type)); 87 | } 88 | 89 | let async_lifetime: GenericParam = parse_quote!('_async_lifetime); 90 | func.sig.generics.params.insert(0, async_lifetime); 91 | funcs.push(TraitItem::Method(func)); 92 | } 93 | } else { 94 | asses.push(item.clone()); 95 | } 96 | } 97 | 98 | asses.append(&mut funcs); 99 | 100 | input.items = asses; 101 | 102 | let tk = quote! { 103 | #(#stmts)* 104 | #input 105 | }; 106 | TokenStream::from(tk) 107 | } 108 | 109 | fn process_impl(mut input: ItemImpl) -> TokenStream { 110 | let mut asses = Vec::new(); 111 | let mut funcs = Vec::new(); 112 | // let struct_name = input. 113 | for item in &mut input.items { 114 | if let ImplItem::Method(method) = item { 115 | if let Some(bounds) = get_return_bounds(&method.sig.output) { 116 | let name = String::from("RititReturn") 117 | + &method.sig.ident.to_string().to_case(Case::Pascal); 118 | let type_name = Ident::new(&name, Span::call_site()); 119 | 120 | let generics = get_generics(&method.sig); 121 | 122 | modify_receiver(&mut method.sig); 123 | 124 | let mut func = method.clone(); 125 | func.sig.output = parse_quote!(-> Self::#type_name<'_async_lifetime, #generics>); 126 | let async_lifetime: GenericParam = parse_quote!('_async_lifetime); 127 | func.sig.generics.params.insert(0, async_lifetime); 128 | funcs.push(ImplItem::Method(func)); 129 | 130 | let associated_type: ImplItem = parse_quote! { 131 | type #type_name<'_async_lifetime, #generics> = impl #bounds; 132 | }; 133 | asses.push(associated_type); 134 | } 135 | } else { 136 | asses.push(item.clone()); 137 | } 138 | } 139 | 140 | asses.append(&mut funcs); 141 | 142 | input.items = asses; 143 | 144 | let tk = quote! { 145 | #input 146 | }; 147 | 148 | TokenStream::from(tk) 149 | } 150 | 151 | pub fn expand(input: Item) -> TokenStream { 152 | 153 | match input { 154 | Item::Trait(i) => process_trait(i), 155 | Item::Impl(i) => process_impl(i), 156 | } 157 | } 158 | --------------------------------------------------------------------------------