Skip to content

Commit

Permalink
Document cancel-safety of stream I/O operations
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith authored and djc committed Feb 21, 2024
1 parent dcc8048 commit 614fef6
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
17 changes: 16 additions & 1 deletion quinn/src/recv_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ use crate::{
/// - A variant of [`ReadError`] has been yielded by a read call
/// - [`stop()`] was called explicitly
///
/// # Cancellation
///
/// A `read` method is said to be *cancel-safe* when dropping its future before the future becomes
/// ready cannot lead to loss of stream data. This is true of methods which succeed immediately when
/// any progress is made, and is not true of methods which might need to perform multiple reads
/// internally before succeeding. Each `read` method documents whether it is cancel-safe.
///
/// # Common issues
///
/// ## Data never received on a locally-opened stream
Expand Down Expand Up @@ -111,6 +118,8 @@ impl RecvStream {
/// Read data contiguously from the stream.
///
/// Yields the number of bytes read into `buf` on success, or `None` if the stream was finished.
///
/// This operation is cancel-safe.
pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError> {
Read {
stream: self,
Expand All @@ -121,7 +130,7 @@ impl RecvStream {

/// Read an exact number of bytes contiguously from the stream.
///
/// See [`read()`] for details.
/// See [`read()`] for details. This operation is *not* cancel-safe.
///
/// [`read()`]: RecvStream::read
pub async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError> {
Expand Down Expand Up @@ -172,6 +181,8 @@ impl RecvStream {
///
/// Slightly more efficient than `read` due to not copying. Chunk boundaries do not correspond
/// to peer writes, and hence cannot be used as framing.
///
/// This operation is cancel-safe.
pub async fn read_chunk(
&mut self,
max_length: usize,
Expand Down Expand Up @@ -206,6 +217,8 @@ impl RecvStream {
///
/// Slightly more efficient than `read` due to not copying. Chunk boundaries
/// do not correspond to peer writes, and hence cannot be used as framing.
///
/// This operation is cancel-safe.
pub async fn read_chunks(&mut self, bufs: &mut [Bytes]) -> Result<Option<usize>, ReadError> {
ReadChunks { stream: self, bufs }.await
}
Expand Down Expand Up @@ -248,6 +261,8 @@ impl RecvStream {
/// If unordered reads have already been made, the resulting buffer may have gaps containing
/// arbitrary data.
///
/// This operation is *not* cancel-safe.
///
/// [`ReadToEndError::TooLong`]: crate::ReadToEndError::TooLong
pub async fn read_to_end(&mut self, size_limit: usize) -> Result<Vec<u8>, ReadToEndError> {
ReadToEnd {
Expand Down
18 changes: 18 additions & 0 deletions quinn/src/send_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ use crate::{
/// If dropped, streams that haven't been explicitly [`reset()`] will continue to (re)transmit
/// previously written data until it has been fully acknowledged or the connection is closed.
///
/// # Cancellation
///
/// A `write` method is said to be *cancel-safe* when dropping its future before the future becomes
/// ready will always result in no data being written to the stream. This is true of methods which
/// succeed immediately when any progress is made, and is not true of methods which might need to
/// perform multiple writes internally before succeeding. Each `write` method documents whether it is
/// cancel-safe.
///
/// [`reset()`]: SendStream::reset
#[derive(Debug)]
pub struct SendStream {
Expand All @@ -43,11 +51,15 @@ impl SendStream {
///
/// Yields the number of bytes written on success. Congestion and flow control may cause this to
/// be shorter than `buf.len()`, indicating that only a prefix of `buf` was written.
///
/// This operation is cancel-safe.
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, WriteError> {
Write { stream: self, buf }.await
}

/// Convenience method to write an entire buffer to the stream
///
/// This operation is *not* cancel-safe.
pub async fn write_all(&mut self, buf: &[u8]) -> Result<(), WriteError> {
WriteAll { stream: self, buf }.await
}
Expand All @@ -57,11 +69,15 @@ impl SendStream {
/// Yields the number of bytes and chunks written on success.
/// Congestion and flow control may cause this to be shorter than `buf.len()`,
/// indicating that only a prefix of `bufs` was written
///
/// This operation is cancel-safe.
pub async fn write_chunks(&mut self, bufs: &mut [Bytes]) -> Result<Written, WriteError> {
WriteChunks { stream: self, bufs }.await
}

/// Convenience method to write a single chunk in its entirety to the stream
///
/// This operation is *not* cancel-safe.
pub async fn write_chunk(&mut self, buf: Bytes) -> Result<(), WriteError> {
WriteChunk {
stream: self,
Expand All @@ -71,6 +87,8 @@ impl SendStream {
}

/// Convenience method to write an entire list of chunks to the stream
///
/// This operation is *not* cancel-safe.
pub async fn write_all_chunks(&mut self, bufs: &mut [Bytes]) -> Result<(), WriteError> {
WriteAllChunks {
stream: self,
Expand Down

0 comments on commit 614fef6

Please sign in to comment.