async-trait-0.1.83/.cargo_vcs_info.json0000644000000001360000000000100133630ustar { "git": { "sha1": "e6b4d471c64156338fb87386b7a7ad8543c3a205" }, "path_in_vcs": "" }async-trait-0.1.83/.github/FUNDING.yml000064400000000000000000000000201046102023000153200ustar 00000000000000github: dtolnay async-trait-0.1.83/.github/workflows/ci.yml000064400000000000000000000052501046102023000166700ustar 00000000000000name: CI on: push: pull_request: workflow_dispatch: schedule: [cron: "40 1 * * *"] permissions: contents: read env: RUSTFLAGS: -Dwarnings jobs: pre_ci: uses: dtolnay/.github/.github/workflows/pre_ci.yml@master test: name: Rust ${{matrix.rust}} needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest strategy: fail-fast: false matrix: rust: [nightly, beta, stable, 1.56.0] timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} - name: Enable type layout randomization run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV if: matrix.rust == 'nightly' - name: Enable nightly-only tests run: echo RUSTFLAGS=${RUSTFLAGS}\ --cfg=async_trait_nightly_testing >> $GITHUB_ENV if: matrix.rust == 'nightly' - run: cargo test - uses: actions/upload-artifact@v4 if: matrix.rust == 'nightly' && always() with: name: Cargo.lock path: Cargo.lock minimal: name: Minimal versions needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly - run: cargo generate-lockfile -Z minimal-versions - run: cargo check --locked doc: name: Documentation needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 env: RUSTDOCFLAGS: -Dwarnings steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-docs-rs - run: cargo docs-rs clippy: name: Clippy runs-on: ubuntu-latest if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic miri: name: Miri needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@miri - run: cargo miri setup - run: cargo miri test env: MIRIFLAGS: -Zmiri-strict-provenance outdated: name: Outdated runs-on: ubuntu-latest if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: dtolnay/install@cargo-outdated - run: cargo outdated --workspace --exit-code 1 async-trait-0.1.83/.gitignore000064400000000000000000000000361046102023000141420ustar 00000000000000/target **/*.rs.bk Cargo.lock async-trait-0.1.83/Cargo.toml0000644000000034060000000000100113640ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56" name = "async-trait" version = "0.1.83" authors = ["David Tolnay "] build = false exclude = ["build.rs"] autobins = false autoexamples = false autotests = false autobenches = false description = "Type erasure for async trait methods" documentation = "https://docs.rs/async-trait" readme = "README.md" keywords = ["async"] categories = [ "asynchronous", "no-std", ] license = "MIT OR Apache-2.0" repository = "https://github.com/dtolnay/async-trait" [package.metadata.docs.rs] rustdoc-args = ["--generate-link-to-definition"] targets = ["x86_64-unknown-linux-gnu"] [lib] name = "async_trait" path = "src/lib.rs" proc-macro = true [[test]] name = "compiletest" path = "tests/compiletest.rs" [[test]] name = "test" path = "tests/test.rs" [dependencies.proc-macro2] version = "1.0.74" [dependencies.quote] version = "1.0.35" [dependencies.syn] version = "2.0.46" features = [ "full", "parsing", "printing", "proc-macro", "visit-mut", ] default-features = false [dev-dependencies.futures] version = "0.3.30" [dev-dependencies.rustversion] version = "1.0.13" [dev-dependencies.tracing] version = "0.1.40" [dev-dependencies.tracing-attributes] version = "0.1.27" [dev-dependencies.trybuild] version = "1.0.81" features = ["diff"] async-trait-0.1.83/Cargo.toml.orig000064400000000000000000000015741046102023000150510ustar 00000000000000[package] name = "async-trait" version = "0.1.83" authors = ["David Tolnay "] categories = ["asynchronous", "no-std"] description = "Type erasure for async trait methods" documentation = "https://docs.rs/async-trait" edition = "2021" exclude = ["build.rs"] keywords = ["async"] license = "MIT OR Apache-2.0" repository = "https://github.com/dtolnay/async-trait" rust-version = "1.56" [lib] proc-macro = true [dependencies] proc-macro2 = "1.0.74" quote = "1.0.35" syn = { version = "2.0.46", default-features = false, features = ["full", "parsing", "printing", "proc-macro", "visit-mut"] } [dev-dependencies] futures = "0.3.30" rustversion = "1.0.13" tracing = "0.1.40" tracing-attributes = "0.1.27" trybuild = { version = "1.0.81", features = ["diff"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = ["--generate-link-to-definition"] async-trait-0.1.83/LICENSE-APACHE000064400000000000000000000227731046102023000141120ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS async-trait-0.1.83/LICENSE-MIT000064400000000000000000000017771046102023000136230ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. async-trait-0.1.83/README.md000064400000000000000000000201131046102023000134270ustar 00000000000000Async trait methods =================== [github](https://github.com/dtolnay/async-trait) [crates.io](https://crates.io/crates/async-trait) [docs.rs](https://docs.rs/async-trait) [build status](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster) The stabilization of async functions in traits in Rust 1.75 did not include support for using traits containing async functions as `dyn Trait`. Trying to use dyn with an async trait produces the following error: ```rust pub trait Trait { async fn f(&self); } pub fn make() -> Box { unimplemented!() } ``` ```console error[E0038]: the trait `Trait` cannot be made into an object --> src/main.rs:5:22 | 5 | pub fn make() -> Box { | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> src/main.rs:2:14 | 1 | pub trait Trait { | ----- this trait cannot be made into an object... 2 | async fn f(&self); | ^ ...because method `f` is `async` = help: consider moving `f` to another trait ``` This crate provides an attribute macro to make async fn in traits work with dyn traits. Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis of how this implementation differs from what the compiler and language deliver natively. [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
## 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. We get to have `Vec>` or `&[&dyn Advertisement]`, for example. ```rust 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.
## Explanation Async fns get transformed into methods that return `Pin>` and delegate to an async block. For example the `impl Advertisement for AutoplayingVideo` above would be expanded as: ```rust impl Advertisement for AutoplayingVideo { fn run<'async_trait>( &'async_trait self, ) -> Pin + Send + 'async_trait>> where Self: Sync + 'async_trait, { Box::pin(async move { /* the original method body */ }) } } ```
## 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. ```rust type Elided<'a> = &'a usize; #[async_trait] trait Test { async fn test(not_okay: Elided, okay: &usize) {} } ``` ```console 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 `'_`. ```rust #[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. ```rust #[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: ```console 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: ```rust #[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`: ```rust #[async_trait] pub trait ObjectSafe { async fn cannot_dyn(&self) where Self: Sized {} // presumably other methods } let object = &value as &dyn ObjectSafe; ```
#### License Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. async-trait-0.1.83/src/args.rs000064400000000000000000000014211046102023000142420ustar 00000000000000use proc_macro2::Span; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::Token; #[derive(Copy, Clone)] pub struct Args { pub local: bool, } mod kw { syn::custom_keyword!(Send); } impl Parse for Args { fn parse(input: ParseStream) -> Result { match try_parse(input) { Ok(args) if input.is_empty() => Ok(args), _ => Err(error()), } } } fn try_parse(input: ParseStream) -> Result { if input.peek(Token![?]) { input.parse::()?; input.parse::()?; Ok(Args { local: true }) } else { Ok(Args { local: false }) } } fn error() -> Error { let msg = "expected #[async_trait] or #[async_trait(?Send)]"; Error::new(Span::call_site(), msg) } async-trait-0.1.83/src/bound.rs000064400000000000000000000026161046102023000144240ustar 00000000000000use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; use syn::punctuated::Punctuated; use syn::{Token, TypeParamBound}; pub type Supertraits = Punctuated; pub enum InferredBound { Send, Sync, } pub fn has_bound(supertraits: &Supertraits, bound: &InferredBound) -> bool { for supertrait in supertraits { if let TypeParamBound::Trait(supertrait) = supertrait { if supertrait.path.is_ident(bound) || supertrait.path.segments.len() == 3 && (supertrait.path.segments[0].ident == "std" || supertrait.path.segments[0].ident == "core") && supertrait.path.segments[1].ident == "marker" && supertrait.path.segments[2].ident == *bound { return true; } } } false } impl InferredBound { fn as_str(&self) -> &str { match self { InferredBound::Send => "Send", InferredBound::Sync => "Sync", } } } impl ToTokens for InferredBound { fn to_tokens(&self, tokens: &mut TokenStream) { let ident = Ident::new(self.as_str(), Span::call_site()); quote!(::core::marker::#ident).to_tokens(tokens); } } impl PartialEq for Ident { fn eq(&self, bound: &InferredBound) -> bool { self == bound.as_str() } } async-trait-0.1.83/src/expand.rs000064400000000000000000000406471046102023000146020ustar 00000000000000use crate::bound::{has_bound, InferredBound, Supertraits}; use crate::lifetime::{AddLifetimeToImplTrait, CollectLifetimes}; use crate::parse::Item; use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf}; use crate::verbatim::VerbatimFn; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; use std::mem; use syn::punctuated::Punctuated; use syn::visit_mut::{self, VisitMut}; use syn::{ parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericArgument, GenericParam, Generics, Ident, ImplItem, Lifetime, LifetimeParam, Pat, PatIdent, PathArguments, Receiver, ReturnType, Signature, Token, TraitItem, Type, TypePath, WhereClause, }; impl ToTokens for Item { fn to_tokens(&self, tokens: &mut TokenStream) { match self { Item::Trait(item) => item.to_tokens(tokens), Item::Impl(item) => item.to_tokens(tokens), } } } #[derive(Clone, Copy)] enum Context<'a> { Trait { generics: &'a Generics, supertraits: &'a Supertraits, }, Impl { impl_generics: &'a Generics, associated_type_impl_traits: &'a Set, }, } impl Context<'_> { fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator { let generics = match self { Context::Trait { generics, .. } => generics, Context::Impl { impl_generics, .. } => impl_generics, }; generics.params.iter().filter_map(move |param| { if let GenericParam::Lifetime(param) = param { if used.contains(¶m.lifetime) { return Some(param); } } None }) } } pub fn expand(input: &mut Item, is_local: bool) { match input { Item::Trait(input) => { let context = Context::Trait { generics: &input.generics, supertraits: &input.supertraits, }; for inner in &mut input.items { if let TraitItem::Fn(method) = inner { let sig = &mut method.sig; if sig.asyncness.is_some() { let block = &mut method.default; let mut has_self = has_self_in_sig(sig); method.attrs.push(parse_quote!(#[must_use])); if let Some(block) = block { has_self |= has_self_in_block(block); transform_block(context, sig, block); method.attrs.push(lint_suppress_with_body()); } else { method.attrs.push(lint_suppress_without_body()); } let has_default = method.default.is_some(); transform_sig(context, sig, has_self, has_default, is_local); } } } } Item::Impl(input) => { let mut associated_type_impl_traits = Set::new(); for inner in &input.items { if let ImplItem::Type(assoc) = inner { if let Type::ImplTrait(_) = assoc.ty { associated_type_impl_traits.insert(assoc.ident.clone()); } } } let context = Context::Impl { impl_generics: &input.generics, associated_type_impl_traits: &associated_type_impl_traits, }; for inner in &mut input.items { match inner { ImplItem::Fn(method) if method.sig.asyncness.is_some() => { let sig = &mut method.sig; let block = &mut method.block; let has_self = has_self_in_sig(sig) || has_self_in_block(block); transform_block(context, sig, block); transform_sig(context, sig, has_self, false, is_local); method.attrs.push(lint_suppress_with_body()); } ImplItem::Verbatim(tokens) => { let mut method = match syn::parse2::(tokens.clone()) { Ok(method) if method.sig.asyncness.is_some() => method, _ => continue, }; let sig = &mut method.sig; let has_self = has_self_in_sig(sig); transform_sig(context, sig, has_self, false, is_local); method.attrs.push(lint_suppress_with_body()); *tokens = quote!(#method); } _ => {} } } } } } fn lint_suppress_with_body() -> Attribute { parse_quote! { #[allow( elided_named_lifetimes, clippy::async_yields_async, clippy::diverging_sub_expression, clippy::let_unit_value, clippy::needless_arbitrary_self_type, clippy::no_effect_underscore_binding, clippy::shadow_same, clippy::type_complexity, clippy::type_repetition_in_bounds, clippy::used_underscore_binding )] } } fn lint_suppress_without_body() -> Attribute { parse_quote! { #[allow( elided_named_lifetimes, clippy::type_complexity, clippy::type_repetition_in_bounds )] } } // Input: // async fn f(&self, x: &T) -> Ret; // // Output: // fn f<'life0, 'life1, 'async_trait, T>( // &'life0 self, // x: &'life1 T, // ) -> Pin + Send + 'async_trait>> // where // 'life0: 'async_trait, // 'life1: 'async_trait, // T: 'async_trait, // Self: Sync + 'async_trait; fn transform_sig( context: Context, sig: &mut Signature, has_self: bool, has_default: bool, is_local: bool, ) { sig.fn_token.span = sig.asyncness.take().unwrap().span; let (ret_arrow, ret) = match &sig.output { ReturnType::Default => (quote!(->), quote!(())), ReturnType::Type(arrow, ret) => (quote!(#arrow), quote!(#ret)), }; let mut lifetimes = CollectLifetimes::new(); for arg in &mut sig.inputs { match arg { FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg), FnArg::Typed(arg) => lifetimes.visit_type_mut(&mut arg.ty), } } for param in &mut sig.generics.params { match param { GenericParam::Type(param) => { let param_name = ¶m.ident; let span = match param.colon_token.take() { Some(colon_token) => colon_token.span, None => param_name.span(), }; let bounds = mem::replace(&mut param.bounds, Punctuated::new()); where_clause_or_default(&mut sig.generics.where_clause) .predicates .push(parse_quote_spanned!(span=> #param_name: 'async_trait + #bounds)); } GenericParam::Lifetime(param) => { let param_name = ¶m.lifetime; let span = match param.colon_token.take() { Some(colon_token) => colon_token.span, None => param_name.span(), }; let bounds = mem::replace(&mut param.bounds, Punctuated::new()); where_clause_or_default(&mut sig.generics.where_clause) .predicates .push(parse_quote_spanned!(span=> #param: 'async_trait + #bounds)); } GenericParam::Const(_) => {} } } for param in context.lifetimes(&lifetimes.explicit) { let param = ¶m.lifetime; let span = param.span(); where_clause_or_default(&mut sig.generics.where_clause) .predicates .push(parse_quote_spanned!(span=> #param: 'async_trait)); } if sig.generics.lt_token.is_none() { sig.generics.lt_token = Some(Token![<](sig.ident.span())); } if sig.generics.gt_token.is_none() { sig.generics.gt_token = Some(Token![>](sig.paren_token.span.join())); } for elided in lifetimes.elided { sig.generics.params.push(parse_quote!(#elided)); where_clause_or_default(&mut sig.generics.where_clause) .predicates .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait)); } sig.generics.params.push(parse_quote!('async_trait)); if has_self { let bounds: &[InferredBound] = if is_local { &[] } else if let Some(receiver) = sig.receiver() { match receiver.ty.as_ref() { // self: &Self Type::Reference(ty) if ty.mutability.is_none() => &[InferredBound::Sync], // self: Arc Type::Path(ty) if { let segment = ty.path.segments.last().unwrap(); segment.ident == "Arc" && match &segment.arguments { PathArguments::AngleBracketed(arguments) => { arguments.args.len() == 1 && match &arguments.args[0] { GenericArgument::Type(Type::Path(arg)) => { arg.path.is_ident("Self") } _ => false, } } _ => false, } } => { &[InferredBound::Sync, InferredBound::Send] } _ => &[InferredBound::Send], } } else { &[InferredBound::Send] }; let bounds = bounds.iter().filter(|bound| match context { Context::Trait { supertraits, .. } => has_default && !has_bound(supertraits, bound), Context::Impl { .. } => false, }); where_clause_or_default(&mut sig.generics.where_clause) .predicates .push(parse_quote! { Self: #(#bounds +)* 'async_trait }); } for (i, arg) in sig.inputs.iter_mut().enumerate() { match arg { FnArg::Receiver(receiver) => { if receiver.reference.is_none() { receiver.mutability = None; } } FnArg::Typed(arg) => { if match *arg.ty { Type::Reference(_) => false, _ => true, } { if let Pat::Ident(pat) = &mut *arg.pat { pat.by_ref = None; pat.mutability = None; } else { let positional = positional_arg(i, &arg.pat); let m = mut_pat(&mut arg.pat); arg.pat = parse_quote!(#m #positional); } } AddLifetimeToImplTrait.visit_type_mut(&mut arg.ty); } } } let bounds = if is_local { quote!('async_trait) } else { quote!(::core::marker::Send + 'async_trait) }; sig.output = parse_quote! { #ret_arrow ::core::pin::Pin + #bounds >> }; } // Input: // async fn f(&self, x: &T, (a, b): (A, B)) -> Ret { // self + x + a + b // } // // Output: // Box::pin(async move { // let ___ret: Ret = { // let __self = self; // let x = x; // let (a, b) = __arg1; // // __self + x + a + b // }; // // ___ret // }) fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { let mut replace_self = false; let decls = sig .inputs .iter() .enumerate() .map(|(i, arg)| match arg { FnArg::Receiver(Receiver { self_token, mutability, .. }) => { replace_self = true; let ident = Ident::new("__self", self_token.span); quote!(let #mutability #ident = #self_token;) } FnArg::Typed(arg) => { // If there is a #[cfg(...)] attribute that selectively enables // the parameter, forward it to the variable. // // This is currently not applied to the `self` parameter. let attrs = arg.attrs.iter().filter(|attr| attr.path().is_ident("cfg")); if let Type::Reference(_) = *arg.ty { quote!() } else if let Pat::Ident(PatIdent { ident, mutability, .. }) = &*arg.pat { quote! { #(#attrs)* let #mutability #ident = #ident; } } else { let pat = &arg.pat; let ident = positional_arg(i, pat); if let Pat::Wild(_) = **pat { quote! { #(#attrs)* let #ident = #ident; } } else { quote! { #(#attrs)* let #pat = { let #ident = #ident; #ident }; } } } } }) .collect::>(); if replace_self { ReplaceSelf.visit_block_mut(block); } let stmts = &block.stmts; let let_ret = match &mut sig.output { ReturnType::Default => quote_spanned! {block.brace_token.span=> #(#decls)* let () = { #(#stmts)* }; }, ReturnType::Type(_, ret) => { if contains_associated_type_impl_trait(context, ret) { if decls.is_empty() { quote!(#(#stmts)*) } else { quote!(#(#decls)* { #(#stmts)* }) } } else { quote! { if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> { #[allow(unreachable_code)] return __ret; } #(#decls)* let __ret: #ret = { #(#stmts)* }; #[allow(unreachable_code)] __ret } } } }; let box_pin = quote_spanned!(block.brace_token.span=> Box::pin(async move { #let_ret }) ); block.stmts = parse_quote!(#box_pin); } fn positional_arg(i: usize, pat: &Pat) -> Ident { let span = syn::spanned::Spanned::span(pat).resolved_at(Span::mixed_site()); format_ident!("__arg{}", i, span = span) } fn contains_associated_type_impl_trait(context: Context, ret: &mut Type) -> bool { struct AssociatedTypeImplTraits<'a> { set: &'a Set, contains: bool, } impl<'a> VisitMut for AssociatedTypeImplTraits<'a> { fn visit_type_path_mut(&mut self, ty: &mut TypePath) { if ty.qself.is_none() && ty.path.segments.len() == 2 && ty.path.segments[0].ident == "Self" && self.set.contains(&ty.path.segments[1].ident) { self.contains = true; } visit_mut::visit_type_path_mut(self, ty); } } match context { Context::Trait { .. } => false, Context::Impl { associated_type_impl_traits, .. } => { let mut visit = AssociatedTypeImplTraits { set: associated_type_impl_traits, contains: false, }; visit.visit_type_mut(ret); visit.contains } } } fn where_clause_or_default(clause: &mut Option) -> &mut WhereClause { clause.get_or_insert_with(|| WhereClause { where_token: Default::default(), predicates: Punctuated::new(), }) } async-trait-0.1.83/src/lib.rs000064400000000000000000000247021046102023000140630ustar 00000000000000//! [![github]](https://github.com/dtolnay/async-trait) [![crates-io]](https://crates.io/crates/async-trait) [![docs-rs]](https://docs.rs/async-trait) //! //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs //! //!
//! //!

