1package wasi:[email protected];
2
3@since(version = 0.2.0)
4interface error {
5  /// A resource which represents some error information.
6  ///
7  /// The only method provided by this resource is `to-debug-string`,
8  /// which provides some human-readable information about the error.
9  ///
10  /// In the `wasi:io` package, this resource is returned through the
11  /// `wasi:io/streams/stream-error` type.
12  ///
13  /// To provide more specific error information, other interfaces may
14  /// offer functions to "downcast" this error into more specific types. For example,
15  /// errors returned from streams derived from filesystem types can be described using
16  /// the filesystem's own error-code type. This is done using the function
17  /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow<error>`
18  /// parameter and returns an `option<wasi:filesystem/types/error-code>`.
19  ///
20  /// The set of functions which can "downcast" an `error` into a more
21  /// concrete type is open.
22  @since(version = 0.2.0)
23  resource error {
24    /// Returns a string that is suitable to assist humans in debugging
25    /// this error.
26    ///
27    /// WARNING: The returned string should not be consumed mechanically!
28    /// It may change across platforms, hosts, or other implementation
29    /// details. Parsing this string is a major platform-compatibility
30    /// hazard.
31    @since(version = 0.2.0)
32    to-debug-string: func() -> string;
33  }
34}
35
36/// A poll API intended to let users wait for I/O events on multiple handles
37/// at once.
38@since(version = 0.2.0)
39interface poll {
40  /// `pollable` represents a single I/O event which may be ready, or not.
41  @since(version = 0.2.0)
42  resource pollable {
43    /// Return the readiness of a pollable. This function never blocks.
44    ///
45    /// Returns `true` when the pollable is ready, and `false` otherwise.
46    @since(version = 0.2.0)
47    ready: func() -> bool;
48    /// `block` returns immediately if the pollable is ready, and otherwise
49    /// blocks until ready.
50    ///
51    /// This function is equivalent to calling `poll.poll` on a list
52    /// containing only this pollable.
53    @since(version = 0.2.0)
54    block: func();
55  }
56
57  /// Poll for completion on a set of pollables.
58  ///
59  /// This function takes a list of pollables, which identify I/O sources of
60  /// interest, and waits until one or more of the events is ready for I/O.
61  ///
62  /// The result `list<u32>` contains one or more indices of handles in the
63  /// argument list that is ready for I/O.
64  ///
65  /// This function traps if either:
66  /// - the list is empty, or:
67  /// - the list contains more elements than can be indexed with a `u32` value.
68  ///
69  /// A timeout can be implemented by adding a pollable from the
70  /// wasi-clocks API to the list.
71  ///
72  /// This function does not return a `result`; polling in itself does not
73  /// do any I/O so it doesn't fail. If any of the I/O sources identified by
74  /// the pollables has an error, it is indicated by marking the source as
75  /// being ready for I/O.
76  @since(version = 0.2.0)
77  poll: func(in: list<borrow<pollable>>) -> list<u32>;
78}
79
80/// WASI I/O is an I/O abstraction API which is currently focused on providing
81/// stream types.
82///
83/// In the future, the component model is expected to add built-in stream types;
84/// when it does, they are expected to subsume this API.
85@since(version = 0.2.0)
86interface streams {
87  @since(version = 0.2.0)
88  use error.{error};
89  @since(version = 0.2.0)
90  use poll.{pollable};
91
92  /// An error for input-stream and output-stream operations.
93  @since(version = 0.2.0)
94  variant stream-error {
95    /// The last operation (a write or flush) failed before completion.
96    ///
97    /// More information is available in the `error` payload.
98    ///
99    /// After this, the stream will be closed. All future operations return
100    /// `stream-error::closed`.
101    last-operation-failed(error),
102    /// The stream is closed: no more input will be accepted by the
103    /// stream. A closed output-stream will return this error on all
104    /// future operations.
105    closed,
106  }
107
108  /// An input bytestream.
109  ///
110  /// `input-stream`s are *non-blocking* to the extent practical on underlying
111  /// platforms. I/O operations always return promptly; if fewer bytes are
112  /// promptly available than requested, they return the number of bytes promptly
113  /// available, which could even be zero. To wait for data to be available,
114  /// use the `subscribe` function to obtain a `pollable` which can be polled
115  /// for using `wasi:io/poll`.
116  @since(version = 0.2.0)
117  resource input-stream {
118    /// Perform a non-blocking read from the stream.
119    ///
120    /// When the source of a `read` is binary data, the bytes from the source
121    /// are returned verbatim. When the source of a `read` is known to the
122    /// implementation to be text, bytes containing the UTF-8 encoding of the
123    /// text are returned.
124    ///
125    /// This function returns a list of bytes containing the read data,
126    /// when successful. The returned list will contain up to `len` bytes;
127    /// it may return fewer than requested, but not more. The list is
128    /// empty when no bytes are available for reading at this time. The
129    /// pollable given by `subscribe` will be ready when more bytes are
130    /// available.
131    ///
132    /// This function fails with a `stream-error` when the operation
133    /// encounters an error, giving `last-operation-failed`, or when the
134    /// stream is closed, giving `closed`.
135    ///
136    /// When the caller gives a `len` of 0, it represents a request to
137    /// read 0 bytes. If the stream is still open, this call should
138    /// succeed and return an empty list, or otherwise fail with `closed`.
139    ///
140    /// The `len` parameter is a `u64`, which could represent a list of u8 which
141    /// is not possible to allocate in wasm32, or not desirable to allocate as
142    /// as a return value by the callee. The callee may return a list of bytes
143    /// less than `len` in size while more bytes are available for reading.
144    @since(version = 0.2.0)
145    read: func(len: u64) -> result<list<u8>, stream-error>;
146    /// Read bytes from a stream, after blocking until at least one byte can
147    /// be read. Except for blocking, behavior is identical to `read`.
148    @since(version = 0.2.0)
149    blocking-read: func(len: u64) -> result<list<u8>, stream-error>;
150    /// Skip bytes from a stream. Returns number of bytes skipped.
151    ///
152    /// Behaves identical to `read`, except instead of returning a list
153    /// of bytes, returns the number of bytes consumed from the stream.
154    @since(version = 0.2.0)
155    skip: func(len: u64) -> result<u64, stream-error>;
156    /// Skip bytes from a stream, after blocking until at least one byte
157    /// can be skipped. Except for blocking behavior, identical to `skip`.
158    @since(version = 0.2.0)
159    blocking-skip: func(len: u64) -> result<u64, stream-error>;
160    /// Create a `pollable` which will resolve once either the specified stream
161    /// has bytes available to read or the other end of the stream has been
162    /// closed.
163    /// The created `pollable` is a child resource of the `input-stream`.
164    /// Implementations may trap if the `input-stream` is dropped before
165    /// all derived `pollable`s created with this function are dropped.
166    @since(version = 0.2.0)
167    subscribe: func() -> pollable;
168  }
169
170  /// An output bytestream.
171  ///
172  /// `output-stream`s are *non-blocking* to the extent practical on
173  /// underlying platforms. Except where specified otherwise, I/O operations also
174  /// always return promptly, after the number of bytes that can be written
175  /// promptly, which could even be zero. To wait for the stream to be ready to
176  /// accept data, the `subscribe` function to obtain a `pollable` which can be
177  /// polled for using `wasi:io/poll`.
178  ///
179  /// Dropping an `output-stream` while there's still an active write in
180  /// progress may result in the data being lost. Before dropping the stream,
181  /// be sure to fully flush your writes.
182  @since(version = 0.2.0)
183  resource output-stream {
184    /// Check readiness for writing. This function never blocks.
185    ///
186    /// Returns the number of bytes permitted for the next call to `write`,
187    /// or an error. Calling `write` with more bytes than this function has
188    /// permitted will trap.
189    ///
190    /// When this function returns 0 bytes, the `subscribe` pollable will
191    /// become ready when this function will report at least 1 byte, or an
192    /// error.
193    @since(version = 0.2.0)
194    check-write: func() -> result<u64, stream-error>;
195    /// Perform a write. This function never blocks.
196    ///
197    /// When the destination of a `write` is binary data, the bytes from
198    /// `contents` are written verbatim. When the destination of a `write` is
199    /// known to the implementation to be text, the bytes of `contents` are
200    /// transcoded from UTF-8 into the encoding of the destination and then
201    /// written.
202    ///
203    /// Precondition: check-write gave permit of Ok(n) and contents has a
204    /// length of less than or equal to n. Otherwise, this function will trap.
205    ///
206    /// returns Err(closed) without writing if the stream has closed since
207    /// the last call to check-write provided a permit.
208    @since(version = 0.2.0)
209    write: func(contents: list<u8>) -> result<_, stream-error>;
210    /// Perform a write of up to 4096 bytes, and then flush the stream. Block
211    /// until all of these operations are complete, or an error occurs.
212    ///
213    /// This is a convenience wrapper around the use of `check-write`,
214    /// `subscribe`, `write`, and `flush`, and is implemented with the
215    /// following pseudo-code:
216    ///
217    /// ```text
218    /// let pollable = this.subscribe();
219    /// while !contents.is_empty() {
220    ///     // Wait for the stream to become writable
221    ///     pollable.block();
222    ///     let Ok(n) = this.check-write(); // eliding error handling
223    ///     let len = min(n, contents.len());
224    ///     let (chunk, rest) = contents.split_at(len);
225    ///     this.write(chunk  );            // eliding error handling
226    ///     contents = rest;
227    /// }
228    /// this.flush();
229    /// // Wait for completion of `flush`
230    /// pollable.block();
231    /// // Check for any errors that arose during `flush`
232    /// let _ = this.check-write();         // eliding error handling
233    /// ```
234    @since(version = 0.2.0)
235    blocking-write-and-flush: func(contents: list<u8>) -> result<_, stream-error>;
236    /// Request to flush buffered output. This function never blocks.
237    ///
238    /// This tells the output-stream that the caller intends any buffered
239    /// output to be flushed. the output which is expected to be flushed
240    /// is all that has been passed to `write` prior to this call.
241    ///
242    /// Upon calling this function, the `output-stream` will not accept any
243    /// writes (`check-write` will return `ok(0)`) until the flush has
244    /// completed. The `subscribe` pollable will become ready when the
245    /// flush has completed and the stream can accept more writes.
246    @since(version = 0.2.0)
247    flush: func() -> result<_, stream-error>;
248    /// Request to flush buffered output, and block until flush completes
249    /// and stream is ready for writing again.
250    @since(version = 0.2.0)
251    blocking-flush: func() -> result<_, stream-error>;
252    /// Create a `pollable` which will resolve once the output-stream
253    /// is ready for more writing, or an error has occurred. When this
254    /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an
255    /// error.
256    ///
257    /// If the stream is closed, this pollable is always ready immediately.
258    ///
259    /// The created `pollable` is a child resource of the `output-stream`.
260    /// Implementations may trap if the `output-stream` is dropped before
261    /// all derived `pollable`s created with this function are dropped.
262    @since(version = 0.2.0)
263    subscribe: func() -> pollable;
264    /// Write zeroes to a stream.
265    ///
266    /// This should be used precisely like `write` with the exact same
267    /// preconditions (must use check-write first), but instead of
268    /// passing a list of bytes, you simply pass the number of zero-bytes
269    /// that should be written.
270    @since(version = 0.2.0)
271    write-zeroes: func(len: u64) -> result<_, stream-error>;
272    /// Perform a write of up to 4096 zeroes, and then flush the stream.
273    /// Block until all of these operations are complete, or an error
274    /// occurs.
275    ///
276    /// This is a convenience wrapper around the use of `check-write`,
277    /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with
278    /// the following pseudo-code:
279    ///
280    /// ```text
281    /// let pollable = this.subscribe();
282    /// while num_zeroes != 0 {
283    ///     // Wait for the stream to become writable
284    ///     pollable.block();
285    ///     let Ok(n) = this.check-write(); // eliding error handling
286    ///     let len = min(n, num_zeroes);
287    ///     this.write-zeroes(len);         // eliding error handling
288    ///     num_zeroes -= len;
289    /// }
290    /// this.flush();
291    /// // Wait for completion of `flush`
292    /// pollable.block();
293    /// // Check for any errors that arose during `flush`
294    /// let _ = this.check-write();         // eliding error handling
295    /// ```
296    @since(version = 0.2.0)
297    blocking-write-zeroes-and-flush: func(len: u64) -> result<_, stream-error>;
298    /// Read from one stream and write to another.
299    ///
300    /// The behavior of splice is equivalent to:
301    /// 1. calling `check-write` on the `output-stream`
302    /// 2. calling `read` on the `input-stream` with the smaller of the
303    /// `check-write` permitted length and the `len` provided to `splice`
304    /// 3. calling `write` on the `output-stream` with that read data.
305    ///
306    /// Any error reported by the call to `check-write`, `read`, or
307    /// `write` ends the splice and reports that error.
308    ///
309    /// This function returns the number of bytes transferred; it may be less
310    /// than `len`.
311    @since(version = 0.2.0)
312    splice: func(src: borrow<input-stream>, len: u64) -> result<u64, stream-error>;
313    /// Read from one stream and write to another, with blocking.
314    ///
315    /// This is similar to `splice`, except that it blocks until the
316    /// `output-stream` is ready for writing, and the `input-stream`
317    /// is ready for reading, before performing the `splice`.
318    @since(version = 0.2.0)
319    blocking-splice: func(src: borrow<input-stream>, len: u64) -> result<u64, stream-error>;
320  }
321}
322
323@since(version = 0.2.0)
324world imports {
325  @since(version = 0.2.0)
326  import error;
327  @since(version = 0.2.0)
328  import poll;
329  @since(version = 0.2.0)
330  import streams;
331}
332