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