88//! environment.
99
1010#[ cfg( all( test, feature = "std" ) ) ]
11- use crate :: sync:: Mutex ;
11+ use crate :: sync:: { Arc , Mutex } ;
1212use crate :: util:: async_poll:: { MaybeSend , MaybeSync } ;
1313
14+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
15+ use alloc:: rc:: Rc ;
16+
1417#[ cfg( all( test, not( feature = "std" ) ) ) ]
1518use core:: cell:: RefCell ;
19+ #[ cfg( test) ]
20+ use core:: convert:: Infallible ;
1621use core:: future:: Future ;
1722#[ cfg( test) ]
1823use core:: pin:: Pin ;
24+ #[ cfg( test) ]
25+ use core:: task:: { Context , Poll } ;
1926
20- /// A generic trait which is able to spawn futures in the background.
27+ /// A generic trait which is able to spawn futures to be polled in the background.
28+ ///
29+ /// When the spawned future completes, the returned [`Self::SpawnedFutureResult`] should resolve
30+ /// with the output of the spawned future.
31+ ///
32+ /// Spawned futures must be polled independently in the background even if the returned
33+ /// [`Self::SpawnedFutureResult`] is dropped without being polled. This matches the semantics of
34+ /// `tokio::spawn`.
2135///
2236/// This is not exported to bindings users as async is only supported in Rust.
2337pub trait FutureSpawner : MaybeSend + MaybeSync + ' static {
38+ /// The error type of [`Self::SpawnedFutureResult`]. This can be used to indicate that the
39+ /// spawned future was cancelled or panicked.
40+ type E ;
41+ /// The result of [`Self::spawn`], a future which completes when the spawned future completes.
42+ type SpawnedFutureResult < O > : Future < Output = Result < O , Self :: E > > + Unpin ;
2443 /// Spawns the given future as a background task.
2544 ///
2645 /// This method MUST NOT block on the given future immediately.
27- fn spawn < T : Future < Output = ( ) > + MaybeSend + ' static > ( & self , future : T ) ;
46+ fn spawn < O : MaybeSend + ' static , T : Future < Output = O > + MaybeSend + ' static > (
47+ & self , future : T ,
48+ ) -> Self :: SpawnedFutureResult < O > ;
2849}
2950
3051#[ cfg( test) ]
@@ -39,6 +60,77 @@ pub(crate) struct FutureQueue(Mutex<Vec<Pin<Box<dyn MaybeSendableFuture>>>>);
3960#[ cfg( all( test, not( feature = "std" ) ) ) ]
4061pub ( crate ) struct FutureQueue ( RefCell < Vec < Pin < Box < dyn MaybeSendableFuture > > > > ) ;
4162
63+ /// A simple future which can be completed later. Used to implement [`FutureQueue`].
64+ #[ cfg( all( test, feature = "std" ) ) ]
65+ pub struct FutureQueueCompletion < O > ( Arc < Mutex < Option < O > > > ) ;
66+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
67+ pub struct FutureQueueCompletion < O > ( Rc < RefCell < Option < O > > > ) ;
68+
69+ #[ cfg( all( test, feature = "std" ) ) ]
70+ impl < O > FutureQueueCompletion < O > {
71+ fn new ( ) -> Self {
72+ Self ( Arc :: new ( Mutex :: new ( None ) ) )
73+ }
74+
75+ fn complete ( & self , o : O ) {
76+ * self . 0 . lock ( ) . unwrap ( ) = Some ( o) ;
77+ }
78+ }
79+
80+ #[ cfg( all( test, feature = "std" ) ) ]
81+ impl < O > Clone for FutureQueueCompletion < O > {
82+ fn clone ( & self ) -> Self {
83+ #[ cfg( all( test, feature = "std" ) ) ]
84+ {
85+ Self ( Arc :: clone ( & self . 0 ) )
86+ }
87+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
88+ {
89+ Self ( Rc :: clone ( & self . 0 ) )
90+ }
91+ }
92+ }
93+
94+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
95+ impl < O > FutureQueueCompletion < O > {
96+ fn new ( ) -> Self {
97+ Self ( Rc :: new ( RefCell :: new ( None ) ) )
98+ }
99+
100+ fn complete ( & self , o : O ) {
101+ * self . 0 . borrow_mut ( ) = Some ( o) ;
102+ }
103+ }
104+
105+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
106+ impl < O > Clone for FutureQueueCompletion < O > {
107+ fn clone ( & self ) -> Self {
108+ Self ( self . 0 . clone ( ) )
109+ }
110+ }
111+
112+ #[ cfg( all( test, feature = "std" ) ) ]
113+ impl < O > Future for FutureQueueCompletion < O > {
114+ type Output = Result < O , Infallible > ;
115+ fn poll ( self : Pin < & mut Self > , _: & mut Context < ' _ > ) -> Poll < Result < O , Infallible > > {
116+ match Pin :: into_inner ( self ) . 0 . lock ( ) . unwrap ( ) . take ( ) {
117+ None => Poll :: Pending ,
118+ Some ( o) => Poll :: Ready ( Ok ( o) ) ,
119+ }
120+ }
121+ }
122+
123+ #[ cfg( all( test, not( feature = "std" ) ) ) ]
124+ impl < O > Future for FutureQueueCompletion < O > {
125+ type Output = Result < O , Infallible > ;
126+ fn poll ( self : Pin < & mut Self > , _: & mut Context < ' _ > ) -> Poll < Result < O , Infallible > > {
127+ match Pin :: into_inner ( self ) . 0 . borrow_mut ( ) . take ( ) {
128+ None => Poll :: Pending ,
129+ Some ( o) => Poll :: Ready ( Ok ( o) ) ,
130+ }
131+ }
132+ }
133+
42134#[ cfg( test) ]
43135impl FutureQueue {
44136 pub ( crate ) fn new ( ) -> Self {
@@ -74,7 +166,6 @@ impl FutureQueue {
74166 futures = self . 0 . borrow_mut ( ) ;
75167 }
76168 futures. retain_mut ( |fut| {
77- use core:: task:: { Context , Poll } ;
78169 let waker = crate :: util:: async_poll:: dummy_waker ( ) ;
79170 match fut. as_mut ( ) . poll ( & mut Context :: from_waker ( & waker) ) {
80171 Poll :: Ready ( ( ) ) => false ,
@@ -86,7 +177,16 @@ impl FutureQueue {
86177
87178#[ cfg( test) ]
88179impl FutureSpawner for FutureQueue {
89- fn spawn < T : Future < Output = ( ) > + MaybeSend + ' static > ( & self , future : T ) {
180+ type E = Infallible ;
181+ type SpawnedFutureResult < O > = FutureQueueCompletion < O > ;
182+ fn spawn < O : MaybeSend + ' static , F : Future < Output = O > + MaybeSend + ' static > (
183+ & self , f : F ,
184+ ) -> FutureQueueCompletion < O > {
185+ let completion = FutureQueueCompletion :: new ( ) ;
186+ let compl_ref = completion. clone ( ) ;
187+ let future = async move {
188+ compl_ref. complete ( f. await ) ;
189+ } ;
90190 #[ cfg( feature = "std" ) ]
91191 {
92192 self . 0 . lock ( ) . unwrap ( ) . push ( Box :: pin ( future) ) ;
@@ -95,14 +195,24 @@ impl FutureSpawner for FutureQueue {
95195 {
96196 self . 0 . borrow_mut ( ) . push ( Box :: pin ( future) ) ;
97197 }
198+ completion
98199 }
99200}
100201
101202#[ cfg( test) ]
102203impl < D : core:: ops:: Deref < Target = FutureQueue > + MaybeSend + MaybeSync + ' static > FutureSpawner
103204 for D
104205{
105- fn spawn < T : Future < Output = ( ) > + MaybeSend + ' static > ( & self , future : T ) {
206+ type E = Infallible ;
207+ type SpawnedFutureResult < O > = FutureQueueCompletion < O > ;
208+ fn spawn < O : MaybeSend + ' static , F : Future < Output = O > + MaybeSend + ' static > (
209+ & self , f : F ,
210+ ) -> FutureQueueCompletion < O > {
211+ let completion = FutureQueueCompletion :: new ( ) ;
212+ let compl_ref = completion. clone ( ) ;
213+ let future = async move {
214+ compl_ref. complete ( f. await ) ;
215+ } ;
106216 #[ cfg( feature = "std" ) ]
107217 {
108218 self . 0 . lock ( ) . unwrap ( ) . push ( Box :: pin ( future) ) ;
@@ -111,5 +221,6 @@ impl<D: core::ops::Deref<Target = FutureQueue> + MaybeSend + MaybeSync + 'static
111221 {
112222 self . 0 . borrow_mut ( ) . push ( Box :: pin ( future) ) ;
113223 }
224+ completion
114225 }
115226}
0 commit comments