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();