@@ -45,12 +45,15 @@ use alloc::boxed::Box;
4545use core:: cell:: UnsafeCell ;
4646use core:: ffi:: c_void;
4747use core:: fmt;
48+ use core:: future:: Future ;
4849use core:: marker:: PhantomData ;
4950use core:: mem:: MaybeUninit ;
5051use core:: pin:: Pin ;
52+ use core:: task:: Poll ;
5153
5254use crate :: sys:: queue:: Queue ;
5355use crate :: time:: { Forever , NoWait , Timeout } ;
56+ use crate :: work:: futures:: WorkWaker ;
5457
5558mod counter;
5659
@@ -205,6 +208,88 @@ impl<T> Sender<T> {
205208 }
206209}
207210
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+
208293impl < T > Drop for Sender < T > {
209294 fn drop ( & mut self ) {
210295 match & self . flavor {
@@ -341,6 +426,42 @@ impl<T> Receiver<T> {
341426 }
342427}
343428
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+
344465impl < T > Drop for Receiver < T > {
345466 fn drop ( & mut self ) {
346467 match & self . flavor {
@@ -390,6 +511,38 @@ impl<T> fmt::Debug for Receiver<T> {
390511 }
391512}
392513
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+
393546/// The "flavor" of a receiver. This maps to the type of the channel.
394547enum ReceiverFlavor < T > {
395548 /// An unbounded queue. Messages were allocated with Box, and will be freed upon receipt.
0 commit comments