Type erasure for async trait methods

//! //! The stabilization of async functions in traits in Rust 1.75 did not include //! support for using traits containing async functions as `dyn Trait`. Trying //! to use dyn with an async trait produces the following error: //! //! ```compile_fail //! pub trait Trait { //! async fn f(&self); //! } //! //! pub fn make() -> Box { //! unimplemented!() //! } //! ``` //! //! ```text //! error[E0038]: the trait `Trait` cannot be made into an object //! --> src/main.rs:5:22 //! | //! 5 | pub fn make() -> Box { //! | ^^^^^^^^^ `Trait` cannot be made into an object //! | //! note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit //! --> src/main.rs:2:14 //! | //! 1 | pub trait Trait { //! | ----- this trait cannot be made into an object... //! 2 | async fn f(&self); //! | ^ ...because method `f` is `async` //! = help: consider moving `f` to another trait //! ``` //! //! This crate provides an attribute macro to make async fn in traits work with //! dyn traits. //! //! Please refer to [*why async fn in traits are hard*][hard] for a deeper //! analysis of how this implementation differs from what the compiler and //! language deliver natively. //! //! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/ //! //!
//! //! # 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. We //! get to have `Vec>` or `&[&dyn Advertisement]`, //! for example. //! //! ``` //! 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; //! } //! } //! # //! # impl Modal { //! # async fn render_fullscreen(&self) {} //! # async fn hide_for_now(&self) {} //! # } //! # //! # async fn remind_user_to_join_mailing_list() {} //! # //! # struct Stream; //! # async fn connect(_media_url: &str) -> Stream { Stream } //! # impl Stream { //! # async fn play(&self) {} //! # } //! ``` //! //!

