diff --git a/crates/wasi-http/wit/deps/io/error.wit b/crates/wasi-http/wit/deps/io/error.wit new file mode 100644 index 000000000000..b45c594e6f83 --- /dev/null +++ b/crates/wasi-http/wit/deps/io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.0-rc-2023-11-05; + + +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// provide functions to further "downcast" this error into more specific + /// error information. For example, `error`s returned in streams derived + /// from filesystem types to be described using the filesystem's own + /// error-code type, using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter + /// `borrow` and returns + /// `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + to-debug-string: func() -> string; + } +} diff --git a/crates/wasi-http/wit/deps/io/streams.wit b/crates/wasi-http/wit/deps/io/streams.wit index 9442f60c0e16..45062505b993 100644 --- a/crates/wasi-http/wit/deps/io/streams.wit +++ b/crates/wasi-http/wit/deps/io/streams.wit @@ -6,6 +6,7 @@ package wasi:io@0.2.0-rc-2023-11-05; /// In the future, the component model is expected to add built-in stream types; /// when it does, they are expected to subsume this API. interface streams { + use error.{error}; use poll.{pollable}; /// An error for input-stream and output-stream operations. @@ -20,26 +21,6 @@ interface streams { closed } - /// Contextual error information about the last failure that happened on - /// a read, write, or flush from an `input-stream` or `output-stream`. - /// - /// This type is returned through the `stream-error` type whenever an - /// operation on a stream directly fails or an error is discovered - /// after-the-fact, for example when a write's failure shows up through a - /// later `flush` or `check-write`. - /// - /// Interfaces such as `wasi:filesystem/types` provide functionality to - /// further "downcast" this error into interface-specific error information. - resource error { - /// Returns a string that's suitable to assist humans in debugging this - /// error. - /// - /// The returned string will change across platforms and hosts which - /// means that parsing it, for example, would be a - /// platform-compatibility hazard. - to-debug-string: func() -> string; - } - /// An input bytestream. /// /// `input-stream`s are *non-blocking* to the extent practical on underlying @@ -51,21 +32,20 @@ interface streams { resource input-stream { /// Perform a non-blocking read from the stream. /// - /// This function returns a list of bytes containing the data that was - /// read, along with a `stream-status` which, indicates whether further - /// reads are expected to produce data. The returned list will contain up to - /// `len` bytes; it may return fewer than requested, but not more. An - /// empty list and `stream-status:open` indicates no more data is - /// available at this time, and that the pollable given by `subscribe` - /// will be ready when more data is available. + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. /// - /// Once a stream has reached the end, subsequent calls to `read` or - /// `skip` will always report `stream-status:ended` rather than producing more - /// data. + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. /// - /// When the caller gives a `len` of 0, it represents a request to read 0 - /// bytes. This read should always succeed and return an empty list and - /// the current `stream-status`. + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. /// /// The `len` parameter is a `u64`, which could represent a list of u8 which /// is not possible to allocate in wasm32, or not desirable to allocate as @@ -77,24 +57,16 @@ interface streams { ) -> result, stream-error>; /// Read bytes from a stream, after blocking until at least one byte can - /// be read. Except for blocking, identical to `read`. + /// be read. Except for blocking, behavior is identical to `read`. blocking-read: func( /// The maximum number of bytes to read len: u64 ) -> result, stream-error>; - /// Skip bytes from a stream. - /// - /// This is similar to the `read` function, but avoids copying the - /// bytes into the instance. - /// - /// Once a stream has reached the end, subsequent calls to read or - /// `skip` will always report end-of-stream rather than producing more - /// data. + /// Skip bytes from a stream. Returns number of bytes skipped. /// - /// This function returns the number of bytes skipped, along with a - /// `stream-status` indicating whether the end of the stream was - /// reached. The returned value will be at most `len`; it may be less. + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. skip: func( /// The maximum number of bytes to skip. len: u64, diff --git a/crates/wasi/src/preview2/command.rs b/crates/wasi/src/preview2/command.rs index 898311157354..314a1a0796b2 100644 --- a/crates/wasi/src/preview2/command.rs +++ b/crates/wasi/src/preview2/command.rs @@ -33,6 +33,7 @@ pub fn add_to_linker(l: &mut wasmtime::component::Linker) -> any crate::preview2::bindings::clocks::timezone::add_to_linker(l, |t| t)?; crate::preview2::bindings::filesystem::types::add_to_linker(l, |t| t)?; crate::preview2::bindings::filesystem::preopens::add_to_linker(l, |t| t)?; + crate::preview2::bindings::io::error::add_to_linker(l, |t| t)?; crate::preview2::bindings::io::poll::add_to_linker(l, |t| t)?; crate::preview2::bindings::io::streams::add_to_linker(l, |t| t)?; crate::preview2::bindings::random::random::add_to_linker(l, |t| t)?; @@ -95,6 +96,7 @@ pub mod sync { crate::preview2::bindings::clocks::timezone::add_to_linker(l, |t| t)?; crate::preview2::bindings::sync_io::filesystem::types::add_to_linker(l, |t| t)?; crate::preview2::bindings::filesystem::preopens::add_to_linker(l, |t| t)?; + crate::preview2::bindings::io::error::add_to_linker(l, |t| t)?; crate::preview2::bindings::sync_io::io::poll::add_to_linker(l, |t| t)?; crate::preview2::bindings::sync_io::io::streams::add_to_linker(l, |t| t)?; crate::preview2::bindings::random::random::add_to_linker(l, |t| t)?; diff --git a/crates/wasi/src/preview2/host/io.rs b/crates/wasi/src/preview2/host/io.rs index 1ad5b4ccb075..ca5bc44b8d7b 100644 --- a/crates/wasi/src/preview2/host/io.rs +++ b/crates/wasi/src/preview2/host/io.rs @@ -1,10 +1,13 @@ use crate::preview2::{ + bindings::io::error, bindings::io::streams::{self, InputStream, OutputStream}, poll::subscribe, Pollable, StreamError, StreamResult, WasiView, }; use wasmtime::component::Resource; +impl error::Host for T {} + impl streams::Host for T { fn convert_stream_error(&mut self, err: StreamError) -> anyhow::Result { match err { @@ -17,7 +20,7 @@ impl streams::Host for T { } } -impl streams::HostError for T { +impl error::HostError for T { fn drop(&mut self, err: Resource) -> anyhow::Result<()> { self.table_mut().delete(err)?; Ok(()) @@ -226,8 +229,8 @@ impl streams::HostInputStream for T { pub mod sync { use crate::preview2::{ bindings::io::streams::{ - self as async_streams, Host as AsyncHost, HostError as AsyncHostError, - HostInputStream as AsyncHostInputStream, HostOutputStream as AsyncHostOutputStream, + self as async_streams, Host as AsyncHost, HostInputStream as AsyncHostInputStream, + HostOutputStream as AsyncHostOutputStream, }, bindings::sync_io::io::poll::Pollable, bindings::sync_io::io::streams::{self, InputStream, OutputStream}, @@ -253,16 +256,6 @@ pub mod sync { } } - impl streams::HostError for T { - fn drop(&mut self, err: Resource) -> anyhow::Result<()> { - AsyncHostError::drop(self, err) - } - - fn to_debug_string(&mut self, err: Resource) -> anyhow::Result { - AsyncHostError::to_debug_string(self, err) - } - } - impl streams::HostOutputStream for T { fn drop(&mut self, stream: Resource) -> anyhow::Result<()> { AsyncHostOutputStream::drop(self, stream) diff --git a/crates/wasi/src/preview2/mod.rs b/crates/wasi/src/preview2/mod.rs index 957a74a37f0b..102d70fadd3b 100644 --- a/crates/wasi/src/preview2/mod.rs +++ b/crates/wasi/src/preview2/mod.rs @@ -84,7 +84,7 @@ pub mod bindings { "wasi:io/poll/pollable": super::super::io::poll::Pollable, "wasi:io/streams/input-stream": super::super::io::streams::InputStream, "wasi:io/streams/output-stream": super::super::io::streams::OutputStream, - "wasi:io/streams/error": super::super::io::streams::Error, + "wasi:io/error/error": super::super::io::error::Error, } }); } @@ -169,7 +169,7 @@ pub mod bindings { "wasi:filesystem/types/descriptor": super::filesystem::Descriptor, "wasi:io/streams/input-stream": super::stream::InputStream, "wasi:io/streams/output-stream": super::stream::OutputStream, - "wasi:io/streams/error": super::stream::Error, + "wasi:io/error/error": super::stream::Error, "wasi:io/poll/pollable": super::poll::Pollable, "wasi:cli/terminal-input/terminal-input": super::stdio::TerminalInput, "wasi:cli/terminal-output/terminal-output": super::stdio::TerminalOutput, diff --git a/crates/wasi/src/preview2/stream.rs b/crates/wasi/src/preview2/stream.rs index 6200e1226d07..f81f5e2771e9 100644 --- a/crates/wasi/src/preview2/stream.rs +++ b/crates/wasi/src/preview2/stream.rs @@ -32,7 +32,7 @@ pub trait HostInputStream: Subscribe { } } -/// Representation of the `error` resource type in the `wasi:io/streams` +/// Representation of the `error` resource type in the `wasi:io/error` /// interface. /// /// This is currently `anyhow::Error` to retain full type information for diff --git a/crates/wasi/wit/deps/io/error.wit b/crates/wasi/wit/deps/io/error.wit new file mode 100644 index 000000000000..b45c594e6f83 --- /dev/null +++ b/crates/wasi/wit/deps/io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.0-rc-2023-11-05; + + +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// provide functions to further "downcast" this error into more specific + /// error information. For example, `error`s returned in streams derived + /// from filesystem types to be described using the filesystem's own + /// error-code type, using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter + /// `borrow` and returns + /// `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + to-debug-string: func() -> string; + } +} diff --git a/crates/wasi/wit/deps/io/streams.wit b/crates/wasi/wit/deps/io/streams.wit index 9442f60c0e16..45062505b993 100644 --- a/crates/wasi/wit/deps/io/streams.wit +++ b/crates/wasi/wit/deps/io/streams.wit @@ -6,6 +6,7 @@ package wasi:io@0.2.0-rc-2023-11-05; /// In the future, the component model is expected to add built-in stream types; /// when it does, they are expected to subsume this API. interface streams { + use error.{error}; use poll.{pollable}; /// An error for input-stream and output-stream operations. @@ -20,26 +21,6 @@ interface streams { closed } - /// Contextual error information about the last failure that happened on - /// a read, write, or flush from an `input-stream` or `output-stream`. - /// - /// This type is returned through the `stream-error` type whenever an - /// operation on a stream directly fails or an error is discovered - /// after-the-fact, for example when a write's failure shows up through a - /// later `flush` or `check-write`. - /// - /// Interfaces such as `wasi:filesystem/types` provide functionality to - /// further "downcast" this error into interface-specific error information. - resource error { - /// Returns a string that's suitable to assist humans in debugging this - /// error. - /// - /// The returned string will change across platforms and hosts which - /// means that parsing it, for example, would be a - /// platform-compatibility hazard. - to-debug-string: func() -> string; - } - /// An input bytestream. /// /// `input-stream`s are *non-blocking* to the extent practical on underlying @@ -51,21 +32,20 @@ interface streams { resource input-stream { /// Perform a non-blocking read from the stream. /// - /// This function returns a list of bytes containing the data that was - /// read, along with a `stream-status` which, indicates whether further - /// reads are expected to produce data. The returned list will contain up to - /// `len` bytes; it may return fewer than requested, but not more. An - /// empty list and `stream-status:open` indicates no more data is - /// available at this time, and that the pollable given by `subscribe` - /// will be ready when more data is available. + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. /// - /// Once a stream has reached the end, subsequent calls to `read` or - /// `skip` will always report `stream-status:ended` rather than producing more - /// data. + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. /// - /// When the caller gives a `len` of 0, it represents a request to read 0 - /// bytes. This read should always succeed and return an empty list and - /// the current `stream-status`. + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. /// /// The `len` parameter is a `u64`, which could represent a list of u8 which /// is not possible to allocate in wasm32, or not desirable to allocate as @@ -77,24 +57,16 @@ interface streams { ) -> result, stream-error>; /// Read bytes from a stream, after blocking until at least one byte can - /// be read. Except for blocking, identical to `read`. + /// be read. Except for blocking, behavior is identical to `read`. blocking-read: func( /// The maximum number of bytes to read len: u64 ) -> result, stream-error>; - /// Skip bytes from a stream. - /// - /// This is similar to the `read` function, but avoids copying the - /// bytes into the instance. - /// - /// Once a stream has reached the end, subsequent calls to read or - /// `skip` will always report end-of-stream rather than producing more - /// data. + /// Skip bytes from a stream. Returns number of bytes skipped. /// - /// This function returns the number of bytes skipped, along with a - /// `stream-status` indicating whether the end of the stream was - /// reached. The returned value will be at most `len`; it may be less. + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. skip: func( /// The maximum number of bytes to skip. len: u64,