4ldo2 / real-async-trait-rs Goto Github PK
View Code? Open in Web Editor NEWA proc macro for real async traits, using nightly-only existential types and generic associated types to work around the need for type erasure
License: Apache License 2.0
A proc macro for real async traits, using nightly-only existential types and generic associated types to work around the need for type erasure
License: Apache License 2.0
Is there a way to make a dyn Trait
object out of a type that impls a trait annotated with #[real_async_trait]
?
I'd like to be able to do something like:
#[real_async_trait]
trait Foo {
async fn foo();
}
struct Bar {
maybe_foo: Option<Box<dyn Foo>>,
}
When I try to do this, however, I get an error saying I need to specify the associated type for Foo::foo
.
The latest version currently on crates.io (0.0.2) does not incorporate PR #5 which is needed to use this crate with a recent compiler, therefore a new version should be pushed to crates.io.
Furthermore, the latest version of syn
now requires the extra-traits
feature to be enabled for some of the traits used in this crate.
Currently, compilation will fail with errors like:
error[E0277]: `AttrStyle` doesn't implement `Debug`
--> /home/nett/.cargo/git/checkouts/real-async-trait-rs-99511d8d826cde78/1789be6/src/lib.rs:559:9
|
559 | assert_eq!(attr.style, AttrStyle::Outer);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `AttrStyle` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `AttrStyle`
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
I was wondering what part currently fails if removing the type alias, as that could potentially bring us to stable rust, with GATs now stabilized.
It seems like the macro doesn't support implementing traits for structs with generic parameters like:
trait Foo {}
struct Bar<F: Foo> { f: F }
#[real_async_trait]
trait Bat {
async fn baz();
}
#[real_async_trait]
impl<F: Foo> Bat for Bar<F> {
async fn baz() { }
}
Compilation fails with the error
error: type parameter `F` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> src/main.rs:13:1
|
13 | #[real_async_trait]
| ^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `real_async_trait` (in Nightly builds, run with -Z macro-backtrace for more info)
Manually typing out the async trait definition and implementation works:
trait Foo {}
struct Bar<F: Foo> { f: F }
trait Bat {
type BazFuture<'a>: Future<Output = ()>;
fn baz<'a>() -> Self::BazFuture<'a>;
}
impl<F: Foo> Bat for Bar<F> {
type BazFuture<'a> = impl Future<Output = ()>;
fn baz<'a>() -> Self::BazFuture<'a> { async move { } }
}
If I have two implementations for async traits in one module, I get a compiler error:
error[E0428]: the name `__real_async_trait_impl` is defined multiple times
--> src/lib.rs:22:1
|
13 | #[real_async_trait]
| ------------------- previous definition of the module `__real_async_trait_impl` here
...
22 | #[real_async_trait]
| ^^^^^^^^^^^^^^^^^^^ `__real_async_trait_impl` redefined here
|
= note: `__real_async_trait_impl` must be defined only once in the type namespace of this module
= note: this error originates in the attribute macro `real_async_trait` (in Nightly builds, run with -Z macro-backtrace for more info)
I used this code:
#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]
use real_async_trait::real_async_trait;
#[real_async_trait]
trait X {
async fn nop<'a>(&'a self) -> ();
}
struct T {}
#[real_async_trait]
impl X for T {
async fn nop<'a>(&'a self) -> () {
()
}
}
struct T2 {}
#[real_async_trait]
impl X for T2 {
async fn nop<'a>(&'a self) -> () {
()
}
}
I used real-async-trait version 0.0.2 and rustc 1.57.0-nightly (485ced56b 2021-10-07)
.
generates invalid code after rust-lang/rust#89970
the generated code:
fn open< 'a>(& 'a mut self,path: & 'a[u8],flags:usize) -> Self::__real_async_trait_impl_TypeFor_open< 'a> ;
type __real_async_trait_impl_TypeFor_open< 'a> : ::core::future::Future<Output = Result<usize,Errno> > + 'a;
18 | #[real_async_trait]
| ^^^^^^^^^^^^^^^^^^^
...
21 | async fn open<'a>(&'a mut self, path: &'a [u8], flags: usize) -> Result<usize, Errno>;
| - help: add the required where clauses: `where Self: 'a`
the expected code:
fn open<'a>(&'a mut self, path: &'a [u8], flags: usize, ) -> Self::__real_async_trait_impl_TypeFor_opsen<'a>;
type __real_async_trait_impl_TypeFor_opsen<'a>: ::core::future::Future<Output = Result<usize, Errno>> + 'a where Self: 'a;
i'm not sure if this is solving the issue completely but it was ok in my case.
diff --git a/src/lib.rs b/src/lib.rs
index 1366b81..cc2ba22 100644
--- a/src/lib.rs
+++ b/src/lib.rs
use syn::{
AngleBracketedGenericArguments, AttrStyle, Attribute, Binding, Block, Expr, ExprAsync, FnArg,
GenericArgument, GenericParam, Generics, Ident, ImplItem, ImplItemType, ItemImpl, ItemTrait,
@@ -311,7 +315,30 @@ fn handle_item_impl(mut item: ItemImpl) -> TokenStream {
generics: Generics {
lt_token: Some(Token!(<)(Span::call_site())),
gt_token: Some(Token!(>)(Span::call_site())),
- where_clause: None,
+ where_clause: Some(WhereClause {
+ where_token: Where::default(),
+ predicates: function_lifetimes
+ .iter()
+ .cloned()
+ .map(|lifetimedef| {
+ WherePredicate::Type(PredicateType {
+ colon_token: Token!(:)(Span::call_site()),
+ lifetimes: None,
+ bounded_ty: Type::Path(TypePath {
+ qself: None,
+ path: Path {
+ leading_colon: None,
+ segments: Punctuated::from_iter([PathSegment {
+ ident: Ident::new("Self", Span::call_site()),
+ arguments: PathArguments::None,
+ }]),
+ },
+ }),
+ bounds: Punctuated::from_iter([TypeParamBound::Lifetime(lifetimedef.lifetime)]),
+ })
+ })
+ .collect(),
+ }),
params: function_lifetimes
.iter()
.cloned()
@@ -590,7 +617,30 @@ fn handle_item_trait(mut item: ItemTrait) -> TokenStream {
generics: Generics {
lt_token: Some(Token!(<)(Span::call_site())),
gt_token: Some(Token!(>)(Span::call_site())),
- where_clause: None,
+ where_clause: Some(WhereClause {
+ where_token: Where::default(),
+ predicates: function_lifetimes
+ .iter()
+ .cloned()
+ .map(|lifetimedef| {
+ WherePredicate::Type(PredicateType {
+ colon_token: Token!(:)(Span::call_site()),
+ lifetimes: None,
+ bounded_ty: Type::Path(TypePath {
+ qself: None,
+ path: Path {
+ leading_colon: None,
+ segments: Punctuated::from_iter([PathSegment {
+ ident: Ident::new("Self", Span::call_site()),
+ arguments: PathArguments::None,
+ }]),
+ },
+ }),
+ bounds: Punctuated::from_iter([TypeParamBound::Lifetime(lifetimedef.lifetime)]),
+ })
+ })
+ .collect(),
+ }),
params: function_lifetimes
.iter()
.cloned()
The generic_associated_types
is not only no longer marked incomplete but has in fact been stabilized and is no longer necessary to specify.
Please also consider updating the README accordingly.
Also, adding a return_position_impl_trait_in_trait
mode, enabled via optional feature on this crate, would be absolutely hilarious.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.