//! //! # 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.
//! //!
//! //! # Explanation //! //! Async fns get transformed into methods that return `Pin>` and delegate to an async block. //! //! For example the `impl Advertisement for AutoplayingVideo` above would be //! expanded as: //! //! ``` //! # const IGNORE: &str = stringify! { //! impl Advertisement for AutoplayingVideo { //! fn run<'async_trait>( //! &'async_trait self, //! ) -> Pin + Send + 'async_trait>> //! where //! Self: Sync + 'async_trait, //! { //! Box::pin(async move { //! /* the original method body */ //! }) //! } //! } //! # }; //! ``` //! //!

//! //! # 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. //! //! ```compile_fail //! # use async_trait::async_trait; //! # //! type Elided<'a> = &'a usize; //! //! #[async_trait] //! trait Test { //! async fn test(not_okay: Elided, okay: &usize) {} //! } //! ``` //! //! ```text //! 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 `'_`. //! //! ``` //! # use async_trait::async_trait; //! # //! # type Elided<'a> = &'a usize; //! # //! #[async_trait] //! trait Test { //! // either //! async fn test<'e>(elided: Elided<'e>) {} //! # } //! # #[async_trait] //! # trait Test2 { //! // 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. //! //! ``` //! # use async_trait::async_trait; //! # //! #[async_trait] //! pub trait ObjectSafe { //! async fn f(&self); //! async fn g(&mut self); //! } //! //! # const IGNORE: &str = stringify! { //! impl ObjectSafe for MyType {...} //! //! let value: MyType = ...; //! # }; //! # //! # struct MyType; //! # //! # #[async_trait] //! # impl ObjectSafe for MyType { //! # async fn f(&self) {} //! # async fn g(&mut self) {} //! # } //! # //! # let value: MyType = 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: //! //! ```text //! 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: //! //! ``` //! # use async_trait::async_trait; //! # //! #[async_trait] //! pub trait ObjectSafe: Sync { // added supertrait //! async fn can_dyn(&self) {} //! } //! # //! # struct MyType; //! # //! # #[async_trait] //! # impl ObjectSafe for MyType {} //! # //! # let value = MyType; //! //! let object = &value as &dyn ObjectSafe; //! ``` //! //! or you can strike the problematic methods from your trait object by //! bounding them with `Self: Sized`: //! //! ``` //! # use async_trait::async_trait; //! # //! #[async_trait] //! pub trait ObjectSafe { //! async fn cannot_dyn(&self) where Self: Sized {} //! //! // presumably other methods //! } //! # //! # struct MyType; //! # //! # #[async_trait] //! # impl ObjectSafe for MyType {} //! # //! # let value = MyType; //! //! let object = &value as &dyn ObjectSafe; //! ``` #![doc(html_root_url = "https://docs.rs/async-trait/0.1.83")] #![allow( clippy::default_trait_access, clippy::doc_markdown, clippy::explicit_auto_deref, clippy::if_not_else, clippy::items_after_statements, clippy::match_like_matches_macro, clippy::module_name_repetitions, clippy::shadow_unrelated, clippy::similar_names, clippy::too_many_lines, clippy::trivially_copy_pass_by_ref )] extern crate proc_macro; mod args; mod bound; mod expand; mod lifetime; mod parse; mod receiver; mod verbatim; use crate::args::Args; use crate::expand::expand; use crate::parse::Item; use proc_macro::TokenStream; use quote::quote; use syn::parse_macro_input; #[proc_macro_attribute] pub fn async_trait(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as Args); let mut item = parse_macro_input!(input as Item); expand(&mut item, args.local); TokenStream::from(quote!(#item)) } async-trait-0.1.83/src/lifetime.rs000064400000000000000000000072011046102023000151060ustar 00000000000000use proc_macro2::{Span, TokenStream}; use std::mem; use syn::visit_mut::{self, VisitMut}; use syn::{ parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Token, Type, TypeBareFn, TypeImplTrait, TypeParen, TypePtr, TypeReference, }; pub struct CollectLifetimes { pub elided: Vec, pub explicit: Vec, } impl CollectLifetimes { pub fn new() -> Self { CollectLifetimes { elided: Vec::new(), explicit: Vec::new(), } } fn visit_opt_lifetime(&mut self, reference: &Token![&], lifetime: &mut Option) { match lifetime { None => *lifetime = Some(self.next_lifetime(reference.span)), Some(lifetime) => self.visit_lifetime(lifetime), } } fn visit_lifetime(&mut self, lifetime: &mut Lifetime) { if lifetime.ident == "_" { *lifetime = self.next_lifetime(lifetime.span()); } else { self.explicit.push(lifetime.clone()); } } fn next_lifetime(&mut self, span: Span) -> Lifetime { let name = format!("'life{}", self.elided.len()); let life = Lifetime::new(&name, span); self.elided.push(life.clone()); life } } impl VisitMut for CollectLifetimes { fn visit_receiver_mut(&mut self, arg: &mut Receiver) { if let Some((reference, lifetime)) = &mut arg.reference { self.visit_opt_lifetime(reference, lifetime); } else { visit_mut::visit_type_mut(self, &mut arg.ty); } } fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) { self.visit_opt_lifetime(&ty.and_token, &mut ty.lifetime); visit_mut::visit_type_reference_mut(self, ty); } fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) { if let GenericArgument::Lifetime(lifetime) = gen { self.visit_lifetime(lifetime); } visit_mut::visit_generic_argument_mut(self, gen); } } pub struct AddLifetimeToImplTrait; impl VisitMut for AddLifetimeToImplTrait { fn visit_type_impl_trait_mut(&mut self, ty: &mut TypeImplTrait) { let span = ty.impl_token.span; let lifetime = parse_quote_spanned!(span=> 'async_trait); ty.bounds.insert(0, lifetime); if let Some(punct) = ty.bounds.pairs_mut().next().unwrap().punct_mut() { punct.span = span; } visit_mut::visit_type_impl_trait_mut(self, ty); } fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) { parenthesize_impl_trait(&mut ty.elem, ty.and_token.span); visit_mut::visit_type_reference_mut(self, ty); } fn visit_type_ptr_mut(&mut self, ty: &mut TypePtr) { parenthesize_impl_trait(&mut ty.elem, ty.star_token.span); visit_mut::visit_type_ptr_mut(self, ty); } fn visit_type_bare_fn_mut(&mut self, ty: &mut TypeBareFn) { if let ReturnType::Type(arrow, return_type) = &mut ty.output { parenthesize_impl_trait(return_type, arrow.spans[0]); } visit_mut::visit_type_bare_fn_mut(self, ty); } fn visit_expr_mut(&mut self, _e: &mut Expr) { // Do not recurse into impl Traits inside of an array length expression. // // fn outer(arg: [u8; { fn inner(_: impl Trait) {}; 0 }]); } } fn parenthesize_impl_trait(elem: &mut Type, paren_span: Span) { if let Type::ImplTrait(_) = *elem { let placeholder = Type::Verbatim(TokenStream::new()); *elem = Type::Paren(TypeParen { paren_token: token::Paren(paren_span), elem: Box::new(mem::replace(elem, placeholder)), }); } } async-trait-0.1.83/src/parse.rs000064400000000000000000000021341046102023000144220ustar 00000000000000use proc_macro2::Span; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::{Attribute, ItemImpl, ItemTrait, Token}; pub enum Item { Trait(ItemTrait), Impl(ItemImpl), } impl Parse for Item { fn parse(input: ParseStream) -> Result { let attrs = input.call(Attribute::parse_outer)?; let mut lookahead = input.lookahead1(); if lookahead.peek(Token![unsafe]) { let ahead = input.fork(); ahead.parse::()?; lookahead = ahead.lookahead1(); } if lookahead.peek(Token![pub]) || lookahead.peek(Token![trait]) { let mut item: ItemTrait = input.parse()?; item.attrs = attrs; Ok(Item::Trait(item)) } else if lookahead.peek(Token![impl]) { let mut item: ItemImpl = input.parse()?; if item.trait_.is_none() { return Err(Error::new(Span::call_site(), "expected a trait impl")); } item.attrs = attrs; Ok(Item::Impl(item)) } else { Err(lookahead.error()) } } } async-trait-0.1.83/src/receiver.rs000064400000000000000000000123451046102023000151210ustar 00000000000000use proc_macro2::{Group, TokenStream, TokenTree}; use syn::visit_mut::{self, VisitMut}; use syn::{ Block, ExprPath, Ident, Item, Macro, Pat, PatIdent, Path, Receiver, Signature, Token, TypePath, }; pub fn has_self_in_sig(sig: &mut Signature) -> bool { let mut visitor = HasSelf(false); visitor.visit_signature_mut(sig); visitor.0 } pub fn has_self_in_block(block: &mut Block) -> bool { let mut visitor = HasSelf(false); visitor.visit_block_mut(block); visitor.0 } fn has_self_in_token_stream(tokens: TokenStream) -> bool { tokens.into_iter().any(|tt| match tt { TokenTree::Ident(ident) => ident == "Self", TokenTree::Group(group) => has_self_in_token_stream(group.stream()), _ => false, }) } pub fn mut_pat(pat: &mut Pat) -> Option { let mut visitor = HasMutPat(None); visitor.visit_pat_mut(pat); visitor.0 } fn contains_fn(tokens: TokenStream) -> bool { tokens.into_iter().any(|tt| match tt { TokenTree::Ident(ident) => ident == "fn", TokenTree::Group(group) => contains_fn(group.stream()), _ => false, }) } struct HasMutPat(Option); impl VisitMut for HasMutPat { fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) { if let Some(m) = &i.mutability { self.0 = Some(Token![mut](m.span)); } else { visit_mut::visit_pat_ident_mut(self, i); } } } struct HasSelf(bool); impl VisitMut for HasSelf { fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { self.0 |= expr.path.segments[0].ident == "Self"; visit_mut::visit_expr_path_mut(self, expr); } fn visit_type_path_mut(&mut self, ty: &mut TypePath) { self.0 |= ty.path.segments[0].ident == "Self"; visit_mut::visit_type_path_mut(self, ty); } fn visit_receiver_mut(&mut self, _arg: &mut Receiver) { self.0 = true; } fn visit_item_mut(&mut self, _: &mut Item) { // Do not recurse into nested items. } fn visit_macro_mut(&mut self, mac: &mut Macro) { if !contains_fn(mac.tokens.clone()) { self.0 |= has_self_in_token_stream(mac.tokens.clone()); } } } pub struct ReplaceSelf; fn prepend_underscore_to_self(ident: &mut Ident) -> bool { let modified = ident == "self"; if modified { *ident = Ident::new("__self", ident.span()); } modified } impl ReplaceSelf { fn visit_token_stream(&mut self, tokens: &mut TokenStream) -> bool { let mut out = Vec::new(); let mut modified = false; visit_token_stream_impl(self, tokens.clone(), &mut modified, &mut out); if modified { *tokens = TokenStream::from_iter(out); } return modified; fn visit_token_stream_impl( visitor: &mut ReplaceSelf, tokens: TokenStream, modified: &mut bool, out: &mut Vec, ) { for tt in tokens { match tt { TokenTree::Ident(mut ident) => { *modified |= prepend_underscore_to_self(&mut ident); out.push(TokenTree::Ident(ident)); } TokenTree::Group(group) => { let mut content = group.stream(); *modified |= visitor.visit_token_stream(&mut content); let mut new = Group::new(group.delimiter(), content); new.set_span(group.span()); out.push(TokenTree::Group(new)); } other => out.push(other), } } } } } impl VisitMut for ReplaceSelf { fn visit_ident_mut(&mut self, i: &mut Ident) { prepend_underscore_to_self(i); } fn visit_path_mut(&mut self, p: &mut Path) { if p.segments.len() == 1 { // Replace `self`, but not `self::function`. self.visit_ident_mut(&mut p.segments[0].ident); } for segment in &mut p.segments { self.visit_path_arguments_mut(&mut segment.arguments); } } fn visit_item_mut(&mut self, i: &mut Item) { // Visit `macro_rules!` because locally defined macros can refer to // `self`. // // Visit `futures::select` and similar select macros, which commonly // appear syntactically like an item despite expanding to an expression. // // Otherwise, do not recurse into nested items. if let Item::Macro(i) = i { if i.mac.path.is_ident("macro_rules") || i.mac.path.segments.last().unwrap().ident == "select" { self.visit_macro_mut(&mut i.mac); } } } fn visit_macro_mut(&mut self, mac: &mut Macro) { // We can't tell in general whether `self` inside a macro invocation // refers to the self in the argument list or a different self // introduced within the macro. Heuristic: if the macro input contains // `fn`, then `self` is more likely to refer to something other than the // outer function's self argument. if !contains_fn(mac.tokens.clone()) { self.visit_token_stream(&mut mac.tokens); } } } async-trait-0.1.83/src/verbatim.rs000064400000000000000000000017101046102023000151200ustar 00000000000000use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt}; use syn::parse::{Parse, ParseStream, Result}; use syn::{Attribute, Signature, Token, Visibility}; pub struct VerbatimFn { pub attrs: Vec, pub vis: Visibility, pub defaultness: Option, pub sig: Signature, pub semi_token: Token![;], } impl Parse for VerbatimFn { fn parse(input: ParseStream) -> Result { Ok(VerbatimFn { attrs: input.call(Attribute::parse_outer)?, vis: input.parse()?, defaultness: input.parse()?, sig: input.parse()?, semi_token: input.parse()?, }) } } impl ToTokens for VerbatimFn { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(&self.attrs); self.vis.to_tokens(tokens); self.defaultness.to_tokens(tokens); self.sig.to_tokens(tokens); self.semi_token.to_tokens(tokens); } } async-trait-0.1.83/tests/compiletest.rs000064400000000000000000000003261046102023000162140ustar 00000000000000#[rustversion::attr(not(nightly), ignore = "requires nightly")] #[cfg_attr(miri, ignore = "incompatible with miri")] #[test] fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); } async-trait-0.1.83/tests/executor/mod.rs000064400000000000000000000020461046102023000163020ustar 00000000000000use std::future::Future; use std::pin::Pin; use std::ptr; use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; // Executor for a future that resolves immediately (test only). #[allow(clippy::missing_panics_doc)] pub fn block_on_simple(mut fut: F) -> F::Output { unsafe fn clone(_null: *const ()) -> RawWaker { unimplemented!() } unsafe fn wake(_null: *const ()) { unimplemented!() } unsafe fn wake_by_ref(_null: *const ()) { unimplemented!() } unsafe fn drop(_null: *const ()) {} let data = ptr::null(); let vtable = &RawWakerVTable::new(clone, wake, wake_by_ref, drop); let raw_waker = RawWaker::new(data, vtable); let waker = unsafe { Waker::from_raw(raw_waker) }; let mut cx = Context::from_waker(&waker); // fut does not move until it gets dropped. let fut = unsafe { Pin::new_unchecked(&mut fut) }; match fut.poll(&mut cx) { Poll::Ready(output) => output, Poll::Pending => panic!("future did not resolve immediately"), } } async-trait-0.1.83/tests/test.rs000064400000000000000000001110051046102023000146400ustar 00000000000000#![cfg_attr( async_trait_nightly_testing, feature(impl_trait_in_assoc_type, min_specialization, never_type) )] #![deny(rust_2021_compatibility, unused_qualifications)] #![allow( clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 clippy::let_underscore_untyped, clippy::let_unit_value, clippy::missing_panics_doc, clippy::missing_safety_doc, clippy::needless_return, clippy::non_minimal_cfg, clippy::trivially_copy_pass_by_ref, clippy::unused_async )] use async_trait::async_trait; pub mod executor; // Dummy module to check that the expansion refer to rust's core crate mod core {} #[async_trait] trait Trait { type Assoc; async fn selfvalue(self) where Self: Sized, { } async fn selfref(&self) {} async fn selfmut(&mut self) {} async fn required() -> Self::Assoc; async fn elided_lifetime(_x: &str) {} async fn explicit_lifetime<'a>(_x: &'a str) {} async fn generic_type_param(x: Box) -> T { *x } async fn calls(&self) { self.selfref().await; Self::elided_lifetime("").await; ::elided_lifetime("").await; } async fn calls_mut(&mut self) { self.selfmut().await; } } struct Struct; #[async_trait] impl Trait for Struct { type Assoc = (); async fn selfvalue(self) {} async fn selfref(&self) {} async fn selfmut(&mut self) {} async fn required() -> Self::Assoc {} async fn elided_lifetime(_x: &str) {} async fn explicit_lifetime<'a>(_x: &'a str) {} async fn generic_type_param(x: Box) -> T { *x } async fn calls(&self) { self.selfref().await; Self::elided_lifetime("").await; ::elided_lifetime("").await; } async fn calls_mut(&mut self) { self.selfmut().await; } } pub async fn test() { let mut s = Struct; s.selfref().await; s.selfmut().await; s.selfvalue().await; Struct::required().await; Struct::elided_lifetime("").await; Struct::explicit_lifetime("").await; Struct::generic_type_param(Box::new("")).await; let mut s = Struct; s.calls().await; s.calls_mut().await; } pub async fn test_object_safe_without_default() { #[async_trait] trait ObjectSafe { async fn f(&self); } #[async_trait] impl ObjectSafe for Struct { async fn f(&self) {} } let object = &Struct as &dyn ObjectSafe; object.f().await; } pub async fn test_object_safe_with_default() { #[async_trait] trait ObjectSafe: Sync { async fn f(&self) {} } #[async_trait] impl ObjectSafe for Struct { async fn f(&self) {} } let object = &Struct as &dyn ObjectSafe; object.f().await; } pub async fn test_object_no_send() { #[async_trait(?Send)] trait ObjectSafe: Sync { async fn f(&self) {} } #[async_trait(?Send)] impl ObjectSafe for Struct { async fn f(&self) {} } let object = &Struct as &dyn ObjectSafe; object.f().await; } #[async_trait] pub unsafe trait UnsafeTrait {} #[async_trait] unsafe impl UnsafeTrait for () {} #[async_trait] #[allow(dead_code)] pub(crate) unsafe trait UnsafeTraitPubCrate {} #[async_trait] #[allow(dead_code)] unsafe trait UnsafeTraitPrivate {} pub async fn test_can_destruct() { #[async_trait] trait CanDestruct { async fn f(&self, foos: (u8, u8, u8, u8)); } #[async_trait] impl CanDestruct for Struct { async fn f(&self, (a, ref mut b, ref c, d): (u8, u8, u8, u8)) { let _a: u8 = a; let _b: &mut u8 = b; let _c: &u8 = c; let _d: u8 = d; } } let _ = ::f; } pub async fn test_self_in_macro() { #[async_trait] trait Trait { async fn a(self); async fn b(&mut self); async fn c(&self); } #[async_trait] impl Trait for String { async fn a(self) { println!("{}", self); } async fn b(&mut self) { println!("{}", self); } async fn c(&self) { println!("{}", self); } } let _ = ::a; let _ = ::b; let _ = ::c; } pub async fn test_inference() { #[async_trait] pub trait Trait { async fn f() -> Box> { Box::new(std::iter::empty()) } } impl Trait for () {} let _ = <() as Trait>::f; } pub async fn test_internal_items() { #[async_trait] #[allow(dead_code, clippy::items_after_statements)] pub trait Trait: Sized { async fn f(self) { struct Struct; impl Struct { fn f(self) { let _ = self; } } } } } pub async fn test_unimplemented() { #[async_trait] pub trait Trait { async fn f() { unimplemented!() } } impl Trait for () {} let _ = <() as Trait>::f; } // https://github.com/dtolnay/async-trait/issues/1 pub mod issue1 { use async_trait::async_trait; #[async_trait] pub trait Issue1 { async fn f(&self); } #[async_trait] impl Issue1 for Vec { async fn f(&self) {} } } // https://github.com/dtolnay/async-trait/issues/2 pub mod issue2 { use async_trait::async_trait; use std::future::Future; #[async_trait] pub trait Issue2: Future { async fn flatten(self) -> ::Output where Self::Output: Future + Send, Self: Sized, { let nested_future = self.await; nested_future.await } } } // https://github.com/dtolnay/async-trait/issues/9 pub mod issue9 { use async_trait::async_trait; #[async_trait] pub trait Issue9: Sized + Send { async fn f(_x: Self) {} } } // https://github.com/dtolnay/async-trait/issues/11 pub mod issue11 { use async_trait::async_trait; use std::sync::Arc; #[async_trait] pub trait Issue11 { async fn example(self: Arc); } pub struct Struct; #[async_trait] impl Issue11 for Struct { async fn example(self: Arc) {} } } // https://github.com/dtolnay/async-trait/issues/15 pub mod issue15 { use async_trait::async_trait; use std::marker::PhantomData; pub trait Trait {} #[async_trait] pub trait Issue15 { async fn myfn(&self, _: PhantomData) {} } } // https://github.com/dtolnay/async-trait/issues/17 pub mod issue17 { use async_trait::async_trait; #[async_trait] pub trait Issue17 { async fn f(&self); } pub struct Struct { pub string: String, } #[async_trait] impl Issue17 for Struct { async fn f(&self) { println!("{}", self.string); } } } // https://github.com/dtolnay/async-trait/issues/23 pub mod issue23 { use async_trait::async_trait; #[async_trait] pub trait Issue23 { async fn f(self); async fn g(mut self) where Self: Sized, { do_something(&mut self); } } #[allow(dead_code)] struct S {} #[async_trait] impl Issue23 for S { async fn f(mut self) { do_something(&mut self); } } fn do_something(_: &mut T) {} } // https://github.com/dtolnay/async-trait/issues/25 #[cfg(async_trait_nightly_testing)] pub mod issue25 { use crate::executor; use async_trait::async_trait; use std::fmt::{Display, Write}; #[async_trait] trait AsyncToString { async fn async_to_string(&self) -> String; } #[async_trait] impl AsyncToString for String { async fn async_to_string(&self) -> String { "special".to_owned() } } macro_rules! hide_from_stable_parser { ($($tt:tt)*) => { $($tt)* }; } hide_from_stable_parser! { #[async_trait] impl AsyncToString for T { default async fn async_to_string(&self) -> String { let mut buf = String::new(); buf.write_fmt(format_args!("{}", self)).unwrap(); buf } } } #[test] fn test() { let fut = true.async_to_string(); assert_eq!(executor::block_on_simple(fut), "true"); let string = String::new(); let fut = string.async_to_string(); assert_eq!(executor::block_on_simple(fut), "special"); } } // https://github.com/dtolnay/async-trait/issues/28 pub mod issue28 { use async_trait::async_trait; pub struct Str<'a>(&'a str); #[async_trait] pub trait Trait1<'a> { async fn f(x: Str<'a>) -> &'a str; async fn g(x: Str<'a>) -> &'a str { x.0 } } #[async_trait] impl<'a> Trait1<'a> for str { async fn f(x: Str<'a>) -> &'a str { x.0 } } #[async_trait] pub trait Trait2 { async fn f(); } #[async_trait] impl<'a> Trait2 for &'a () { async fn f() {} } #[async_trait] pub trait Trait3<'a, 'b> { async fn f(_: &'a &'b ()); // chain 'a and 'b async fn g(_: &'b ()); // chain 'b only async fn h(); // do not chain } } // https://github.com/dtolnay/async-trait/issues/31 pub mod issue31 { use async_trait::async_trait; pub struct Struct<'a> { pub name: &'a str, } #[async_trait] pub trait Trait<'a> { async fn hello(thing: Struct<'a>) -> String; async fn hello_twice(one: Struct<'a>, two: Struct<'a>) -> String { let str1 = Self::hello(one).await; let str2 = Self::hello(two).await; str1 + &str2 } } } // https://github.com/dtolnay/async-trait/issues/42 pub mod issue42 { use async_trait::async_trait; #[async_trait] pub trait Context: Sized { async fn from_parts() -> Self; } pub struct TokenContext; #[async_trait] impl Context for TokenContext { async fn from_parts() -> TokenContext { TokenContext } } } // https://github.com/dtolnay/async-trait/issues/44 pub mod issue44 { use async_trait::async_trait; #[async_trait] pub trait StaticWithWhereSelf where Box: Sized, Self: Sized + Send, { async fn get_one() -> u8 { 1 } } pub struct Struct; #[async_trait] impl StaticWithWhereSelf for Struct {} } // https://github.com/dtolnay/async-trait/issues/45 pub mod issue45 { use crate::executor; use async_trait::async_trait; use std::fmt::Debug; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; use tracing::event::Event; use tracing::field::{Field, Visit}; use tracing::span::{Attributes, Id, Record}; use tracing::{info, instrument, subscriber, Metadata, Subscriber}; #[async_trait] pub trait Parent { async fn foo(&mut self, v: usize); } #[async_trait] pub trait Child { async fn bar(&self); } #[derive(Debug)] struct Impl(usize); #[async_trait] impl Parent for Impl { #[instrument] async fn foo(&mut self, v: usize) { self.0 = v; self.bar().await; } } #[async_trait] impl Child for Impl { // Let's check that tracing detects the renaming of the `self` variable // too, as tracing::instrument is not going to be able to skip the // `self` argument if it can't find it in the function signature. #[instrument(skip(self))] async fn bar(&self) { info!(val = self.0); } } // A simple subscriber implementation to test the behavior of async-trait // with tokio-rs/tracing. This implementation is not robust against race // conditions, but it's not an issue here as we are only polling on a single // future at a time. #[derive(Debug)] struct SubscriberInner { current_depth: AtomicU64, // We assert that nested functions work. If the fix were to break, we // would see two top-level functions instead of `bar` nested in `foo`. max_depth: AtomicU64, max_span_id: AtomicU64, // Name of the variable / value / depth when the event was recorded. value: Mutex>, } #[derive(Debug, Clone)] struct TestSubscriber { inner: Arc, } impl TestSubscriber { fn new() -> Self { TestSubscriber { inner: Arc::new(SubscriberInner { current_depth: AtomicU64::new(0), max_depth: AtomicU64::new(0), max_span_id: AtomicU64::new(1), value: Mutex::new(None), }), } } } struct U64Visitor(Option<(&'static str, u64)>); impl Visit for U64Visitor { fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {} fn record_u64(&mut self, field: &Field, value: u64) { self.0 = Some((field.name(), value)); } } impl Subscriber for TestSubscriber { fn enabled(&self, _metadata: &Metadata) -> bool { true } fn new_span(&self, _span: &Attributes) -> Id { Id::from_u64(self.inner.max_span_id.fetch_add(1, Ordering::AcqRel)) } fn record(&self, _span: &Id, _values: &Record) {} fn record_follows_from(&self, _span: &Id, _follows: &Id) {} fn event(&self, event: &Event) { let mut visitor = U64Visitor(None); event.record(&mut visitor); if let Some((s, v)) = visitor.0 { let current_depth = self.inner.current_depth.load(Ordering::Acquire); *self.inner.value.lock().unwrap() = Some((s, v, current_depth)); } } fn enter(&self, _span: &Id) { let old_depth = self.inner.current_depth.fetch_add(1, Ordering::AcqRel); if old_depth + 1 > self.inner.max_depth.load(Ordering::Acquire) { self.inner.max_depth.fetch_add(1, Ordering::AcqRel); } } fn exit(&self, _span: &Id) { self.inner.current_depth.fetch_sub(1, Ordering::AcqRel); } } #[test] fn tracing() { // Create the future outside of the subscriber, as no call to tracing // should be made until the future is polled. let mut struct_impl = Impl(0); let fut = struct_impl.foo(5); let subscriber = TestSubscriber::new(); subscriber::with_default(subscriber.clone(), || executor::block_on_simple(fut)); // Did we enter bar inside of foo? assert_eq!(subscriber.inner.max_depth.load(Ordering::Acquire), 2); // Have we exited all spans? assert_eq!(subscriber.inner.current_depth.load(Ordering::Acquire), 0); // Did we create only two spans? Note: spans start at 1, hence the -1. assert_eq!(subscriber.inner.max_span_id.load(Ordering::Acquire) - 1, 2); // Was the value recorded at the right depth i.e. in the right function? // If so, was it the expected value? assert_eq!(*subscriber.inner.value.lock().unwrap(), Some(("val", 5, 2))); } } // https://github.com/dtolnay/async-trait/issues/46 pub mod issue46 { use async_trait::async_trait; macro_rules! implement_commands_workaround { ($tyargs:tt : $ty:tt) => { #[async_trait] pub trait AsyncCommands1: Sized { async fn f<$tyargs: $ty>(&mut self, x: $tyargs) { self.f(x).await } } }; } implement_commands_workaround!(K: Send); macro_rules! implement_commands { ($tyargs:ident : $ty:ident) => { #[async_trait] pub trait AsyncCommands2: Sized { async fn f<$tyargs: $ty>(&mut self, x: $tyargs) { self.f(x).await } } }; } implement_commands!(K: Send); } // https://github.com/dtolnay/async-trait/issues/53 pub mod issue53 { use async_trait::async_trait; pub struct Unit; pub struct Tuple(pub u8); pub struct Struct { pub x: u8, } #[async_trait] pub trait Trait { async fn method(); } #[async_trait] impl Trait for Unit { async fn method() { let _ = Self; } } #[async_trait] impl Trait for Tuple { async fn method() { let _ = Self(0); } } #[async_trait] impl Trait for Struct { async fn method() { let _ = Self { x: 0 }; } } #[async_trait] impl Trait for std::marker::PhantomData { async fn method() { let _ = Self; } } } // https://github.com/dtolnay/async-trait/issues/57 pub mod issue57 { use crate::executor; use async_trait::async_trait; #[async_trait] trait Trait { async fn const_generic(_: [T; C]) {} } struct Struct; #[async_trait] impl Trait for Struct { async fn const_generic(_: [T; C]) {} } #[test] fn test() { let fut = Struct::const_generic([0; 10]); executor::block_on_simple(fut); } } // https://github.com/dtolnay/async-trait/issues/68 pub mod issue68 { #[async_trait::async_trait] pub trait Example { async fn method(&self) { macro_rules! t { () => {{ let _: &Self = self; }}; } t!(); } } } // https://github.com/dtolnay/async-trait/issues/73 pub mod issue73 { use async_trait::async_trait; #[async_trait] pub trait Example { const ASSOCIATED: &'static str; async fn associated(&self) { println!("Associated:{}", Self::ASSOCIATED); } } } // https://github.com/dtolnay/async-trait/issues/81 pub mod issue81 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn handle(&self); } pub enum Enum { Variant, } #[async_trait] impl Trait for Enum { async fn handle(&self) { let Enum::Variant = self; let Self::Variant = self; } } } // https://github.com/dtolnay/async-trait/issues/83 pub mod issue83 { #![allow(clippy::needless_arbitrary_self_type)] use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(&self) {} async fn g(self: &Self) {} } } // https://github.com/dtolnay/async-trait/issues/85 pub mod issue85 { #![deny(non_snake_case)] use async_trait::async_trait; #[async_trait] pub trait Trait { #[allow(non_snake_case)] async fn camelCase(); } pub struct Struct; #[async_trait] impl Trait for Struct { async fn camelCase() {} } } // https://github.com/dtolnay/async-trait/issues/87 pub mod issue87 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(&self); } pub enum Tuple { V(), } pub enum Struct { V {}, } #[async_trait] impl Trait for Tuple { async fn f(&self) { let Tuple::V() = self; let Self::V() = self; let _ = Self::V; let _ = Self::V(); } } #[async_trait] impl Trait for Struct { async fn f(&self) { let Struct::V {} = self; let Self::V {} = self; let _ = Self::V {}; } } } // https://github.com/dtolnay/async-trait/issues/89 pub mod issue89 { #![allow(bare_trait_objects)] use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(&self); } #[async_trait] impl Trait for dyn Send + Sync { async fn f(&self) {} } #[async_trait] impl Trait for dyn Fn(i8) + Send + Sync { async fn f(&self) {} } #[async_trait] impl Trait for (dyn Fn(u8) + Send + Sync) { async fn f(&self) {} } } // https://github.com/dtolnay/async-trait/issues/92 pub mod issue92 { use async_trait::async_trait; macro_rules! mac { ($($tt:tt)*) => { $($tt)* }; } pub struct Struct { _x: T, } impl Struct { const ASSOCIATED1: &'static str = "1"; async fn associated1() {} } #[async_trait] pub trait Trait where mac!(Self): Send, { const ASSOCIATED2: &'static str; type Associated2; #[allow(path_statements, clippy::let_underscore_future, clippy::no_effect)] async fn associated2(&self) { // trait items mac!(let _: Self::Associated2;); mac!(let _: ::Associated2;); mac!(let _: ::Associated2;); mac!(Self::ASSOCIATED2;); mac!(::ASSOCIATED2;); mac!(::ASSOCIATED2;); mac!(let _ = Self::associated2(self);); mac!(let _ = ::associated2(self);); mac!(let _ = ::associated2(self);); } } #[async_trait] impl Trait for Struct where mac!(Self): Send, { const ASSOCIATED2: &'static str = "2"; type Associated2 = (); #[allow(path_statements, clippy::let_underscore_future, clippy::no_effect)] async fn associated2(&self) { // inherent items mac!(Self::ASSOCIATED1;); mac!(::ASSOCIATED1;); mac!(let _ = Self::associated1();); mac!(let _ = ::associated1();); // trait items mac!(let (): ::Associated2;); mac!(Self::ASSOCIATED2;); mac!(::ASSOCIATED2;); mac!(::ASSOCIATED2;); mac!(let _ = Self::associated2(self);); mac!(let _ = ::associated2(self);); mac!(let _ = ::associated2(self);); } } pub struct Unit; #[async_trait] impl Trait for Unit { const ASSOCIATED2: &'static str = "2"; type Associated2 = (); async fn associated2(&self) { mac!(let Self: Self = *self;); } } } // https://github.com/dtolnay/async-trait/issues/92#issuecomment-683370136 pub mod issue92_2 { use async_trait::async_trait; macro_rules! mac { ($($tt:tt)*) => { $($tt)* }; } pub trait Trait1 { fn func1(); } #[async_trait] pub trait Trait2: Trait1 { async fn func2() { mac!(Self::func1()); macro_rules! mac2 { ($($tt:tt)*) => { Self::func1(); }; } mac2!(); } } } // https://github.com/dtolnay/async-trait/issues/104 pub mod issue104 { use async_trait::async_trait; #[async_trait] pub trait T1 { async fn id(&self) -> i32; } macro_rules! impl_t1 { ($ty:ty, $id:expr) => { #[async_trait] impl T1 for $ty { async fn id(&self) -> i32 { $id } } }; } pub struct Foo; impl_t1!(Foo, 1); } // https://github.com/dtolnay/async-trait/issues/106 pub mod issue106 { use async_trait::async_trait; use std::future::Future; #[async_trait] pub trait ProcessPool: Send + Sync { type ThreadPool; async fn spawn(&self, work: F) -> T where F: FnOnce(&Self::ThreadPool) -> Fut + Send, Fut: Future + 'static; } #[async_trait] impl

