8
8
//! environment.
9
9
10
10
#[ cfg( all( test, feature = "std" ) ) ]
11
- use crate :: sync:: Mutex ;
11
+ use crate :: sync:: { Arc , Mutex } ;
12
12
use crate :: util:: async_poll:: { MaybeSend , MaybeSync } ;
13
13
14
14
#[ cfg( all( test, not( feature = "std" ) ) ) ]
15
- use core:: cell:: RefCell ;
15
+ use core:: cell:: { Rc , RefCell } ;
16
+ #[ cfg( test) ]
17
+ use core:: convert:: Infallible ;
16
18
use core:: future:: Future ;
17
19
#[ cfg( test) ]
18
20
use core:: pin:: Pin ;
21
+ #[ cfg( test) ]
22
+ use core:: task:: { Context , Poll } ;
19
23
20
- /// A generic trait which is able to spawn futures in the background.
24
+ /// A generic trait which is able to spawn futures to be polled in the background.
25
+ ///
26
+ /// When the spawned future completes, the returned [`Self::SpawnedFutureResult`] should resolve
27
+ /// with the output of the spawned future.
28
+ ///
29
+ /// Spawned futures must be polled independently in the background even if the returned
30
+ /// [`Self::SpawnedFutureResult`] is dropped without being polled. This matches the semantics of
31
+ /// `tokio::spawn`.
21
32
pub trait FutureSpawner : MaybeSend + MaybeSync + ' static {
33
+ /// The error type of [`Self::SpawnedFutureResult`]. This can be used to indicate that the
34
+ /// spawned future was cancelled or panicked.
35
+ type E ;
36
+ /// The result of [`Self::spawn`], a future which completes when the spawned future completes.
37
+ type SpawnedFutureResult < O > : Future < Output = Result < O , Self :: E > > + Unpin ;
22
38
/// Spawns the given future as a background task.
23
39
///
24
40
/// This method MUST NOT block on the given future immediately.
25
- fn spawn < T : Future < Output = ( ) > + MaybeSend + ' static > ( & self , future : T ) ;
41
+ fn spawn < O : MaybeSend + ' static , T : Future < Output = O > + MaybeSend + ' static > (
42
+ & self , future : T ,
43
+ ) -> Self :: SpawnedFutureResult < O > ;
26
44
}
27
45
28
46
#[ cfg( test) ]
@@ -37,6 +55,69 @@ pub(crate) struct FutureQueue(Mutex<Vec<Pin<Box<dyn MaybeSendableFuture>>>>);
37
55
#[ cfg( all( test, not( feature = "std" ) ) ) ]
38
56
pub ( crate ) struct FutureQueue ( RefCell < Vec < Pin < Box < dyn MaybeSendableFuture > > > > ) ;
39
57
58
+ #[ cfg( all( test, feature = "std" ) ) ]
59
+ pub struct FutureQueueCompletion < O > ( Arc < Mutex < Option < O > > > ) ;
60
+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
61
+ pub struct FutureQueueCompletion < O > ( Rc < RefCell < Option < O > > > ) ;
62
+
63
+ #[ cfg( all( test, feature = "std" ) ) ]
64
+ impl < O > FutureQueueCompletion < O > {
65
+ fn new ( ) -> Self {
66
+ Self ( Arc :: new ( Mutex :: new ( None ) ) )
67
+ }
68
+
69
+ fn complete ( & self , o : O ) {
70
+ * self . 0 . lock ( ) . unwrap ( ) = Some ( o) ;
71
+ }
72
+ }
73
+
74
+ #[ cfg( all( test, feature = "std" ) ) ]
75
+ impl < O > Clone for FutureQueueCompletion < O > {
76
+ fn clone ( & self ) -> Self {
77
+ Self ( self . 0 . clone ( ) )
78
+ }
79
+ }
80
+
81
+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
82
+ impl < O > FutureQueueCompletion < O > {
83
+ fn new ( ) -> Self {
84
+ Self ( Rc :: new ( Mutex :: new ( None ) ) )
85
+ }
86
+
87
+ fn complete ( & self , o : O ) {
88
+ * self . 0 . lock ( ) . unwrap ( ) = Some ( o) ;
89
+ }
90
+ }
91
+
92
+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
93
+ impl < O > Clone for FutureQueueCompletion < O > {
94
+ fn clone ( & self ) -> Self {
95
+ Self ( self . 0 . clone ( ) )
96
+ }
97
+ }
98
+
99
+ #[ cfg( all( test, feature = "std" ) ) ]
100
+ impl < O > Future for FutureQueueCompletion < O > {
101
+ type Output = Result < O , Infallible > ;
102
+ fn poll ( self : Pin < & mut Self > , _: & mut Context < ' _ > ) -> Poll < Result < O , Infallible > > {
103
+ match Pin :: into_inner ( self ) . 0 . lock ( ) . unwrap ( ) . take ( ) {
104
+ None => Poll :: Pending ,
105
+ Some ( o) => Poll :: Ready ( Ok ( o) ) ,
106
+ }
107
+ }
108
+ }
109
+
110
+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
111
+ impl < O > Future for FutureQueueCompletion < O > {
112
+ type Output = Result < O , Infallible > ;
113
+ fn poll ( self : Pin < & mut Self > , _: & mut Context < ' _ > ) -> Poll < Result < O , Infallible > > {
114
+ match Pin :: into_inner ( self ) . 0 . get_mut ( ) . take ( ) {
115
+ None => Poll :: Pending ,
116
+ Some ( o) => Poll :: Ready ( Ok ( o) ) ,
117
+ }
118
+ }
119
+ }
120
+
40
121
#[ cfg( test) ]
41
122
impl FutureQueue {
42
123
pub ( crate ) fn new ( ) -> Self {
@@ -84,7 +165,16 @@ impl FutureQueue {
84
165
85
166
#[ cfg( test) ]
86
167
impl FutureSpawner for FutureQueue {
87
- fn spawn < T : Future < Output = ( ) > + MaybeSend + ' static > ( & self , future : T ) {
168
+ type E = Infallible ;
169
+ type SpawnedFutureResult < O > = FutureQueueCompletion < O > ;
170
+ fn spawn < O : MaybeSend + ' static , F : Future < Output = O > + MaybeSend + ' static > (
171
+ & self , f : F ,
172
+ ) -> FutureQueueCompletion < O > {
173
+ let completion = FutureQueueCompletion :: new ( ) ;
174
+ let compl_ref = completion. clone ( ) ;
175
+ let future = async move {
176
+ compl_ref. complete ( f. await ) ;
177
+ } ;
88
178
#[ cfg( feature = "std" ) ]
89
179
{
90
180
self . 0 . lock ( ) . unwrap ( ) . push ( Box :: pin ( future) ) ;
@@ -93,14 +183,24 @@ impl FutureSpawner for FutureQueue {
93
183
{
94
184
self . 0 . borrow_mut ( ) . push ( Box :: pin ( future) ) ;
95
185
}
186
+ completion
96
187
}
97
188
}
98
189
99
190
#[ cfg( test) ]
100
191
impl < D : core:: ops:: Deref < Target = FutureQueue > + MaybeSend + MaybeSync + ' static > FutureSpawner
101
192
for D
102
193
{
103
- fn spawn < T : Future < Output = ( ) > + MaybeSend + ' static > ( & self , future : T ) {
194
+ type E = Infallible ;
195
+ type SpawnedFutureResult < O > = FutureQueueCompletion < O > ;
196
+ fn spawn < O : MaybeSend + ' static , F : Future < Output = O > + MaybeSend + ' static > (
197
+ & self , f : F ,
198
+ ) -> FutureQueueCompletion < O > {
199
+ let completion = FutureQueueCompletion :: new ( ) ;
200
+ let compl_ref = completion. clone ( ) ;
201
+ let future = async move {
202
+ compl_ref. complete ( f. await ) ;
203
+ } ;
104
204
#[ cfg( feature = "std" ) ]
105
205
{
106
206
self . 0 . lock ( ) . unwrap ( ) . push ( Box :: pin ( future) ) ;
@@ -109,5 +209,6 @@ impl<D: core::ops::Deref<Target = FutureQueue> + MaybeSend + MaybeSync + 'static
109
209
{
110
210
self . 0 . borrow_mut ( ) . push ( Box :: pin ( future) ) ;
111
211
}
212
+ completion
112
213
}
113
214
}
0 commit comments