From 3981ca633f4edcc085e3b9aa2e92be15553b44d8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Sat, 25 Jan 2025 11:16:39 -0800 Subject: [PATCH] AsyncInputStream: if input-stream.read returns empty, try again. --- src/io/streams.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/io/streams.rs b/src/io/streams.rs index db28718..bc26c12 100644 --- a/src/io/streams.rs +++ b/src/io/streams.rs @@ -28,19 +28,23 @@ impl AsyncInputStream { } /// Like [`AsyncRead::read`], but doesn't require a `&mut self`. pub async fn read(&self, buf: &mut [u8]) -> Result { - self.ready().await; - // Ideally, the ABI would be able to read directly into buf. However, with the default - // generated bindings, it returns a newly allocated vec, which we need to copy into buf. - let read = match self.stream.read(buf.len() as u64) { - // We don't need to special-case 0 here: a value of 0 bytes from - // WASI's `read` doesn't mean end-of-stream as it does in Rust, - // however since we called `self.ready()`, we'll always get at - // least one byte. - Ok(r) => r, - // 0 bytes from Rust's `read` means end-of-stream. - Err(StreamError::Closed) => return Ok(0), - Err(StreamError::LastOperationFailed(err)) => { - return Err(std::io::Error::other(err.to_debug_string())) + let read = loop { + self.ready().await; + // Ideally, the ABI would be able to read directly into buf. + // However, with the default generated bindings, it returns a + // newly allocated vec, which we need to copy into buf. + match self.stream.read(buf.len() as u64) { + // A read of 0 bytes from WASI's `read` doesn't mean + // end-of-stream as it does in Rust. However, `self.ready()` + // cannot guarantee that at least one byte is ready for + // reading, so in this case we try again. + Ok(r) if r.is_empty() => continue, + Ok(r) => break r, + // 0 bytes from Rust's `read` means end-of-stream. + Err(StreamError::Closed) => return Ok(0), + Err(StreamError::LastOperationFailed(err)) => { + return Err(std::io::Error::other(err.to_debug_string())) + } } }; let len = read.len();