#![cfg_attr( async_trait_nightly_testing, feature(min_specialization, type_alias_impl_trait) )] #![deny(rust_2021_compatibility)] #![allow( clippy::let_unit_value, clippy::missing_panics_doc, clippy::missing_safety_doc, clippy::needless_return, 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] pub(crate) unsafe trait UnsafeTraitPubCrate {} #[async_trait] 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; } } } 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); } } } pub async fn test_inference() { #[async_trait] pub trait Trait { async fn f() -> Box> { Box::new(std::iter::empty()) } } } 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!() } } } // https://github.com/dtolnay/async-trait/issues/1 pub mod issue1 { use async_trait::async_trait; #[async_trait] 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] trait Issue11 { async fn example(self: Arc); } 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; trait Trait {} #[async_trait] 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] trait Issue17 { async fn f(&self); } struct Struct { 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); } } 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; struct Str<'a>(&'a str); #[async_trait] 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] trait Trait2 { async fn f(); } #[async_trait] impl<'a> Trait2 for &'a () { async fn f() {} } #[async_trait] 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] #[cfg_attr(miri, ignore)] // https://github.com/matklad/once_cell/pull/185 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(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 #[cfg(async_trait_nightly_testing)] 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 { #[rustversion::since(1.40)] // procedural macros cannot expand to macro definitions in 1.39. #[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] trait Trait { async fn f(&self); } #[async_trait] impl Trait for 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] 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 } } }; } 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] 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] 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 #[cfg(async_trait_nightly_testing)] pub mod issue134 { use async_trait::async_trait; #[async_trait] 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] trait Trait { type Assoc; async fn f(&self) -> Self::Assoc; } 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] 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 #[deny(where_clauses_object_safety)] pub mod issue169 { use async_trait::async_trait; #[async_trait] 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] 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)); } 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(()) } } }