|
| 1 | +package wasi:io@0.2.0; |
| 2 | + |
| 3 | +/// WASI I/O is an I/O abstraction API which is currently focused on providing |
| 4 | +/// stream types. |
| 5 | +/// |
| 6 | +/// In the future, the component model is expected to add built-in stream types; |
| 7 | +/// when it does, they are expected to subsume this API. |
| 8 | +interface streams { |
| 9 | + use error.{error}; |
| 10 | + use poll.{pollable}; |
| 11 | + |
| 12 | + /// An error for input-stream and output-stream operations. |
| 13 | + variant stream-error { |
| 14 | + /// The last operation (a write or flush) failed before completion. |
| 15 | + /// |
| 16 | + /// More information is available in the `error` payload. |
| 17 | + last-operation-failed(error), |
| 18 | + /// The stream is closed: no more input will be accepted by the |
| 19 | + /// stream. A closed output-stream will return this error on all |
| 20 | + /// future operations. |
| 21 | + closed |
| 22 | + } |
| 23 | + |
| 24 | + /// An input bytestream. |
| 25 | + /// |
| 26 | + /// `input-stream`s are *non-blocking* to the extent practical on underlying |
| 27 | + /// platforms. I/O operations always return promptly; if fewer bytes are |
| 28 | + /// promptly available than requested, they return the number of bytes promptly |
| 29 | + /// available, which could even be zero. To wait for data to be available, |
| 30 | + /// use the `subscribe` function to obtain a `pollable` which can be polled |
| 31 | + /// for using `wasi:io/poll`. |
| 32 | + resource input-stream { |
| 33 | + /// Perform a non-blocking read from the stream. |
| 34 | + /// |
| 35 | + /// When the source of a `read` is binary data, the bytes from the source |
| 36 | + /// are returned verbatim. When the source of a `read` is known to the |
| 37 | + /// implementation to be text, bytes containing the UTF-8 encoding of the |
| 38 | + /// text are returned. |
| 39 | + /// |
| 40 | + /// This function returns a list of bytes containing the read data, |
| 41 | + /// when successful. The returned list will contain up to `len` bytes; |
| 42 | + /// it may return fewer than requested, but not more. The list is |
| 43 | + /// empty when no bytes are available for reading at this time. The |
| 44 | + /// pollable given by `subscribe` will be ready when more bytes are |
| 45 | + /// available. |
| 46 | + /// |
| 47 | + /// This function fails with a `stream-error` when the operation |
| 48 | + /// encounters an error, giving `last-operation-failed`, or when the |
| 49 | + /// stream is closed, giving `closed`. |
| 50 | + /// |
| 51 | + /// When the caller gives a `len` of 0, it represents a request to |
| 52 | + /// read 0 bytes. If the stream is still open, this call should |
| 53 | + /// succeed and return an empty list, or otherwise fail with `closed`. |
| 54 | + /// |
| 55 | + /// The `len` parameter is a `u64`, which could represent a list of u8 which |
| 56 | + /// is not possible to allocate in wasm32, or not desirable to allocate as |
| 57 | + /// as a return value by the callee. The callee may return a list of bytes |
| 58 | + /// less than `len` in size while more bytes are available for reading. |
| 59 | + read: func( |
| 60 | + /// The maximum number of bytes to read |
| 61 | + len: u64 |
| 62 | + ) -> result<list<u8>, stream-error>; |
| 63 | + |
| 64 | + /// Read bytes from a stream, after blocking until at least one byte can |
| 65 | + /// be read. Except for blocking, behavior is identical to `read`. |
| 66 | + blocking-read: func( |
| 67 | + /// The maximum number of bytes to read |
| 68 | + len: u64 |
| 69 | + ) -> result<list<u8>, stream-error>; |
| 70 | + |
| 71 | + /// Skip bytes from a stream. Returns number of bytes skipped. |
| 72 | + /// |
| 73 | + /// Behaves identical to `read`, except instead of returning a list |
| 74 | + /// of bytes, returns the number of bytes consumed from the stream. |
| 75 | + skip: func( |
| 76 | + /// The maximum number of bytes to skip. |
| 77 | + len: u64, |
| 78 | + ) -> result<u64, stream-error>; |
| 79 | + |
| 80 | + /// Skip bytes from a stream, after blocking until at least one byte |
| 81 | + /// can be skipped. Except for blocking behavior, identical to `skip`. |
| 82 | + blocking-skip: func( |
| 83 | + /// The maximum number of bytes to skip. |
| 84 | + len: u64, |
| 85 | + ) -> result<u64, stream-error>; |
| 86 | + |
| 87 | + /// Create a `pollable` which will resolve once either the specified stream |
| 88 | + /// has bytes available to read or the other end of the stream has been |
| 89 | + /// closed. |
| 90 | + /// The created `pollable` is a child resource of the `input-stream`. |
| 91 | + /// Implementations may trap if the `input-stream` is dropped before |
| 92 | + /// all derived `pollable`s created with this function are dropped. |
| 93 | + subscribe: func() -> pollable; |
| 94 | + } |
| 95 | + |
| 96 | + |
| 97 | + /// An output bytestream. |
| 98 | + /// |
| 99 | + /// `output-stream`s are *non-blocking* to the extent practical on |
| 100 | + /// underlying platforms. Except where specified otherwise, I/O operations also |
| 101 | + /// always return promptly, after the number of bytes that can be written |
| 102 | + /// promptly, which could even be zero. To wait for the stream to be ready to |
| 103 | + /// accept data, the `subscribe` function to obtain a `pollable` which can be |
| 104 | + /// polled for using `wasi:io/poll`. |
| 105 | + resource output-stream { |
| 106 | + /// Check readiness for writing. This function never blocks. |
| 107 | + /// |
| 108 | + /// Returns the number of bytes permitted for the next call to `write`, |
| 109 | + /// or an error. Calling `write` with more bytes than this function has |
| 110 | + /// permitted will trap. |
| 111 | + /// |
| 112 | + /// When this function returns 0 bytes, the `subscribe` pollable will |
| 113 | + /// become ready when this function will report at least 1 byte, or an |
| 114 | + /// error. |
| 115 | + check-write: func() -> result<u64, stream-error>; |
| 116 | + |
| 117 | + /// Perform a write. This function never blocks. |
| 118 | + /// |
| 119 | + /// When the destination of a `write` is binary data, the bytes from |
| 120 | + /// `contents` are written verbatim. When the destination of a `write` is |
| 121 | + /// known to the implementation to be text, the bytes of `contents` are |
| 122 | + /// transcoded from UTF-8 into the encoding of the destination and then |
| 123 | + /// written. |
| 124 | + /// |
| 125 | + /// Precondition: check-write gave permit of Ok(n) and contents has a |
| 126 | + /// length of less than or equal to n. Otherwise, this function will trap. |
| 127 | + /// |
| 128 | + /// returns Err(closed) without writing if the stream has closed since |
| 129 | + /// the last call to check-write provided a permit. |
| 130 | + write: func( |
| 131 | + contents: list<u8> |
| 132 | + ) -> result<_, stream-error>; |
| 133 | + |
| 134 | + /// Perform a write of up to 4096 bytes, and then flush the stream. Block |
| 135 | + /// until all of these operations are complete, or an error occurs. |
| 136 | + /// |
| 137 | + /// This is a convenience wrapper around the use of `check-write`, |
| 138 | + /// `subscribe`, `write`, and `flush`, and is implemented with the |
| 139 | + /// following pseudo-code: |
| 140 | + /// |
| 141 | + /// ```text |
| 142 | + /// let pollable = this.subscribe(); |
| 143 | + /// while !contents.is_empty() { |
| 144 | + /// // Wait for the stream to become writable |
| 145 | + /// pollable.block(); |
| 146 | + /// let Ok(n) = this.check-write(); // eliding error handling |
| 147 | + /// let len = min(n, contents.len()); |
| 148 | + /// let (chunk, rest) = contents.split_at(len); |
| 149 | + /// this.write(chunk ); // eliding error handling |
| 150 | + /// contents = rest; |
| 151 | + /// } |
| 152 | + /// this.flush(); |
| 153 | + /// // Wait for completion of `flush` |
| 154 | + /// pollable.block(); |
| 155 | + /// // Check for any errors that arose during `flush` |
| 156 | + /// let _ = this.check-write(); // eliding error handling |
| 157 | + /// ``` |
| 158 | + blocking-write-and-flush: func( |
| 159 | + contents: list<u8> |
| 160 | + ) -> result<_, stream-error>; |
| 161 | + |
| 162 | + /// Request to flush buffered output. This function never blocks. |
| 163 | + /// |
| 164 | + /// This tells the output-stream that the caller intends any buffered |
| 165 | + /// output to be flushed. the output which is expected to be flushed |
| 166 | + /// is all that has been passed to `write` prior to this call. |
| 167 | + /// |
| 168 | + /// Upon calling this function, the `output-stream` will not accept any |
| 169 | + /// writes (`check-write` will return `ok(0)`) until the flush has |
| 170 | + /// completed. The `subscribe` pollable will become ready when the |
| 171 | + /// flush has completed and the stream can accept more writes. |
| 172 | + flush: func() -> result<_, stream-error>; |
| 173 | + |
| 174 | + /// Request to flush buffered output, and block until flush completes |
| 175 | + /// and stream is ready for writing again. |
| 176 | + blocking-flush: func() -> result<_, stream-error>; |
| 177 | + |
| 178 | + /// Create a `pollable` which will resolve once the output-stream |
| 179 | + /// is ready for more writing, or an error has occured. When this |
| 180 | + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an |
| 181 | + /// error. |
| 182 | + /// |
| 183 | + /// If the stream is closed, this pollable is always ready immediately. |
| 184 | + /// |
| 185 | + /// The created `pollable` is a child resource of the `output-stream`. |
| 186 | + /// Implementations may trap if the `output-stream` is dropped before |
| 187 | + /// all derived `pollable`s created with this function are dropped. |
| 188 | + subscribe: func() -> pollable; |
| 189 | + |
| 190 | + /// Write zeroes to a stream. |
| 191 | + /// |
| 192 | + /// This should be used precisely like `write` with the exact same |
| 193 | + /// preconditions (must use check-write first), but instead of |
| 194 | + /// passing a list of bytes, you simply pass the number of zero-bytes |
| 195 | + /// that should be written. |
| 196 | + write-zeroes: func( |
| 197 | + /// The number of zero-bytes to write |
| 198 | + len: u64 |
| 199 | + ) -> result<_, stream-error>; |
| 200 | + |
| 201 | + /// Perform a write of up to 4096 zeroes, and then flush the stream. |
| 202 | + /// Block until all of these operations are complete, or an error |
| 203 | + /// occurs. |
| 204 | + /// |
| 205 | + /// This is a convenience wrapper around the use of `check-write`, |
| 206 | + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with |
| 207 | + /// the following pseudo-code: |
| 208 | + /// |
| 209 | + /// ```text |
| 210 | + /// let pollable = this.subscribe(); |
| 211 | + /// while num_zeroes != 0 { |
| 212 | + /// // Wait for the stream to become writable |
| 213 | + /// pollable.block(); |
| 214 | + /// let Ok(n) = this.check-write(); // eliding error handling |
| 215 | + /// let len = min(n, num_zeroes); |
| 216 | + /// this.write-zeroes(len); // eliding error handling |
| 217 | + /// num_zeroes -= len; |
| 218 | + /// } |
| 219 | + /// this.flush(); |
| 220 | + /// // Wait for completion of `flush` |
| 221 | + /// pollable.block(); |
| 222 | + /// // Check for any errors that arose during `flush` |
| 223 | + /// let _ = this.check-write(); // eliding error handling |
| 224 | + /// ``` |
| 225 | + blocking-write-zeroes-and-flush: func( |
| 226 | + /// The number of zero-bytes to write |
| 227 | + len: u64 |
| 228 | + ) -> result<_, stream-error>; |
| 229 | + |
| 230 | + /// Read from one stream and write to another. |
| 231 | + /// |
| 232 | + /// The behavior of splice is equivelant to: |
| 233 | + /// 1. calling `check-write` on the `output-stream` |
| 234 | + /// 2. calling `read` on the `input-stream` with the smaller of the |
| 235 | + /// `check-write` permitted length and the `len` provided to `splice` |
| 236 | + /// 3. calling `write` on the `output-stream` with that read data. |
| 237 | + /// |
| 238 | + /// Any error reported by the call to `check-write`, `read`, or |
| 239 | + /// `write` ends the splice and reports that error. |
| 240 | + /// |
| 241 | + /// This function returns the number of bytes transferred; it may be less |
| 242 | + /// than `len`. |
| 243 | + splice: func( |
| 244 | + /// The stream to read from |
| 245 | + src: borrow<input-stream>, |
| 246 | + /// The number of bytes to splice |
| 247 | + len: u64, |
| 248 | + ) -> result<u64, stream-error>; |
| 249 | + |
| 250 | + /// Read from one stream and write to another, with blocking. |
| 251 | + /// |
| 252 | + /// This is similar to `splice`, except that it blocks until the |
| 253 | + /// `output-stream` is ready for writing, and the `input-stream` |
| 254 | + /// is ready for reading, before performing the `splice`. |
| 255 | + blocking-splice: func( |
| 256 | + /// The stream to read from |
| 257 | + src: borrow<input-stream>, |
| 258 | + /// The number of bytes to splice |
| 259 | + len: u64, |
| 260 | + ) -> result<u64, stream-error>; |
| 261 | + } |
| 262 | +} |
0 commit comments