ProcessPool for &P where P: ?Sized + ProcessPool, { type ThreadPool = P::ThreadPool; async fn spawn(&self, work: F) -> T where F: FnOnce(&Self::ThreadPool) -> Fut + Send, Fut: Future + 'static, { (**self).spawn(work).await } } } // https://github.com/dtolnay/async-trait/issues/110 pub mod issue110 { use async_trait::async_trait; use std::marker::PhantomData; #[async_trait] pub trait Loader { async fn load(&self, key: &str); } pub struct AwsEc2MetadataLoader<'a> { marker: PhantomData<&'a ()>, } #[async_trait] impl Loader for AwsEc2MetadataLoader<'_> { async fn load(&self, _key: &str) {} } } // https://github.com/dtolnay/async-trait/issues/120 pub mod issue120 { #![deny(clippy::trivially_copy_pass_by_ref)] use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(&self); } #[async_trait] impl Trait for () { async fn f(&self) {} } } // https://github.com/dtolnay/async-trait/issues/123 pub mod issue123 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(&self) -> &str where T: 'async_trait, { "default" } } #[async_trait] impl Trait for () {} } // https://github.com/dtolnay/async-trait/issues/129 pub mod issue129 { use async_trait::async_trait; #[async_trait] pub trait TestTrait { async fn a(_b: u8, c: u8) -> u8 { c } } pub struct TestStruct; #[async_trait] impl TestTrait for TestStruct { async fn a(_b: u8, c: u8) -> u8 { c } } } // https://github.com/dtolnay/async-trait/issues/134 pub mod issue134 { use async_trait::async_trait; #[async_trait] pub trait TestTrait { async fn run(self) where Self: Sized, { } } pub struct TestStruct; #[async_trait] impl TestTrait for TestStruct { async fn run(self) where Self: Sized, { } } } // https://github.com/dtolnay/async-trait/pull/125#pullrequestreview-491880881 pub mod drop_order { use crate::executor; use async_trait::async_trait; use std::sync::atomic::{AtomicBool, Ordering}; struct Flagger<'a>(&'a AtomicBool); impl Drop for Flagger<'_> { fn drop(&mut self) { self.0.fetch_xor(true, Ordering::AcqRel); } } #[async_trait] trait Trait { async fn async_trait(_: Flagger<'_>, flag: &AtomicBool); } struct Struct; #[async_trait] impl Trait for Struct { async fn async_trait(_: Flagger<'_>, flag: &AtomicBool) { flag.fetch_or(true, Ordering::AcqRel); } } async fn standalone(_: Flagger<'_>, flag: &AtomicBool) { flag.fetch_or(true, Ordering::AcqRel); } #[async_trait] trait SelfTrait { async fn async_trait(self, flag: &AtomicBool); } #[async_trait] impl SelfTrait for Flagger<'_> { async fn async_trait(self, flag: &AtomicBool) { flag.fetch_or(true, Ordering::AcqRel); } } #[test] fn test_drop_order() { // 0 : 0 ^ 1 = 1 | 1 = 1 (if flagger then block) // 0 : 0 | 1 = 1 ^ 1 = 0 (if block then flagger) let flag = AtomicBool::new(false); executor::block_on_simple(standalone(Flagger(&flag), &flag)); assert!(!flag.load(Ordering::Acquire)); executor::block_on_simple(Struct::async_trait(Flagger(&flag), &flag)); assert!(!flag.load(Ordering::Acquire)); executor::block_on_simple(Flagger(&flag).async_trait(&flag)); assert!(!flag.load(Ordering::Acquire)); } } // https://github.com/dtolnay/async-trait/issues/145 pub mod issue145 { #![deny(clippy::type_complexity)] use async_trait::async_trait; #[async_trait] pub trait ManageConnection: Sized + Send + Sync + 'static { type Connection: Send + 'static; type Error: Send + 'static; async fn connect(&self) -> Result; } } // https://github.com/dtolnay/async-trait/issues/147 pub mod issue147 { #![deny(clippy::let_unit_value)] use async_trait::async_trait; pub struct MyType; #[async_trait] pub trait MyTrait { async fn x(); async fn y() -> (); async fn z(); } #[async_trait] impl MyTrait for MyType { async fn x() {} async fn y() -> () {} async fn z() { unimplemented!() } } } // https://github.com/dtolnay/async-trait/issues/149 pub mod issue149 { use async_trait::async_trait; pub struct Thing; pub trait Ret {} impl Ret for Thing {} pub async fn ok() -> &'static dyn Ret { return &Thing; } #[async_trait] pub trait Trait { async fn fail() -> &'static dyn Ret { return &Thing; } } } // https://github.com/dtolnay/async-trait/issues/152 #[cfg(async_trait_nightly_testing)] pub mod issue152 { use async_trait::async_trait; #[async_trait] pub trait Trait { type Assoc; async fn f(&self) -> Self::Assoc; } pub struct Struct; #[async_trait] impl Trait for Struct { type Assoc = impl Sized; async fn f(&self) -> Self::Assoc {} } } // https://github.com/dtolnay/async-trait/issues/154 pub mod issue154 { #![deny(clippy::items_after_statements)] use async_trait::async_trait; #[async_trait] pub trait MyTrait { async fn f(&self); } pub struct Struct; #[async_trait] impl MyTrait for Struct { async fn f(&self) { const MAX: u16 = 128; println!("{}", MAX); } } } // https://github.com/dtolnay/async-trait/issues/158 pub mod issue158 { use async_trait::async_trait; fn f() {} #[async_trait] #[allow(unused_qualifications)] pub trait Trait { async fn f(&self) { self::f(); } } } // https://github.com/dtolnay/async-trait/issues/161 #[allow(clippy::mut_mut)] pub mod issue161 { use async_trait::async_trait; use futures::future::FutureExt; use std::sync::Arc; #[async_trait] pub trait Trait { async fn f(self: Arc); } pub struct MyStruct(bool); #[async_trait] impl Trait for MyStruct { async fn f(self: Arc) { futures::select! { () = async { println!("{}", self.0); }.fuse() => {} } } } } // https://github.com/dtolnay/async-trait/issues/169 pub mod issue169 { use async_trait::async_trait; #[async_trait] #[allow(unused_qualifications)] pub trait Trait: ::core::marker::Sync { async fn f(&self) {} } pub fn test(_t: &dyn Trait) {} } // https://github.com/dtolnay/async-trait/issues/177 pub mod issue177 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn foo(&self, _callback: impl FnMut(&str) + Send) {} } pub struct Struct; #[async_trait] impl Trait for Struct { async fn foo(&self, _callback: impl FnMut(&str) + Send) {} } } // https://github.com/dtolnay/async-trait/issues/183 pub mod issue183 { #![deny(clippy::shadow_same)] use async_trait::async_trait; #[async_trait] pub trait Foo { async fn foo(_n: i32) {} } } // https://github.com/dtolnay/async-trait/issues/199 pub mod issue199 { use async_trait::async_trait; use std::cell::Cell; struct IncrementOnDrop<'a>(&'a Cell); impl<'a> Drop for IncrementOnDrop<'a> { fn drop(&mut self) { self.0.set(self.0.get() + 1); } } #[async_trait(?Send)] trait Trait { async fn f(counter: &Cell, arg: IncrementOnDrop<'_>); } struct Struct; #[async_trait(?Send)] impl Trait for Struct { async fn f(counter: &Cell, _: IncrementOnDrop<'_>) { assert_eq!(counter.get(), 0); // second arg not dropped yet } } #[test] fn test() { let counter = Cell::new(0); let future = Struct::f(&counter, IncrementOnDrop(&counter)); assert_eq!(counter.get(), 0); drop(future); assert_eq!(counter.get(), 1); } } // https://github.com/dtolnay/async-trait/issues/204 pub mod issue204 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(arg: &impl Trait); async fn g(arg: *const impl Trait); } } // https://github.com/dtolnay/async-trait/issues/210 pub mod issue210 { use async_trait::async_trait; use std::sync::Arc; #[async_trait] pub trait Trait { async fn f(self: Arc) {} } } // https://github.com/dtolnay/async-trait/issues/226 pub mod issue226 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn cfg_param(&self, param: u8); async fn cfg_param_wildcard(&self, _: u8); async fn cfg_param_tuple(&self, (left, right): (u8, u8)); } #[allow(dead_code)] struct Struct; #[async_trait] impl Trait for Struct { async fn cfg_param(&self, #[cfg(any())] param: u8, #[cfg(all())] _unused: u8) {} async fn cfg_param_wildcard(&self, #[cfg(any())] _: u8, #[cfg(all())] _: u8) {} async fn cfg_param_tuple( &self, #[cfg(any())] (left, right): (u8, u8), #[cfg(all())] (_left, _right): (u8, u8), ) { } } } // https://github.com/dtolnay/async-trait/issues/232 pub mod issue232 { use async_trait::async_trait; #[async_trait] pub trait Generic { async fn take_ref(&self, thing: &T); } pub struct One; #[async_trait] impl Generic for One { async fn take_ref(&self, _: &T) {} } pub struct Two; #[async_trait] impl Generic<(T, T)> for Two { async fn take_ref(&self, (a, b): &(T, T)) { let _ = a; let _ = b; } } pub struct Three; #[async_trait] impl Generic<(T, T, T)> for Three { async fn take_ref(&self, (_a, _b, _c): &(T, T, T)) {} } } // https://github.com/dtolnay/async-trait/issues/234 pub mod issue234 { use async_trait::async_trait; pub struct Droppable; impl Drop for Droppable { fn drop(&mut self) {} } pub struct Tuple(T, U); #[async_trait] pub trait Trait { async fn f(arg: Tuple); } pub struct UnderscorePattern; #[async_trait] impl Trait for UnderscorePattern { async fn f(Tuple(_, _int): Tuple) {} } pub struct DotDotPattern; #[async_trait] impl Trait for DotDotPattern { async fn f(Tuple { 1: _int, .. }: Tuple) {} } } // https://github.com/dtolnay/async-trait/issues/236 pub mod issue236 { #![deny(clippy::async_yields_async)] #![allow(clippy::manual_async_fn)] use async_trait::async_trait; use std::future::{self, Future, Ready}; // Does not trigger the lint. pub async fn async_fn() -> Ready<()> { future::ready(()) } #[allow(clippy::async_yields_async)] pub fn impl_future_fn() -> impl Future> { async { future::ready(()) } } // The async_trait attribute turns the former into the latter, so we make it // put its own allow(async_yeilds_async) to remain consistent with async fn. #[async_trait] pub trait Trait { async fn f() -> Ready<()> { future::ready(()) } } } // https://github.com/dtolnay/async-trait/issues/238 pub mod issue238 { #![deny(single_use_lifetimes)] use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(); } pub struct Struct; #[async_trait] impl Trait for &Struct { async fn f() {} } } // https://github.com/dtolnay/async-trait/issues/266 #[cfg(async_trait_nightly_testing)] pub mod issue266 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f() -> !; } #[async_trait] impl Trait for () { async fn f() -> ! { loop { std::thread::sleep(std::time::Duration::from_millis(1)); } } } } // https://github.com/dtolnay/async-trait/issues/277 pub mod issue277 { use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f(&self); } #[async_trait] impl Trait for () { async fn f(mut self: &Self) { g(&mut self); } } fn g(_: &mut &()) {} } async-trait-0.1.83/tests/ui/arg-implementation-detail.rs000064400000000000000000000010051046102023000213300ustar 00000000000000use async_trait::async_trait; pub struct Struct; #[async_trait] pub trait Trait { async fn f((_a, _b): (Struct, Struct)) { // Expands to something like: // // fn f(__arg0: (Struct, Struct)) -> … { // Box::pin(async move { // let (_a, _b) = __arg0; // … // }) // } // // but user's code must not be allowed to name that temporary argument: let _ = __arg0; } } fn main() {} async-trait-0.1.83/tests/ui/arg-implementation-detail.stderr000064400000000000000000000002771046102023000222210ustar 00000000000000error[E0425]: cannot find value `__arg0` in this scope --> tests/ui/arg-implementation-detail.rs:18:17 | 18 | let _ = __arg0; | ^^^^^^ not found in this scope async-trait-0.1.83/tests/ui/bare-trait-object.rs000064400000000000000000000003111046102023000175710ustar 00000000000000#![deny(bare_trait_objects)] use async_trait::async_trait; #[async_trait] trait Trait { async fn f(&self); } #[async_trait] impl Trait for Send + Sync { async fn f(&self) {} } fn main() {} async-trait-0.1.83/tests/ui/bare-trait-object.stderr000064400000000000000000000007471046102023000204650ustar 00000000000000error[E0782]: trait objects must include the `dyn` keyword --> tests/ui/bare-trait-object.rs:11:16 | 11 | impl Trait for Send + Sync { | ^^^^^^^^^^^ | help: add `dyn` keyword before this trait | 11 | impl Trait for dyn Send + Sync { | +++ help: alternatively use a blanket implementation to implement `Trait` for all types that also implement `Send + Sync` | 11 | impl Trait for T { | ++++++++++++++++ ~ async-trait-0.1.83/tests/ui/consider-restricting.rs000064400000000000000000000006511046102023000204430ustar 00000000000000// https://github.com/rust-lang/rust/issues/93828 use async_trait::async_trait; pub trait IntoUrl {} #[async_trait] pub trait ClientExt { async fn publish(&self, url: T); } struct Client; #[async_trait] impl ClientExt for Client { async fn publish(&self, url: T) {} } struct Client2; #[async_trait] impl ClientExt for Client2 { async fn publish(&self, url: T) {} } fn main() {} async-trait-0.1.83/tests/ui/consider-restricting.stderr000064400000000000000000000031531046102023000213220ustar 00000000000000error: future cannot be sent between threads safely --> tests/ui/consider-restricting.rs:16:49 | 16 | async fn publish(&self, url: T) {} | ^^ future created by async block is not `Send` | note: captured value is not `Send` --> tests/ui/consider-restricting.rs:16:41 | 16 | async fn publish(&self, url: T) {} | ^^^ has type `T` which is not `Send` = note: required for the cast from `Pin>` to `Pin + Send + 'async_trait)>>` help: consider further restricting this bound | 16 | async fn publish(&self, url: T) {} | +++++++++++++++++++ error: future cannot be sent between threads safely --> tests/ui/consider-restricting.rs:23:40 | 23 | async fn publish(&self, url: T) {} | ^^ future created by async block is not `Send` | note: captured value is not `Send` --> tests/ui/consider-restricting.rs:23:32 | 23 | async fn publish(&self, url: T) {} | ^^^ has type `T` which is not `Send` = note: required for the cast from `Pin>` to `Pin + Send + 'async_trait)>>` help: consider further restricting this bound | 23 | async fn publish(&self, url: T) {} | +++++++++++++++++++ async-trait-0.1.83/tests/ui/delimiter-span.rs000064400000000000000000000005001046102023000172100ustar 00000000000000#![allow(unused_macro_rules)] use async_trait::async_trait; macro_rules! picky { ($(t:tt)*) => {}; } #[async_trait] trait Trait { async fn method(); } struct Struct; #[async_trait] impl Trait for Struct { async fn method() { picky!({ 123, self }); picky!({ 123 }); } } fn main() {} async-trait-0.1.83/tests/ui/delimiter-span.stderr000064400000000000000000000011611046102023000200730ustar 00000000000000error: no rules expected the token `{` --> tests/ui/delimiter-span.rs:19:16 | 5 | macro_rules! picky { | ------------------ when calling this macro ... 19 | picky!({ 123, self }); | ^ no rules expected this token in macro call | = note: while trying to match sequence start error: no rules expected the token `{` --> tests/ui/delimiter-span.rs:20:16 | 5 | macro_rules! picky { | ------------------ when calling this macro ... 20 | picky!({ 123 }); | ^ no rules expected this token in macro call | = note: while trying to match sequence start async-trait-0.1.83/tests/ui/lifetime-defined-here.rs000064400000000000000000000005731046102023000204200ustar 00000000000000use async_trait::async_trait; #[async_trait] trait Foo { async fn bar(&self, x: &str, y: &'_ str) -> &'static str; } struct S(String); #[async_trait] impl Foo for S { async fn bar(&self, x: &str, y: &'_ str) -> &'static str { if false { &self.0 } else if false { x } else { y } } } fn main() {} async-trait-0.1.83/tests/ui/lifetime-defined-here.stderr000064400000000000000000000025051046102023000212740ustar 00000000000000error: lifetime may not live long enough --> tests/ui/lifetime-defined-here.rs:12:49 | 12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str { | - ^^^^^^^^^^^^ type annotation requires that `'life0` must outlive `'static` | | | lifetime `'life0` defined here error: lifetime may not live long enough --> tests/ui/lifetime-defined-here.rs:12:49 | 12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str { | - ^^^^^^^^^^^^ type annotation requires that `'life1` must outlive `'static` | | | lifetime `'life1` defined here error: lifetime may not live long enough --> tests/ui/lifetime-defined-here.rs:12:49 | 12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str { | -- ^^^^^^^^^^^^ type annotation requires that `'life2` must outlive `'static` | | | lifetime `'life2` defined here help: the following changes may resolve your lifetime errors | = help: replace `'life0` with `'static` = help: replace `'life1` with `'static` = help: replace `'life2` with `'static` async-trait-0.1.83/tests/ui/lifetime-span.rs000064400000000000000000000007611046102023000170410ustar 00000000000000use async_trait::async_trait; struct A; struct B; #[async_trait] pub trait Trait<'r> { async fn method(&'r self); } #[async_trait] impl Trait for A { async fn method(&self) {} } #[async_trait] impl<'r> Trait<'r> for B { async fn method(&self) {} } #[async_trait] pub trait Trait2 { async fn method<'r>(&'r self); } #[async_trait] impl Trait2 for A { async fn method(&self) {} } #[async_trait] impl<'r> Trait2<'r> for B { async fn method(&'r self) {} } fn main() {} async-trait-0.1.83/tests/ui/lifetime-span.stderr000064400000000000000000000020601046102023000177120ustar 00000000000000error[E0726]: implicit elided lifetime not allowed here --> tests/ui/lifetime-span.rs:12:6 | 12 | impl Trait for A { | ^^^^^ expected lifetime parameter | help: indicate the anonymous lifetime | 12 | impl Trait<'_> for A { | ++++ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied --> tests/ui/lifetime-span.rs:32:10 | 32 | impl<'r> Trait2<'r> for B { | ^^^^^^---- help: remove the unnecessary generics | | | expected 0 lifetime arguments | note: trait defined here, with 0 lifetime parameters --> tests/ui/lifetime-span.rs:22:11 | 22 | pub trait Trait2 { | ^^^^^^ error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration --> tests/ui/lifetime-span.rs:33:14 | 23 | async fn method<'r>(&'r self); | ---- lifetimes in impl do not match this method in trait ... 33 | async fn method(&'r self) {} | ^^^^^^^^^^^^^^^^ lifetimes do not match method in trait async-trait-0.1.83/tests/ui/missing-async-in-impl.rs000064400000000000000000000002701046102023000204260ustar 00000000000000use async_trait::async_trait; #[async_trait] pub trait Trait { async fn method(); } pub struct Struct; #[async_trait] impl Trait for Struct { fn method() {} } fn main() {} async-trait-0.1.83/tests/ui/missing-async-in-impl.stderr000064400000000000000000000005761046102023000213160ustar 00000000000000error[E0195]: lifetime parameters or bounds on associated function `method` do not match the trait declaration --> tests/ui/missing-async-in-impl.rs:12:14 | 5 | async fn method(); | -------- lifetimes in impl do not match this associated function in trait ... 12 | fn method() {} | ^ lifetimes do not match associated function in trait async-trait-0.1.83/tests/ui/missing-async-in-trait.rs000064400000000000000000000002701046102023000206100ustar 00000000000000use async_trait::async_trait; #[async_trait] pub trait Trait { fn method(); } pub struct Struct; #[async_trait] impl Trait for Struct { async fn method() {} } fn main() {} async-trait-0.1.83/tests/ui/missing-async-in-trait.stderr000064400000000000000000000005771046102023000215010ustar 00000000000000error[E0195]: lifetime parameters or bounds on associated function `method` do not match the trait declaration --> tests/ui/missing-async-in-trait.rs:12:14 | 5 | fn method(); | - lifetimes in impl do not match this associated function in trait ... 12 | async fn method() {} | ^^^^^^^^ lifetimes do not match associated function in trait async-trait-0.1.83/tests/ui/missing-body.rs000064400000000000000000000002621046102023000167040ustar 00000000000000use async_trait::async_trait; #[async_trait] trait Trait { async fn f(&self); } struct Thing; #[async_trait] impl Trait for Thing { async fn f(&self); } fn main() {} async-trait-0.1.83/tests/ui/missing-body.stderr000064400000000000000000000004031046102023000175600ustar 00000000000000error: associated function in `impl` without body --> tests/ui/missing-body.rs:12:5 | 12 | async fn f(&self); | ^^^^^^^^^^^^^^^^^- | | | help: provide a definition for the function: `{ }` async-trait-0.1.83/tests/ui/must-use.rs000064400000000000000000000003741046102023000160660ustar 00000000000000#![deny(unused_must_use)] use async_trait::async_trait; #[async_trait] trait Interface { async fn f(&self); } struct Thing; #[async_trait] impl Interface for Thing { async fn f(&self) {} } pub async fn f() { Thing.f(); } fn main() {} async-trait-0.1.83/tests/ui/must-use.stderr000064400000000000000000000011211046102023000167340ustar 00000000000000error: unused pinned boxed `Future` trait object that must be used --> tests/ui/must-use.rs:18:5 | 18 | Thing.f(); | ^^^^^^^^^ | = note: futures do nothing unless you `.await` or poll them note: the lint level is defined here --> tests/ui/must-use.rs:1:9 | 1 | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ error: unused return value of `Interface::f` that must be used --> tests/ui/must-use.rs:18:5 | 18 | Thing.f(); | ^^^^^^^^^ | help: use `let _ = ...` to ignore the resulting value | 18 | let _ = Thing.f(); | +++++++ async-trait-0.1.83/tests/ui/no-attribute-macro.rs000064400000000000000000000002431046102023000200130ustar 00000000000000pub trait Trait { async fn method(&self); } pub struct Struct; impl Trait for Struct { async fn method(&self) {} } fn main() { let _: &dyn Trait; } async-trait-0.1.83/tests/ui/no-attribute-macro.stderr000064400000000000000000000017201046102023000206730ustar 00000000000000error[E0038]: the trait `Trait` cannot be made into an object --> tests/ui/no-attribute-macro.rs:12:12 | 12 | let _: &dyn Trait; | ^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> tests/ui/no-attribute-macro.rs:2:14 | 1 | pub trait Trait { | ----- this trait cannot be made into an object... 2 | async fn method(&self); | ^^^^^^ ...because method `method` is `async` = help: consider moving `method` to another trait = help: only type `Struct` is seen to implement the trait in this crate, consider using it directly instead = note: `Trait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type async-trait-0.1.83/tests/ui/self-span.rs000064400000000000000000000006231046102023000161710ustar 00000000000000use async_trait::async_trait; pub struct S {} pub enum E { V {}, } #[async_trait] pub trait Trait { async fn method(self); } #[async_trait] impl Trait for S { async fn method(self) { let _: () = self; let _: Self = Self; } } #[async_trait] impl Trait for E { async fn method(self) { let _: () = self; let _: Self = Self::V; } } fn main() {} async-trait-0.1.83/tests/ui/self-span.stderr000064400000000000000000000017521046102023000170540ustar 00000000000000error[E0308]: mismatched types --> tests/ui/self-span.rs:17:21 | 17 | let _: () = self; | -- ^^^^ expected `()`, found `S` | | | expected due to this error: the `Self` constructor can only be used with tuple or unit structs --> tests/ui/self-span.rs:18:23 | 18 | let _: Self = Self; | ^^^^ help: use curly brackets: `Self { /* fields */ }` error[E0308]: mismatched types --> tests/ui/self-span.rs:25:21 | 25 | let _: () = self; | -- ^^^^ expected `()`, found `E` | | | expected due to this error[E0533]: expected value, found struct variant `Self::V` --> tests/ui/self-span.rs:26:23 | 26 | let _: Self = Self::V; | ^^^^^^^ not a value | help: you might have meant to create a new value of the struct | 26 | let _: Self = Self::V {}; | ++ async-trait-0.1.83/tests/ui/send-not-implemented.rs000064400000000000000000000006241046102023000203320ustar 00000000000000use async_trait::async_trait; use std::sync::Mutex; async fn f() {} #[async_trait] trait Test { async fn test(&self) { let mutex = Mutex::new(()); let _guard = mutex.lock().unwrap(); f().await; } async fn test_ret(&self) -> bool { let mutex = Mutex::new(()); let _guard = mutex.lock().unwrap(); f().await; true } } fn main() {} async-trait-0.1.83/tests/ui/send-not-implemented.stderr000064400000000000000000000043031046102023000212070ustar 00000000000000error: future cannot be sent between threads safely --> tests/ui/send-not-implemented.rs:8:26 | 8 | async fn test(&self) { | __________________________^ 9 | | let mutex = Mutex::new(()); 10 | | let _guard = mutex.lock().unwrap(); 11 | | f().await; 12 | | } | |_____^ future created by async block is not `Send` | = help: within `{async block@$DIR/tests/ui/send-not-implemented.rs:8:26: 12:6}`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `{async block@$DIR/tests/ui/send-not-implemented.rs:8:26: 12:6}: Send` note: future is not `Send` as this value is used across an await --> tests/ui/send-not-implemented.rs:11:13 | 10 | let _guard = mutex.lock().unwrap(); | ------ has type `MutexGuard<'_, ()>` which is not `Send` 11 | f().await; | ^^^^^ await occurs here, with `_guard` maybe used later = note: required for the cast from `Pin>` to `Pin + Send>>` error: future cannot be sent between threads safely --> tests/ui/send-not-implemented.rs:14:38 | 14 | async fn test_ret(&self) -> bool { | ______________________________________^ 15 | | let mutex = Mutex::new(()); 16 | | let _guard = mutex.lock().unwrap(); 17 | | f().await; 18 | | true 19 | | } | |_____^ future created by async block is not `Send` | = help: within `{async block@$DIR/tests/ui/send-not-implemented.rs:14:38: 19:6}`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `{async block@$DIR/tests/ui/send-not-implemented.rs:14:38: 19:6}: Send` note: future is not `Send` as this value is used across an await --> tests/ui/send-not-implemented.rs:17:13 | 16 | let _guard = mutex.lock().unwrap(); | ------ has type `MutexGuard<'_, ()>` which is not `Send` 17 | f().await; | ^^^^^ await occurs here, with `_guard` maybe used later = note: required for the cast from `Pin>` to `Pin + Send>>` async-trait-0.1.83/tests/ui/unreachable.rs000064400000000000000000000004161046102023000165520ustar 00000000000000#![deny(warnings)] use async_trait::async_trait; #[async_trait] pub trait Trait { async fn f() { unimplemented!() } } #[async_trait] pub trait TraitFoo { async fn f() { let _y = unimplemented!(); let _z = _y; } } fn main() {} async-trait-0.1.83/tests/ui/unreachable.stderr000064400000000000000000000007251046102023000174340ustar 00000000000000error: unreachable statement --> tests/ui/unreachable.rs:16:9 | 15 | let _y = unimplemented!(); | ---------------- any code following this expression is unreachable 16 | let _z = _y; | ^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> tests/ui/unreachable.rs:1:9 | 1 | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(unreachable_code)]` implied by `#[deny(warnings)]` async-trait-0.1.83/tests/ui/unsupported-self.rs000064400000000000000000000003131046102023000176140ustar 00000000000000use async_trait::async_trait; #[async_trait] pub trait Trait { async fn method(); } #[async_trait] impl Trait for &'static str { async fn method() { let _ = Self; } } fn main() {} async-trait-0.1.83/tests/ui/unsupported-self.stderr000064400000000000000000000002551046102023000205000ustar 00000000000000error: the `Self` constructor can only be used with tuple or unit structs --> tests/ui/unsupported-self.rs:11:17 | 11 | let _ = Self; | ^^^^