@@ -45,12 +45,15 @@ use alloc::boxed::Box;
45
45
use core:: cell:: UnsafeCell ;
46
46
use core:: ffi:: c_void;
47
47
use core:: fmt;
48
+ use core:: future:: Future ;
48
49
use core:: marker:: PhantomData ;
49
50
use core:: mem:: MaybeUninit ;
50
51
use core:: pin:: Pin ;
52
+ use core:: task:: Poll ;
51
53
52
54
use crate :: sys:: queue:: Queue ;
53
55
use crate :: time:: { Forever , NoWait , Timeout } ;
56
+ use crate :: work:: futures:: WorkWaker ;
54
57
55
58
mod counter;
56
59
@@ -205,6 +208,88 @@ impl<T> Sender<T> {
205
208
}
206
209
}
207
210
211
+ // A little note about the Unpin constraint here. Because Futures are pinned in Rust Async code,
212
+ // and the future stores the messages, we can only send and receive messages that aren't pinned.
213
+ impl < T : Unpin > Sender < T > {
214
+ /// Waits for a message to be sent into the channel, but only for a limited time. Async
215
+ /// version.
216
+ ///
217
+ /// This has the same behavior as [`send_timeout`], but as an Async function.
218
+ pub fn send_timeout_async < ' a > ( & ' a self , msg : T , timeout : impl Into < Timeout > )
219
+ -> impl Future < Output = Result < ( ) , SendError < T > > > + ' a
220
+ {
221
+ SendFuture {
222
+ sender : self ,
223
+ msg : Some ( msg) ,
224
+ timeout : timeout. into ( ) ,
225
+ waited : false ,
226
+ }
227
+ }
228
+
229
+ /// Sends a message over the given channel, waiting if necessary. Async version.
230
+ pub async fn send_async ( & self , msg : T ) -> Result < ( ) , SendError < T > > {
231
+ self . send_timeout_async ( msg, Forever ) . await
232
+ }
233
+
234
+ // Note that there is no async version of `try_send`.
235
+ }
236
+
237
+ /// The implementation of Future for Sender::send_timeout_async.
238
+ struct SendFuture < ' a , T : Unpin > {
239
+ sender : & ' a Sender < T > ,
240
+ msg : Option < T > ,
241
+ timeout : Timeout ,
242
+ waited : bool ,
243
+ }
244
+
245
+ impl < ' a , T : Unpin > Future for SendFuture < ' a , T > {
246
+ type Output = Result < ( ) , SendError < T > > ;
247
+
248
+ fn poll ( self : Pin < & mut Self > , cx : & mut core:: task:: Context < ' _ > ) -> core:: task:: Poll < Self :: Output > {
249
+ /*
250
+ let this = unsafe {
251
+ Pin::get_unchecked_mut(self)
252
+ };
253
+ */
254
+ let this = Pin :: get_mut ( self ) ;
255
+
256
+ // Take the message out in preparation to try sending it. It is a logic error if the unwrap
257
+ // fails.
258
+ let msg = this. msg . take ( ) . unwrap ( ) ;
259
+
260
+ // Try sending the message, with no timeout.
261
+ let msg = match this. sender . try_send ( msg) {
262
+ Ok ( ( ) ) => return Poll :: Ready ( Ok ( ( ) ) ) ,
263
+ Err ( SendError ( msg) ) => msg,
264
+ } ;
265
+
266
+ if this. waited {
267
+ // We already waited, and no message, so give the messagre back, indiciating a timeout.
268
+ return Poll :: Ready ( Err ( SendError ( msg) ) ) ;
269
+ }
270
+
271
+ // Send didn't happen, put the message back to have for the next call.
272
+ this. msg = Some ( msg) ;
273
+
274
+ // Otherwise, schedule to wake up on receipt or timeout.
275
+ let work = unsafe { WorkWaker :: from_waker ( cx. waker ( ) ) } ;
276
+ let mut lock = work. lock ( ) . unwrap ( ) ;
277
+ match & this. sender . flavor {
278
+ SenderFlavor :: Unbounded { .. } => {
279
+ panic ! ( "Implementation error: unbounded queues should never fail" ) ;
280
+ }
281
+ SenderFlavor :: Bounded ( chan) => {
282
+ unsafe {
283
+ lock. add_queue ( & chan. free ) ;
284
+ }
285
+ }
286
+ }
287
+ lock. timeout = this. timeout ;
288
+
289
+ Poll :: Pending
290
+ }
291
+ }
292
+
208
293
impl < T > Drop for Sender < T > {
209
294
fn drop ( & mut self ) {
210
295
match & self . flavor {
@@ -341,6 +426,42 @@ impl<T> Receiver<T> {
341
426
}
342
427
}
343
428
429
+ // Note that receive doesn't need the Unpin constraint, as we aren't storing any message.
430
+ impl < T > Receiver < T > {
431
+ /// Waits for a message to be received from the channel, but only for a limited time.
432
+ /// Async version.
433
+ ///
434
+ /// If the channel is empty and not disconnected, this call will block until the receive
435
+ /// operation can proceed or the operation times out.
436
+ /// wake up and return an error.
437
+ pub fn recv_timeout_async < ' a > ( & ' a self , timeout : impl Into < Timeout > )
438
+ -> impl Future < Output = Result < T , RecvError > > + ' a
439
+ {
440
+ RecvFuture {
441
+ receiver : self ,
442
+ timeout : timeout. into ( ) ,
443
+ waited : false ,
444
+ }
445
+ }
446
+
447
+ /// Blocks the current thread until a message is received or the channel is empty and
448
+ /// disconnected. Async version.
449
+ ///
450
+ /// If the channel is empty and not disconnected, this call will block until the receive
451
+ /// operation can proceed.
452
+ pub async fn recv_async ( & self ) -> Result < T , RecvError > {
453
+ self . recv_timeout_async ( Forever ) . await
454
+ }
455
+
456
+ /// Return a reference to the inner queue.
457
+ fn as_queue ( & self ) -> & Queue {
458
+ match & self . flavor {
459
+ ReceiverFlavor :: Unbounded { queue, .. } => queue,
460
+ ReceiverFlavor :: Bounded ( chan) => & chan. chan ,
461
+ }
462
+ }
463
+ }
464
+
344
465
impl < T > Drop for Receiver < T > {
345
466
fn drop ( & mut self ) {
346
467
match & self . flavor {
@@ -390,6 +511,38 @@ impl<T> fmt::Debug for Receiver<T> {
390
511
}
391
512
}
392
513
514
+ struct RecvFuture < ' a , T > {
515
+ receiver : & ' a Receiver < T > ,
516
+ timeout : Timeout ,
517
+ waited : bool ,
518
+ }
519
+
520
+ impl < ' a , T > Future for RecvFuture < ' a , T > {
521
+ type Output = Result < T , RecvError > ;
522
+
523
+ fn poll ( self : Pin < & mut Self > , cx : & mut core:: task:: Context < ' _ > ) -> Poll < Self :: Output > {
524
+ // Try to receive a message.
525
+ if let Ok ( msg) = self . receiver . try_recv ( ) {
526
+ return Poll :: Ready ( Ok ( msg) ) ;
527
+ }
528
+
529
+ if self . waited {
530
+ // Wait already happened, so this is a timeout.
531
+ return Poll :: Ready ( Err ( RecvError ) ) ;
532
+ }
533
+
534
+ // Otherwise, schedule to wakeup on receipt or timeout.
535
+ let work = unsafe { WorkWaker :: from_waker ( cx. waker ( ) ) } ;
536
+ let mut lock = work. lock ( ) . unwrap ( ) ;
537
+ unsafe {
538
+ lock. add_queue ( self . receiver . as_queue ( ) ) ;
539
+ }
540
+ lock. timeout = self . timeout ;
541
+
542
+ Poll :: Pending
543
+ }
544
+ }
545
+
393
546
/// The "flavor" of a receiver. This maps to the type of the channel.
394
547
enum ReceiverFlavor < T > {
395
548
/// An unbounded queue. Messages were allocated with Box, and will be freed upon receipt.
0 commit comments