blob: 3ea2d1577144dc7b390813baee889e94f3be732a [file] [log] [blame]
Andrew Walbrand1b91c72020-08-11 17:12:08 +01001#![cfg_attr(async_trait_nightly_testing, feature(specialization, const_generics))]
2
3use async_trait::async_trait;
4
5pub mod executor;
6
7// Dummy module to check that the expansion refer to rust's core crate
8mod core {}
9
10#[async_trait]
11trait Trait {
12 type Assoc;
13
14 async fn selfvalue(self)
15 where
16 Self: Sized,
17 {
18 }
19
20 async fn selfref(&self) {}
21
22 async fn selfmut(&mut self) {}
23
24 async fn required() -> Self::Assoc;
25
26 async fn elided_lifetime(_x: &str) {}
27
28 async fn explicit_lifetime<'a>(_x: &'a str) {}
29
30 async fn generic_type_param<T: Send>(x: Box<T>) -> T {
31 *x
32 }
33
34 async fn calls(&self) {
35 self.selfref().await;
36 Self::elided_lifetime("").await;
37 <Self>::elided_lifetime("").await;
38 }
39
40 async fn calls_mut(&mut self) {
41 self.selfmut().await;
42 }
43}
44
45struct Struct;
46
47#[async_trait]
48impl Trait for Struct {
49 type Assoc = ();
50
51 async fn selfvalue(self) {}
52
53 async fn selfref(&self) {}
54
55 async fn selfmut(&mut self) {}
56
57 async fn required() -> Self::Assoc {}
58
59 async fn elided_lifetime(_x: &str) {}
60
61 async fn explicit_lifetime<'a>(_x: &'a str) {}
62
63 async fn generic_type_param<T: Send>(x: Box<T>) -> T {
64 *x
65 }
66
67 async fn calls(&self) {
68 self.selfref().await;
69 Self::elided_lifetime("").await;
70 <Self>::elided_lifetime("").await;
71 }
72
73 async fn calls_mut(&mut self) {
74 self.selfmut().await;
75 }
76}
77
78pub async fn test() {
79 let mut s = Struct;
80 s.selfref().await;
81 s.selfmut().await;
82 s.selfvalue().await;
83
84 Struct::required().await;
85 Struct::elided_lifetime("").await;
86 Struct::explicit_lifetime("").await;
87 Struct::generic_type_param(Box::new("")).await;
88
89 let mut s = Struct;
90 s.calls().await;
91 s.calls_mut().await;
92}
93
94pub async fn test_object_safe_without_default() {
95 #[async_trait]
96 trait ObjectSafe {
97 async fn f(&self);
98 }
99
100 #[async_trait]
101 impl ObjectSafe for Struct {
102 async fn f(&self) {}
103 }
104
105 let object = &Struct as &dyn ObjectSafe;
106 object.f().await;
107}
108
109pub async fn test_object_safe_with_default() {
110 #[async_trait]
111 trait ObjectSafe: Sync {
112 async fn f(&self) {}
113 }
114
115 #[async_trait]
116 impl ObjectSafe for Struct {
117 async fn f(&self) {}
118 }
119
120 let object = &Struct as &dyn ObjectSafe;
121 object.f().await;
122}
123
124pub async fn test_object_no_send() {
125 #[async_trait(?Send)]
126 trait ObjectSafe: Sync {
127 async fn f(&self) {}
128 }
129
130 #[async_trait(?Send)]
131 impl ObjectSafe for Struct {
132 async fn f(&self) {}
133 }
134
135 let object = &Struct as &dyn ObjectSafe;
136 object.f().await;
137}
138
139#[async_trait]
140pub unsafe trait UnsafeTrait {}
141
142#[async_trait]
143unsafe impl UnsafeTrait for () {}
144
145#[async_trait]
146pub(crate) unsafe trait UnsafeTraitPubCrate {}
147
148#[async_trait]
149unsafe trait UnsafeTraitPrivate {}
150
151// https://github.com/dtolnay/async-trait/issues/1
152pub mod issue1 {
153 use async_trait::async_trait;
154
155 #[async_trait]
156 trait Issue1 {
157 async fn f<U>(&self);
158 }
159
160 #[async_trait]
161 impl<T: Sync> Issue1 for Vec<T> {
162 async fn f<U>(&self) {}
163 }
164}
165
166// https://github.com/dtolnay/async-trait/issues/2
167pub mod issue2 {
168 use async_trait::async_trait;
169 use std::future::Future;
170
171 #[async_trait]
172 pub trait Issue2: Future {
173 async fn flatten(self) -> <Self::Output as Future>::Output
174 where
175 Self::Output: Future + Send,
176 Self: Sized,
177 {
178 let nested_future = self.await;
179 nested_future.await
180 }
181 }
182}
183
184// https://github.com/dtolnay/async-trait/issues/9
185pub mod issue9 {
186 use async_trait::async_trait;
187
188 #[async_trait]
189 pub trait Issue9: Sized + Send {
190 async fn f(_x: Self) {}
191 }
192}
193
194// https://github.com/dtolnay/async-trait/issues/11
195pub mod issue11 {
196 use async_trait::async_trait;
197 use std::sync::Arc;
198
199 #[async_trait]
200 trait Issue11 {
201 async fn example(self: Arc<Self>);
202 }
203
204 struct Struct;
205
206 #[async_trait]
207 impl Issue11 for Struct {
208 async fn example(self: Arc<Self>) {}
209 }
210}
211
212// https://github.com/dtolnay/async-trait/issues/15
213pub mod issue15 {
214 use async_trait::async_trait;
215 use std::marker::PhantomData;
216
217 trait Trait {}
218
219 #[async_trait]
220 trait Issue15 {
221 async fn myfn(&self, _: PhantomData<dyn Trait + Send>) {}
222 }
223}
224
225// https://github.com/dtolnay/async-trait/issues/17
226pub mod issue17 {
227 use async_trait::async_trait;
228
229 #[async_trait]
230 trait Issue17 {
231 async fn f(&self);
232 }
233
234 struct Struct {
235 string: String,
236 }
237
238 #[async_trait]
239 impl Issue17 for Struct {
240 async fn f(&self) {
241 println!("{}", self.string);
242 }
243 }
244}
245
246// https://github.com/dtolnay/async-trait/issues/23
247pub mod issue23 {
248 use async_trait::async_trait;
249
250 #[async_trait]
251 pub trait Issue23 {
252 async fn f(self);
253
254 async fn g(mut self)
255 where
256 Self: Sized,
257 {
258 do_something(&mut self);
259 }
260 }
261
262 struct S {}
263
264 #[async_trait]
265 impl Issue23 for S {
266 async fn f(mut self) {
267 do_something(&mut self);
268 }
269 }
270
271 fn do_something<T>(_: &mut T) {}
272}
273
274// https://github.com/dtolnay/async-trait/issues/25
275#[cfg(async_trait_nightly_testing)]
276pub mod issue25 {
277 use crate::executor;
278 use async_trait::async_trait;
279 use std::fmt::{Display, Write};
280
281 #[async_trait]
282 trait AsyncToString {
283 async fn async_to_string(&self) -> String;
284 }
285
286 #[async_trait]
287 impl AsyncToString for String {
288 async fn async_to_string(&self) -> String {
289 "special".to_owned()
290 }
291 }
292
293 macro_rules! hide_from_stable_parser {
294 ($($tt:tt)*) => {
295 $($tt)*
296 };
297 }
298
299 hide_from_stable_parser! {
300 #[async_trait]
301 impl<T: ?Sized + Display + Sync> AsyncToString for T {
302 default async fn async_to_string(&self) -> String {
303 let mut buf = String::new();
304 buf.write_fmt(format_args!("{}", self)).unwrap();
305 buf
306 }
307 }
308 }
309
310 #[test]
311 fn test() {
312 let fut = true.async_to_string();
313 assert_eq!(executor::block_on_simple(fut), "true");
314
315 let string = String::new();
316 let fut = string.async_to_string();
317 assert_eq!(executor::block_on_simple(fut), "special");
318 }
319}
320
321// https://github.com/dtolnay/async-trait/issues/28
322pub mod issue28 {
323 use async_trait::async_trait;
324
325 struct Str<'a>(&'a str);
326
327 #[async_trait]
328 trait Trait1<'a> {
329 async fn f(x: Str<'a>) -> &'a str;
330 async fn g(x: Str<'a>) -> &'a str {
331 x.0
332 }
333 }
334
335 #[async_trait]
336 impl<'a> Trait1<'a> for str {
337 async fn f(x: Str<'a>) -> &'a str {
338 x.0
339 }
340 }
341
342 #[async_trait]
343 trait Trait2 {
344 async fn f();
345 }
346
347 #[async_trait]
348 impl<'a> Trait2 for &'a () {
349 async fn f() {}
350 }
351
352 #[async_trait]
353 trait Trait3<'a, 'b> {
354 async fn f(_: &'a &'b ()); // chain 'a and 'b
355 async fn g(_: &'b ()); // chain 'b only
356 async fn h(); // do not chain
357 }
358}
359
360// https://github.com/dtolnay/async-trait/issues/31
361pub mod issue31 {
362 use async_trait::async_trait;
363
364 pub struct Struct<'a> {
365 pub name: &'a str,
366 }
367
368 #[async_trait]
369 pub trait Trait<'a> {
370 async fn hello(thing: Struct<'a>) -> String;
371 async fn hello_twice(one: Struct<'a>, two: Struct<'a>) -> String {
372 let str1 = Self::hello(one).await;
373 let str2 = Self::hello(two).await;
374 str1 + &str2
375 }
376 }
377}
378
379// https://github.com/dtolnay/async-trait/issues/42
380pub mod issue42 {
381 use async_trait::async_trait;
382
383 #[async_trait]
384 pub trait Context: Sized {
385 async fn from_parts() -> Self;
386 }
387
388 pub struct TokenContext;
389
390 #[async_trait]
391 impl Context for TokenContext {
392 async fn from_parts() -> TokenContext {
393 TokenContext
394 }
395 }
396}
397
398// https://github.com/dtolnay/async-trait/issues/44
399pub mod issue44 {
400 use async_trait::async_trait;
401
402 #[async_trait]
403 pub trait StaticWithWhereSelf
404 where
405 Box<Self>: Sized,
406 Self: Sized + Send,
407 {
408 async fn get_one() -> u8 {
409 1
410 }
411 }
412
413 pub struct Struct;
414
415 #[async_trait]
416 impl StaticWithWhereSelf for Struct {}
417}
418
419// https://github.com/dtolnay/async-trait/issues/45
420pub mod issue45 {
421 use crate::executor;
422 use async_trait::async_trait;
423 use std::fmt::Debug;
424 use std::sync::atomic::{AtomicU64, Ordering};
425 use std::sync::{Arc, Mutex};
426 use tracing::event::Event;
427 use tracing::field::{Field, Visit};
428 use tracing::span::{Attributes, Id, Record};
429 use tracing::{info, instrument, subscriber, Metadata, Subscriber};
430
431 #[async_trait]
432 pub trait Parent {
433 async fn foo(&mut self, v: usize);
434 }
435
436 #[async_trait]
437 pub trait Child {
438 async fn bar(&self);
439 }
440
441 #[derive(Debug)]
442 struct Impl(usize);
443
444 #[async_trait]
445 impl Parent for Impl {
446 #[instrument]
447 async fn foo(&mut self, v: usize) {
448 self.0 = v;
449 self.bar().await;
450 }
451 }
452
453 #[async_trait]
454 impl Child for Impl {
455 // Let's check that tracing detects the renaming of the `self` variable
456 // too, as tracing::instrument is not going to be able to skip the
457 // `self` argument if it can't find it in the function signature.
458 #[instrument(skip(self))]
459 async fn bar(&self) {
460 info!(val = self.0);
461 }
462 }
463
464 // A simple subscriber implementation to test the behavior of async-trait
465 // with tokio-rs/tracing. This implementation is not robust against race
466 // conditions, but it's not an issue here as we are only polling on a single
467 // future at a time.
468 #[derive(Debug)]
469 struct SubscriberInner {
470 current_depth: AtomicU64,
471 // We assert that nested functions work. If the fix were to break, we
472 // would see two top-level functions instead of `bar` nested in `foo`.
473 max_depth: AtomicU64,
474 max_span_id: AtomicU64,
475 // Name of the variable / value / depth when the event was recorded.
476 value: Mutex<Option<(&'static str, u64, u64)>>,
477 }
478
479 #[derive(Debug, Clone)]
480 struct TestSubscriber {
481 inner: Arc<SubscriberInner>,
482 }
483
484 impl TestSubscriber {
485 fn new() -> Self {
486 TestSubscriber {
487 inner: Arc::new(SubscriberInner {
488 current_depth: AtomicU64::new(0),
489 max_depth: AtomicU64::new(0),
490 max_span_id: AtomicU64::new(1),
491 value: Mutex::new(None),
492 }),
493 }
494 }
495 }
496
497 struct U64Visitor(Option<(&'static str, u64)>);
498
499 impl Visit for U64Visitor {
500 fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
501
502 fn record_u64(&mut self, field: &Field, value: u64) {
503 self.0 = Some((field.name(), value));
504 }
505 }
506
507 impl Subscriber for TestSubscriber {
508 fn enabled(&self, _metadata: &Metadata) -> bool {
509 true
510 }
511 fn new_span(&self, _span: &Attributes) -> Id {
512 Id::from_u64(self.inner.max_span_id.fetch_add(1, Ordering::AcqRel))
513 }
514 fn record(&self, _span: &Id, _values: &Record) {}
515 fn record_follows_from(&self, _span: &Id, _follows: &Id) {}
516 fn event(&self, event: &Event) {
517 let mut visitor = U64Visitor(None);
518 event.record(&mut visitor);
519 if let Some((s, v)) = visitor.0 {
520 let current_depth = self.inner.current_depth.load(Ordering::Acquire);
521 *self.inner.value.lock().unwrap() = Some((s, v, current_depth));
522 }
523 }
524 fn enter(&self, _span: &Id) {
525 let old_depth = self.inner.current_depth.fetch_add(1, Ordering::AcqRel);
526 if old_depth + 1 > self.inner.max_depth.load(Ordering::Acquire) {
527 self.inner.max_depth.fetch_add(1, Ordering::AcqRel);
528 }
529 }
530 fn exit(&self, _span: &Id) {
531 self.inner.current_depth.fetch_sub(1, Ordering::AcqRel);
532 }
533 }
534
535 #[test]
536 fn tracing() {
537 // Create the future outside of the subscriber, as no call to tracing
538 // should be made until the future is polled.
539 let mut struct_impl = Impl(0);
540 let fut = struct_impl.foo(5);
541 let subscriber = TestSubscriber::new();
542 subscriber::with_default(subscriber.clone(), || executor::block_on_simple(fut));
543 // Did we enter bar inside of foo?
544 assert_eq!(subscriber.inner.max_depth.load(Ordering::Acquire), 2);
545 // Have we exited all spans?
546 assert_eq!(subscriber.inner.current_depth.load(Ordering::Acquire), 0);
547 // Did we create only two spans? Note: spans start at 1, hence the -1.
548 assert_eq!(subscriber.inner.max_span_id.load(Ordering::Acquire) - 1, 2);
549 // Was the value recorded at the right depth i.e. in the right function?
550 // If so, was it the expected value?
551 assert_eq!(*subscriber.inner.value.lock().unwrap(), Some(("val", 5, 2)));
552 }
553}
554
555// https://github.com/dtolnay/async-trait/issues/46
556pub mod issue46 {
557 use async_trait::async_trait;
558
559 macro_rules! implement_commands_workaround {
560 ($tyargs:tt : $ty:tt) => {
561 #[async_trait]
562 pub trait AsyncCommands1: Sized {
563 async fn f<$tyargs: $ty>(&mut self, x: $tyargs) {
564 self.f(x).await
565 }
566 }
567 };
568 }
569
570 implement_commands_workaround!(K: Send);
571
572 macro_rules! implement_commands {
573 ($tyargs:ident : $ty:ident) => {
574 #[async_trait]
575 pub trait AsyncCommands2: Sized {
576 async fn f<$tyargs: $ty>(&mut self, x: $tyargs) {
577 self.f(x).await
578 }
579 }
580 };
581 }
582
583 implement_commands!(K: Send);
584}
585
586// https://github.com/dtolnay/async-trait/issues/53
587pub mod issue53 {
588 use async_trait::async_trait;
589
590 pub struct Unit;
591 pub struct Tuple(u8);
592 pub struct Struct {
593 pub x: u8,
594 }
595
596 #[async_trait]
597 pub trait Trait {
598 async fn method();
599 }
600
601 #[async_trait]
602 impl Trait for Unit {
603 async fn method() {
604 let _ = Self;
605 }
606 }
607
608 #[async_trait]
609 impl Trait for Tuple {
610 async fn method() {
611 let _ = Self(0);
612 }
613 }
614
615 #[async_trait]
616 impl Trait for Struct {
617 async fn method() {
618 let _ = Self { x: 0 };
619 }
620 }
621
622 #[async_trait]
623 impl Trait for std::marker::PhantomData<Struct> {
624 async fn method() {
625 let _ = Self;
626 }
627 }
628}
629
630// https://github.com/dtolnay/async-trait/issues/57
631#[cfg(async_trait_nightly_testing)]
632pub mod issue57 {
633 use crate::executor;
634 use async_trait::async_trait;
635
636 #[async_trait]
637 trait Trait {
638 async fn const_generic<T: Send, const C: usize>(_: [T; C]) {}
639 }
640
641 struct Struct;
642
643 #[async_trait]
644 impl Trait for Struct {
645 async fn const_generic<T: Send, const C: usize>(_: [T; C]) {}
646 }
647
648 #[test]
649 fn test() {
650 let fut = Struct::const_generic([0; 10]);
651 executor::block_on_simple(fut);
652 }
653}
654
655// https://github.com/dtolnay/async-trait/issues/68
656pub mod issue68 {
657 #[rustversion::since(1.40)] // procedural macros cannot expand to macro definitions in 1.39.
658 #[async_trait::async_trait]
659 pub trait Example {
660 async fn method(&self) {
661 macro_rules! t {
662 () => {{
663 let _: &Self = self;
664 }};
665 }
666 t!();
667 }
668 }
669}
670
671// https://github.com/dtolnay/async-trait/issues/73
672pub mod issue73 {
673 use async_trait::async_trait;
674
675 #[async_trait]
676 pub trait Example {
677 const ASSOCIATED: &'static str;
678
679 async fn associated(&self) {
680 println!("Associated:{}", Self::ASSOCIATED);
681 }
682 }
683}
684
685// https://github.com/dtolnay/async-trait/issues/81
686pub mod issue81 {
687 use async_trait::async_trait;
688
689 #[async_trait]
690 pub trait Trait {
691 async fn handle(&self);
692 }
693
694 pub enum Enum {
695 Variant,
696 }
697
698 #[async_trait]
699 impl Trait for Enum {
700 async fn handle(&self) {
701 let Enum::Variant = self;
702 let Self::Variant = self;
703 }
704 }
705}
706
707// https://github.com/dtolnay/async-trait/issues/83
708pub mod issue83 {
709 use async_trait::async_trait;
710
711 #[async_trait]
712 pub trait Trait {
713 async fn f(&self) {}
714 async fn g(self: &Self) {}
715 }
716}
717
718// https://github.com/dtolnay/async-trait/issues/85
719pub mod issue85 {
720 #![deny(non_snake_case)]
721
722 use async_trait::async_trait;
723
724 #[async_trait]
725 pub trait Trait {
726 #[allow(non_snake_case)]
727 async fn camelCase();
728 }
729
730 pub struct Struct;
731
732 #[async_trait]
733 impl Trait for Struct {
734 async fn camelCase() {}
735 }
736}
737
738// https://github.com/dtolnay/async-trait/issues/87
739pub mod issue87 {
740 use async_trait::async_trait;
741
742 #[async_trait]
743 pub trait Trait {
744 async fn f(&self);
745 }
746
747 pub enum Tuple {
748 V(),
749 }
750
751 pub enum Struct {
752 V {},
753 }
754
755 #[async_trait]
756 impl Trait for Tuple {
757 async fn f(&self) {
758 let Tuple::V() = self;
759 let Self::V() = self;
760 let _ = Self::V;
761 let _ = Self::V();
762 }
763 }
764
765 #[async_trait]
766 impl Trait for Struct {
767 async fn f(&self) {
768 let Struct::V {} = self;
769 let Self::V {} = self;
770 let _ = Self::V {};
771 }
772 }
773}
774
775// https://github.com/dtolnay/async-trait/issues/89
776pub mod issue89 {
777 #![allow(bare_trait_objects)]
778
779 use async_trait::async_trait;
780
781 #[async_trait]
782 trait Trait {
783 async fn f(&self);
784 }
785
786 #[async_trait]
787 impl Trait for Send + Sync {
788 async fn f(&self) {}
789 }
790
791 #[async_trait]
792 impl Trait for dyn Fn(i8) + Send + Sync {
793 async fn f(&self) {}
794 }
795
796 #[async_trait]
797 impl Trait for (dyn Fn(u8) + Send + Sync) {
798 async fn f(&self) {}
799 }
800}
801
802// https://github.com/dtolnay/async-trait/issues/92
803pub mod issue92 {
804 use async_trait::async_trait;
805
806 macro_rules! mac {
807 ($($tt:tt)*) => {
808 $($tt)*
809 };
810 }
811
812 pub struct Struct<T> {
813 _x: T,
814 }
815
816 impl<T> Struct<T> {
817 const ASSOCIATED1: &'static str = "1";
818 async fn associated1() {}
819 }
820
821 #[async_trait]
822 pub trait Trait
823 where
824 mac!(Self): Send,
825 {
826 const ASSOCIATED2: &'static str;
827 type Associated2;
828
829 #[allow(path_statements, clippy::no_effect)]
830 async fn associated2(&self) {
831 // trait items
832 mac!(let _: Self::Associated2;);
833 mac!(let _: <Self>::Associated2;);
834 mac!(let _: <Self as Trait>::Associated2;);
835 mac!(Self::ASSOCIATED2;);
836 mac!(<Self>::ASSOCIATED2;);
837 mac!(<Self as Trait>::ASSOCIATED2;);
838 mac!(let _ = Self::associated2(self););
839 mac!(let _ = <Self>::associated2(self););
840 mac!(let _ = <Self as Trait>::associated2(self););
841 }
842 }
843
844 #[async_trait]
845 impl<T: Send + Sync> Trait for Struct<T>
846 where
847 mac!(Self): Send,
848 {
849 const ASSOCIATED2: &'static str = "2";
850 type Associated2 = ();
851
852 #[allow(path_statements, clippy::no_effect)]
853 async fn associated2(&self) {
854 // inherent items
855 mac!(Self::ASSOCIATED1;);
856 mac!(<Self>::ASSOCIATED1;);
857 mac!(let _ = Self::associated1(););
858 mac!(let _ = <Self>::associated1(););
859
860 // trait items
861 mac!(let _: <Self as Trait>::Associated2;);
862 mac!(Self::ASSOCIATED2;);
863 mac!(<Self>::ASSOCIATED2;);
864 mac!(<Self as Trait>::ASSOCIATED2;);
865 mac!(let _ = Self::associated2(self););
866 mac!(let _ = <Self>::associated2(self););
867 mac!(let _ = <Self as Trait>::associated2(self););
868 }
869 }
870
871 pub struct Unit;
872
873 #[async_trait]
874 impl Trait for Unit {
875 const ASSOCIATED2: &'static str = "2";
876 type Associated2 = ();
877
878 async fn associated2(&self) {
879 mac!(let Self: Self = *self;);
880 }
881 }
882}
883
884// https://github.com/dtolnay/async-trait/issues/104
885mod issue104 {
886 use async_trait::async_trait;
887
888 #[async_trait]
889 trait T1 {
890 async fn id(&self) -> i32;
891 }
892
893 macro_rules! impl_t1 {
894 ($ty:ty, $id:expr) => {
895 #[async_trait]
896 impl T1 for $ty {
897 async fn id(&self) -> i32 {
898 $id
899 }
900 }
901 };
902 }
903
904 struct Foo;
905
906 impl_t1!(Foo, 1);
907}
908
909// https://github.com/dtolnay/async-trait/issues/106
910mod issue106 {
911 use async_trait::async_trait;
912 use std::future::Future;
913
914 #[async_trait]
915 pub trait ProcessPool: Send + Sync {
916 type ThreadPool;
917
918 async fn spawn<F, Fut, T>(&self, work: F) -> T
919 where
920 F: FnOnce(&Self::ThreadPool) -> Fut + Send,
921 Fut: Future<Output = T> + 'static;
922 }
923
924 #[async_trait]
925 impl<P: ?Sized> ProcessPool for &P
926 where
927 P: ProcessPool,
928 {
929 type ThreadPool = P::ThreadPool;
930
931 async fn spawn<F, Fut, T>(&self, work: F) -> T
932 where
933 F: FnOnce(&Self::ThreadPool) -> Fut + Send,
934 Fut: Future<Output = T> + 'static,
935 {
936 (**self).spawn(work).await
937 }
938 }
939}
940
941// https://github.com/dtolnay/async-trait/issues/110
942mod issue110 {
943 #![deny(clippy::all)]
944
945 use async_trait::async_trait;
946 use std::marker::PhantomData;
947
948 #[async_trait]
949 pub trait Loader {
950 async fn load(&self, key: &str);
951 }
952
953 pub struct AwsEc2MetadataLoader<'a> {
954 marker: PhantomData<&'a ()>,
955 }
956
957 #[async_trait]
958 impl Loader for AwsEc2MetadataLoader<'_> {
959 async fn load(&self, _key: &str) {}
960 }
961}