{"id":13566232,"url":"https://github.com/dtolnay/async-trait","last_synced_at":"2025-05-15T00:00:20.988Z","repository":{"id":35030407,"uuid":"198288319","full_name":"dtolnay/async-trait","owner":"dtolnay","description":"Type erasure for async trait methods","archived":false,"fork":false,"pushed_at":"2025-03-15T01:00:18.000Z","size":885,"stargazers_count":1975,"open_issues_count":6,"forks_count":87,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-05-07T23:30:50.622Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dtolnay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"dtolnay"}},"created_at":"2019-07-22T19:21:13.000Z","updated_at":"2025-05-07T20:56:15.000Z","dependencies_parsed_at":"2023-01-15T12:22:47.320Z","dependency_job_id":"e9a74bf7-88db-45f1-bffe-8f6dafed41f4","html_url":"https://github.com/dtolnay/async-trait","commit_stats":{"total_commits":527,"total_committers":18,"mean_commits":29.27777777777778,"dds":0.09677419354838712,"last_synced_commit":"eb4b03862554611ca431fa6195cda47cf4c3eb96"},"previous_names":[],"tags_count":90,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtolnay%2Fasync-trait","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtolnay%2Fasync-trait/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtolnay%2Fasync-trait/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtolnay%2Fasync-trait/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dtolnay","download_url":"https://codeload.github.com/dtolnay/async-trait/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252973682,"owners_count":21834107,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T13:02:05.022Z","updated_at":"2025-05-15T00:00:20.964Z","avatar_url":"https://github.com/dtolnay.png","language":"Rust","funding_links":["https://github.com/sponsors/dtolnay"],"categories":["Rust"],"sub_categories":[],"readme":"Async trait methods\n===================\n\n[\u003cimg alt=\"github\" src=\"https://img.shields.io/badge/github-dtolnay/async--trait-8da0cb?style=for-the-badge\u0026labelColor=555555\u0026logo=github\" height=\"20\"\u003e](https://github.com/dtolnay/async-trait)\n[\u003cimg alt=\"crates.io\" src=\"https://img.shields.io/crates/v/async-trait.svg?style=for-the-badge\u0026color=fc8d62\u0026logo=rust\" height=\"20\"\u003e](https://crates.io/crates/async-trait)\n[\u003cimg alt=\"docs.rs\" src=\"https://img.shields.io/badge/docs.rs-async--trait-66c2a5?style=for-the-badge\u0026labelColor=555555\u0026logo=docs.rs\" height=\"20\"\u003e](https://docs.rs/async-trait)\n[\u003cimg alt=\"build status\" src=\"https://img.shields.io/github/actions/workflow/status/dtolnay/async-trait/ci.yml?branch=master\u0026style=for-the-badge\" height=\"20\"\u003e](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)\n\nThe stabilization of async functions in traits in Rust 1.75 did not include\nsupport for using traits containing async functions as `dyn Trait`. Trying to\nuse dyn with an async trait produces the following error:\n\n```rust\npub trait Trait {\n    async fn f(\u0026self);\n}\n\npub fn make() -\u003e Box\u003cdyn Trait\u003e {\n    unimplemented!()\n}\n```\n\n```console\nerror[E0038]: the trait `Trait` is not dyn compatible\n --\u003e src/main.rs:5:22\n  |\n5 | pub fn make() -\u003e Box\u003cdyn Trait\u003e {\n  |                      ^^^^^^^^^ `Trait` is not dyn compatible\n  |\nnote: for a trait to be dyn compatible it needs to allow building a vtable\n      for more information, visit \u003chttps://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility\u003e\n --\u003e src/main.rs:2:14\n  |\n1 | pub trait Trait {\n  |           ----- this trait is not dyn compatible...\n2 |     async fn f(\u0026self);\n  |              ^ ...because method `f` is `async`\n  = help: consider moving `f` to another trait\n```\n\nThis crate provides an attribute macro to make async fn in traits work with dyn\ntraits.\n\nPlease refer to [*why async fn in traits are hard*][hard] for a deeper analysis\nof how this implementation differs from what the compiler and language deliver\nnatively.\n\n[hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/\n\n\u003cbr\u003e\n\n## Example\n\nThis example implements the core of a highly effective advertising platform\nusing async fn in a trait.\n\nThe only thing to notice here is that we write an `#[async_trait]` macro on top\nof traits and trait impls that contain async fn, and then they work. We get to\nhave `Vec\u003cBox\u003cdyn Advertisement + Sync\u003e\u003e` or `\u0026[\u0026dyn Advertisement]`, for\nexample.\n\n```rust\nuse async_trait::async_trait;\n\n#[async_trait]\ntrait Advertisement {\n    async fn run(\u0026self);\n}\n\nstruct Modal;\n\n#[async_trait]\nimpl Advertisement for Modal {\n    async fn run(\u0026self) {\n        self.render_fullscreen().await;\n        for _ in 0..4u16 {\n            remind_user_to_join_mailing_list().await;\n        }\n        self.hide_for_now().await;\n    }\n}\n\nstruct AutoplayingVideo {\n    media_url: String,\n}\n\n#[async_trait]\nimpl Advertisement for AutoplayingVideo {\n    async fn run(\u0026self) {\n        let stream = connect(\u0026self.media_url).await;\n        stream.play().await;\n\n        // Video probably persuaded user to join our mailing list!\n        Modal.run().await;\n    }\n}\n```\n\n\u003cbr\u003e\n\n## Supported features\n\nIt is the intention that all features of Rust traits should work nicely with\n\\#\\[async_trait\\], but the edge cases are numerous. *Please file an issue if you\nsee unexpected borrow checker errors, type errors, or warnings.* There is no use\nof `unsafe` in the expanded code, so rest assured that if your code compiles it\ncan't be that badly broken.\n\n- \u0026#128077;\u0026ensp;Self by value, by reference, by mut reference, or no self;\n- \u0026#128077;\u0026ensp;Any number of arguments, any return value;\n- \u0026#128077;\u0026ensp;Generic type parameters and lifetime parameters;\n- \u0026#128077;\u0026ensp;Associated types;\n- \u0026#128077;\u0026ensp;Having async and non-async functions in the same trait;\n- \u0026#128077;\u0026ensp;Default implementations provided by the trait;\n- \u0026#128077;\u0026ensp;Elided lifetimes.\n\n\u003cbr\u003e\n\n## Explanation\n\nAsync fns get transformed into methods that return `Pin\u003cBox\u003cdyn Future + Send +\n'async_trait\u003e\u003e` and delegate to an async block.\n\nFor example the `impl Advertisement for AutoplayingVideo` above would be\nexpanded as:\n\n```rust\nimpl Advertisement for AutoplayingVideo {\n    fn run\u003c'async_trait\u003e(\n        \u0026'async_trait self,\n    ) -\u003e Pin\u003cBox\u003cdyn std::future::Future\u003cOutput = ()\u003e + Send + 'async_trait\u003e\u003e\n    where\n        Self: Sync + 'async_trait,\n    {\n        Box::pin(async move {\n            /* the original method body */\n        })\n    }\n}\n```\n\n\u003cbr\u003e\n\n## Non-threadsafe futures\n\nNot all async traits need futures that are `dyn Future + Send`. To avoid having\nSend and Sync bounds placed on the async trait methods, invoke the async trait\nmacro as `#[async_trait(?Send)]` on both the trait and the impl blocks.\n\n\u003cbr\u003e\n\n## Elided lifetimes\n\nBe aware that async fn syntax does not allow lifetime elision outside of `\u0026` and\n`\u0026mut` references. (This is true even when not using #\\[async_trait\\].)\nLifetimes must be named or marked by the placeholder `'_`.\n\nFortunately the compiler is able to diagnose missing lifetimes with a good error\nmessage.\n\n```rust\ntype Elided\u003c'a\u003e = \u0026'a usize;\n\n#[async_trait]\ntrait Test {\n    async fn test(not_okay: Elided, okay: \u0026usize) {}\n}\n```\n\n```console\nerror[E0726]: implicit elided lifetime not allowed here\n --\u003e src/main.rs:9:29\n  |\n9 |     async fn test(not_okay: Elided, okay: \u0026usize) {}\n  |                             ^^^^^^- help: indicate the anonymous lifetime: `\u003c'_\u003e`\n```\n\nThe fix is to name the lifetime or use `'_`.\n\n```rust\n#[async_trait]\ntrait Test {\n    // either\n    async fn test\u003c'e\u003e(elided: Elided\u003c'e\u003e) {}\n    // or\n    async fn test(elided: Elided\u003c'_\u003e) {}\n}\n```\n\n\u003cbr\u003e\n\n#### License\n\n\u003csup\u003e\nLicensed under either of \u003ca href=\"LICENSE-APACHE\"\u003eApache License, Version\n2.0\u003c/a\u003e or \u003ca href=\"LICENSE-MIT\"\u003eMIT license\u003c/a\u003e at your option.\n\u003c/sup\u003e\n\n\u003cbr\u003e\n\n\u003csub\u003e\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this crate by you, as defined in the Apache-2.0 license, shall\nbe dual licensed as above, without any additional terms or conditions.\n\u003c/sub\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdtolnay%2Fasync-trait","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdtolnay%2Fasync-trait","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdtolnay%2Fasync-trait/lists"}