@@ -2,14 +2,17 @@ use std::{
22 future:: { Future , poll_fn} ,
33 io,
44 pin:: Pin ,
5- task:: { Context , Poll } ,
5+ task:: { Context , Poll , ready } ,
66} ;
77
88use bytes:: Bytes ;
99use proto:: { ClosedStream , ConnectionError , FinishError , StreamId , Written } ;
1010use thiserror:: Error ;
1111
12- use crate :: { VarInt , connection:: ConnectionRef } ;
12+ use crate :: {
13+ VarInt ,
14+ connection:: { ConnectionRef , State } ,
15+ } ;
1316
1417/// A stream that can only be used to send data
1518///
@@ -199,27 +202,31 @@ impl SendStream {
199202 /// For a variety of reasons, the peer may not send acknowledgements immediately upon receiving
200203 /// data. As such, relying on `stopped` to know when the peer has read a stream to completion
201204 /// may introduce more latency than using an application-level response of some sort.
202- pub async fn stopped ( & mut self ) -> Result < Option < VarInt > , StoppedError > {
203- Stopped { stream : self } . await
204- }
205-
206- fn poll_stopped ( & mut self , cx : & mut Context ) -> Poll < Result < Option < VarInt > , StoppedError > > {
207- let mut conn = self . conn . state . lock ( "SendStream::poll_stopped" ) ;
208-
209- if self . is_0rtt {
210- conn. check_0rtt ( )
211- . map_err ( |( ) | StoppedError :: ZeroRttRejected ) ?;
212- }
213-
214- match conn. inner . send_stream ( self . stream ) . stopped ( ) {
215- Err ( _) => Poll :: Ready ( Ok ( None ) ) ,
216- Ok ( Some ( error_code) ) => Poll :: Ready ( Ok ( Some ( error_code) ) ) ,
217- Ok ( None ) => {
218- if let Some ( e) = & conn. error {
219- return Poll :: Ready ( Err ( e. clone ( ) . into ( ) ) ) ;
205+ pub fn stopped (
206+ & self ,
207+ ) -> impl Future < Output = Result < Option < VarInt > , StoppedError > > + Send + Sync + ' static {
208+ let conn = self . conn . clone ( ) ;
209+ let stream = self . stream ;
210+ let is_0rtt = self . is_0rtt ;
211+ async move {
212+ loop {
213+ // The `Notify::notified` future needs to be created while the lock is being held,
214+ // otherwise a wakeup could be missed if triggered inbetween releasing the lock
215+ // and creating the future.
216+ // The lock may only be held in a block without `await`s, otherwise the future
217+ // becomes `!Send`. `Notify::notified` is lifetime-bound to `Notify`, therefore
218+ // we need to declare `notify` outside of the block, and initialize it inside.
219+ let notify;
220+ {
221+ let mut conn = conn. state . lock ( "SendStream::stopped" ) ;
222+ if let Some ( output) = send_stream_stopped ( & mut conn, stream, is_0rtt) {
223+ return output;
224+ }
225+
226+ notify = conn. stopped . entry ( stream) . or_default ( ) . clone ( ) ;
227+ notify. notified ( )
220228 }
221- conn. stopped . insert ( self . stream , cx. waker ( ) . clone ( ) ) ;
222- Poll :: Pending
229+ . await
223230 }
224231 }
225232 }
@@ -245,6 +252,32 @@ impl SendStream {
245252 }
246253}
247254
255+ /// Check if a send stream is stopped.
256+ ///
257+ /// Returns `Some` if the stream is stopped or the connection is closed.
258+ /// Returns `None` if the stream is not stopped.
259+ fn send_stream_stopped (
260+ conn : & mut State ,
261+ stream : StreamId ,
262+ is_0rtt : bool ,
263+ ) -> Option < Result < Option < VarInt > , StoppedError > > {
264+ if is_0rtt && conn. check_0rtt ( ) . is_err ( ) {
265+ Some ( Err ( StoppedError :: ZeroRttRejected ) )
266+ } else {
267+ match conn. inner . send_stream ( stream) . stopped ( ) {
268+ Err ( ClosedStream { .. } ) => Some ( Ok ( None ) ) ,
269+ Ok ( Some ( error_code) ) => Some ( Ok ( Some ( error_code) ) ) ,
270+ Ok ( None ) => {
271+ if let Some ( error) = & conn. error {
272+ Some ( Err ( error. clone ( ) . into ( ) ) )
273+ } else {
274+ None
275+ }
276+ }
277+ }
278+ }
279+ }
280+
248281#[ cfg( feature = "futures-io" ) ]
249282impl futures_io:: AsyncWrite for SendStream {
250283 fn poll_write ( self : Pin < & mut Self > , cx : & mut Context , buf : & [ u8 ] ) -> Poll < io:: Result < usize > > {
@@ -283,7 +316,6 @@ impl Drop for SendStream {
283316 let mut conn = self . conn . state . lock ( "SendStream::drop" ) ;
284317
285318 // clean up any previously registered wakers
286- conn. stopped . remove ( & self . stream ) ;
287319 conn. blocked_writers . remove ( & self . stream ) ;
288320
289321 if conn. error . is_some ( ) || ( self . is_0rtt && conn. check_0rtt ( ) . is_err ( ) ) {
@@ -302,16 +334,106 @@ impl Drop for SendStream {
302334 }
303335}
304336
305- /// Future produced by `SendStream::stopped`
306- struct Stopped < ' a > {
337+ /// Future produced by [`SendStream::write()`].
338+ ///
339+ /// [`SendStream::write()`]: crate::SendStream::write
340+ struct Write < ' a > {
307341 stream : & ' a mut SendStream ,
342+ buf : & ' a [ u8 ] ,
343+ }
344+
345+ impl Future for Write < ' _ > {
346+ type Output = Result < usize , WriteError > ;
347+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
348+ let this = self . get_mut ( ) ;
349+ let buf = this. buf ;
350+ this. stream . execute_poll ( cx, |s| s. write ( buf) )
351+ }
308352}
309353
310- impl Future for Stopped < ' _ > {
311- type Output = Result < Option < VarInt > , StoppedError > ;
354+ /// Future produced by [`SendStream::write_all()`].
355+ ///
356+ /// [`SendStream::write_all()`]: crate::SendStream::write_all
357+ struct WriteAll < ' a > {
358+ stream : & ' a mut SendStream ,
359+ buf : & ' a [ u8 ] ,
360+ }
312361
362+ impl Future for WriteAll < ' _ > {
363+ type Output = Result < ( ) , WriteError > ;
313364 fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
314- self . get_mut ( ) . stream . poll_stopped ( cx)
365+ let this = self . get_mut ( ) ;
366+ loop {
367+ if this. buf . is_empty ( ) {
368+ return Poll :: Ready ( Ok ( ( ) ) ) ;
369+ }
370+ let buf = this. buf ;
371+ let n = ready ! ( this. stream. execute_poll( cx, |s| s. write( buf) ) ) ?;
372+ this. buf = & this. buf [ n..] ;
373+ }
374+ }
375+ }
376+
377+ /// Future produced by [`SendStream::write_chunks()`].
378+ ///
379+ /// [`SendStream::write_chunks()`]: crate::SendStream::write_chunks
380+ struct WriteChunks < ' a > {
381+ stream : & ' a mut SendStream ,
382+ bufs : & ' a mut [ Bytes ] ,
383+ }
384+
385+ impl Future for WriteChunks < ' _ > {
386+ type Output = Result < Written , WriteError > ;
387+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
388+ let this = self . get_mut ( ) ;
389+ let bufs = & mut * this. bufs ;
390+ this. stream . execute_poll ( cx, |s| s. write_chunks ( bufs) )
391+ }
392+ }
393+
394+ /// Future produced by [`SendStream::write_chunk()`].
395+ ///
396+ /// [`SendStream::write_chunk()`]: crate::SendStream::write_chunk
397+ struct WriteChunk < ' a > {
398+ stream : & ' a mut SendStream ,
399+ buf : [ Bytes ; 1 ] ,
400+ }
401+
402+ impl Future for WriteChunk < ' _ > {
403+ type Output = Result < ( ) , WriteError > ;
404+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
405+ let this = self . get_mut ( ) ;
406+ loop {
407+ if this. buf [ 0 ] . is_empty ( ) {
408+ return Poll :: Ready ( Ok ( ( ) ) ) ;
409+ }
410+ let bufs = & mut this. buf [ ..] ;
411+ ready ! ( this. stream. execute_poll( cx, |s| s. write_chunks( bufs) ) ) ?;
412+ }
413+ }
414+ }
415+
416+ /// Future produced by [`SendStream::write_all_chunks()`].
417+ ///
418+ /// [`SendStream::write_all_chunks()`]: crate::SendStream::write_all_chunks
419+ struct WriteAllChunks < ' a > {
420+ stream : & ' a mut SendStream ,
421+ bufs : & ' a mut [ Bytes ] ,
422+ offset : usize ,
423+ }
424+
425+ impl Future for WriteAllChunks < ' _ > {
426+ type Output = Result < ( ) , WriteError > ;
427+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
428+ let this = self . get_mut ( ) ;
429+ loop {
430+ if this. offset == this. bufs . len ( ) {
431+ return Poll :: Ready ( Ok ( ( ) ) ) ;
432+ }
433+ let bufs = & mut this. bufs [ this. offset ..] ;
434+ let written = ready ! ( this. stream. execute_poll( cx, |s| s. write_chunks( bufs) ) ) ?;
435+ this. offset += written. chunks ;
436+ }
315437 }
316438}
317439
0 commit comments