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