# Crate async_trait

source · [−]
Expand description

##### Type erasure for async trait methods

The initial round of stabilizations for the async/await language feature in Rust 1.39 did not include support for async fn in traits. Trying to include an async fn in a trait produces the following error:

ⓘ

    trait MyTrait {
        async fn f() {}
    }

    error[E0706]: trait fns cannot be declared `async`
     --> src/main.rs:4:5
      |
    4 |     async fn f() {}
      |     ^^^^^^^^^^^^^^^

This crate provides an attribute macro to make async fn in traits work.

Please refer to why async fn in traits are hard for a deeper analysis of how this implementation differs from what the compiler and language hope to deliver in the future.

## Example

This example implements the core of a highly effective advertising platform using async fn in a trait.

The only thing to notice here is that we write an `#[async_trait]` macro on top of traits and trait impls that contain async fn, and then they work.

    use async_trait::async_trait;

    #[async_trait]
    trait Advertisement {
        async fn run(&self);
    }

    struct Modal;

    #[async_trait]
    impl Advertisement for Modal {
        async fn run(&self) {
            self.render_fullscreen().await;
            for _ in 0..4u16 {
                remind_user_to_join_mailing_list().await;
            }
            self.hide_for_now().await;
        }
    }

    struct AutoplayingVideo {
        media_url: String,
    }

    #[async_trait]
    impl Advertisement for AutoplayingVideo {
        async fn run(&self) {
            let stream = connect(&self.media_url).await;
            stream.play().await;

            // Video probably persuaded user to join our mailing list!
            Modal.run().await;
        }
    }

## Supported features

It is the intention that all features of Rust traits should work nicely with #[async_trait], but the edge cases are numerous. Please file an issue if you see unexpected borrow checker errors, type errors, or warnings. There is no use of `unsafe` in the expanded code, so rest assured that if your code compiles it can’t be that badly broken.

> ☑ Self by value, by reference, by mut reference, or no self;
> ☑ Any number of arguments, any return value;
> ☑ Generic type parameters and lifetime parameters;
> ☑ Associated types;
> ☑ Having async and non-async functions in the same trait;
> ☑ Default implementations provided by the trait;
> ☑ Elided lifetimes;
> ☑ Dyn-capable traits.

## Explanation

Async fns get transformed into methods that return `Pin<Box<dyn Future + Send + 'async>>` and delegate to a private async freestanding function.

For example the `impl Advertisement for AutoplayingVideo` above would be expanded as:

    impl Advertisement for AutoplayingVideo {
        fn run<'async>(
            &'async self,
        ) -> Pin<Box<dyn core::future::Future<Output = ()> + Send + 'async>>
        where
            Self: Sync + 'async,
        {
            async fn run(_self: &AutoplayingVideo) {
                /* the original method body */
            }

            Box::pin(run(self))
        }
    }

## Non-threadsafe futures

Not all async traits need futures that are `dyn Future + Send`. To avoid having Send and Sync bounds placed on the async trait methods, invoke the async trait macro as `#[async_trait(?Send)]` on both the trait and the impl blocks.

## Elided lifetimes

Be aware that async fn syntax does not allow lifetime elision outside of `&` and `&mut` references. (This is true even when not using #[async_trait].) Lifetimes must be named or marked by the placeholder `'_`.

Fortunately the compiler is able to diagnose missing lifetimes with a good error message.

ⓘ

    type Elided<'a> = &'a usize;

    #[async_trait]
    trait Test {
        async fn test(not_okay: Elided, okay: &usize) {}
    }

    error[E0726]: implicit elided lifetime not allowed here
     --> src/main.rs:9:29
      |
    9 |     async fn test(not_okay: Elided, okay: &usize) {}
      |                             ^^^^^^- help: indicate the anonymous lifetime: `<'_>`

The fix is to name the lifetime or use `'_`.

    #[async_trait]
    trait Test {
        // either
        async fn test<'e>(elided: Elided<'e>) {}
        // or
        async fn test(elided: Elided<'_>) {}
    }

## Dyn traits

Traits with async methods can be used as trait objects as long as they meet the usual requirements for dyn – no methods with type parameters, no self by value, no associated types, etc.

    #[async_trait]
    pub trait ObjectSafe {
        async fn f(&self);
        async fn g(&mut self);
    }

    impl ObjectSafe for MyType {...}

    let value: MyType = ...;
    let object = &value as &dyn ObjectSafe;  // make trait object

The one wrinkle is in traits that provide default implementations of async methods. In order for the default implementation to produce a future that is Send, the async_trait macro must emit a bound of `Self: Sync` on trait methods that take `&self` and a bound `Self: Send` on trait methods that take `&mut self`. An example of the former is visible in the expanded code in the explanation section above.

If you make a trait with async methods that have default implementations, everything will work except that the trait cannot be used as a trait object. Creating a value of type `&dyn Trait` will produce an error that looks like this:

    error: the trait `Test` cannot be made into an object
     --> src/main.rs:8:5
      |
    8 |     async fn cannot_dyn(&self) {}
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

For traits that need to be object safe and need to have default implementations for some async methods, there are two resolutions. Either you can add Send and/or Sync as supertraits (Send if there are `&mut self` methods with default implementations, Sync if there are `&self` methods with default implementations) to constrain all implementors of the trait such that the default implementations are applicable to them:

    #[async_trait]
    pub trait ObjectSafe: Sync {  // added supertrait
        async fn can_dyn(&self) {}
    }

    let object = &value as &dyn ObjectSafe;

or you can strike the problematic methods from your trait object by bounding them with `Self: Sized`:

    #[async_trait]
    pub trait ObjectSafe {
        async fn cannot_dyn(&self) where Self: Sized {}

        // presumably other methods
    }

    let object = &value as &dyn ObjectSafe;

## Attribute Macros

async_trait