Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement trait for async-trait instance method #167

Closed
ebkalderon opened this issue Jun 1, 2021 · 4 comments
Closed

Implement trait for async-trait instance method #167

ebkalderon opened this issue Jun 1, 2021 · 4 comments

Comments

@ebkalderon
Copy link

I'm running into the following apparent edge case with async-trait where a generic trait is being implemented for inherent async fn instance methods, but not on async-trait instance methods:

pub struct Service;

// This inherent `async fn` implements `Handler<S, P, R>` and is accepted by `Router::define_method`.
impl Service {
    async fn my_handler(&self) -> Result<(), ()> {
        Ok(())
    }
}

// But this async trait method is rejected if you replace the above code with the below.
//
// #[async_trait]
// trait MyHandlers {
//     async fn my_handler(&self) -> Result<(), ()>;
// }
//
// #[async_trait]
// impl MyHandlers for Service {
//     async fn my_handler(&self) -> Result<(), ()> {
//         Ok(())
//     }
// }

fn main() {
    let mut router = Router::new(Service);
    router.define_method("my_handler", Service::my_handler);
}

See the playground link for the minimal reproducible example.

It seems odd that the Handler trait isn't being implemented for methods generated by async-trait. I believe the included blanket impls should cover methods returning impl Future<Output = _>> + Send and Pin<Box<dyn Future<Output = _> + Send>> equally. Any ideas why this could be?

Might be related to #47, but I'm not sure. That issue is more about implementing an async-trait on top of any Fn() -> Fut, while this issue is getting a regular trait to apply equally to both inherent async fn and async-trait methods, but there could possibly be some overlap.

@ebkalderon
Copy link
Author

ebkalderon commented Jun 10, 2021

After a bit more investigation, I believe this might indirectly be caused by rust-lang/rust#64552, the same rustc bug that caused #141. Attempting to reduce this example any further runs into similar error messages quite a lot.

EDIT: My example seems strikingly similar to rust-lang/rust#64552 (comment).

@ebkalderon
Copy link
Author

ebkalderon commented Jun 13, 2021

Interestingly, this simplified example actually works as expected: Playground link

As soon as I try to use higher-kinded lifetimes and wrap the receiver in an Arc , then the lifetimes refuse to match up.

@ebkalderon
Copy link
Author

A temporary workaround I've found is to wrap the trait method in a regular async fn like so:

async fn my_handler<T: MyHandlers>(receiver: &T) -> Result<(), ()> {
    receiver.my_handler(arg).await
}

router.define_method("my_handler", my_handler); // This works!

@dtolnay
Copy link
Owner

dtolnay commented Mar 25, 2022

I'm glad you found a workaround. I am going to close this issue in favor of rust-lang/rust#64552, since I believe this is a compiler bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants