Skip to content

Commit 72b64dc

Browse files
committed
Change how async stream/future results are encoded
Updating to WebAssembly/component-model#498
1 parent adbeb1b commit 72b64dc

File tree

4 files changed

+59
-38
lines changed

4 files changed

+59
-38
lines changed

Cargo.lock

-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/guest-rust/rt/src/async_support.rs

+35-7
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,41 @@ const STATUS_STARTING: u32 = 1;
287287
const STATUS_STARTED: u32 = 2;
288288
const STATUS_RETURNED: u32 = 3;
289289

290+
const BLOCKED: u32 = 0xffff_ffff;
291+
const COMPLETED: u32 = 0x0;
292+
const CLOSED: u32 = 0x1;
293+
const CANCELLED: u32 = 0x2;
294+
295+
/// Return code of stream/future operations.
296+
#[derive(PartialEq, Debug)]
297+
enum ReturnCode {
298+
/// The operation is blocked and has not completed.
299+
Blocked,
300+
/// The operation completed with the specified number of items.
301+
Completed(u32),
302+
/// The other end is closed, but before that the specified number of items
303+
/// were transferred.
304+
Closed(u32),
305+
/// The operation was cancelled, but before that the specified number of
306+
/// items were transferred.
307+
Cancelled(u32),
308+
}
309+
310+
impl ReturnCode {
311+
fn decode(val: u32) -> ReturnCode {
312+
if val == BLOCKED {
313+
return ReturnCode::Blocked;
314+
}
315+
let amt = val >> 4;
316+
match val & 0xf {
317+
COMPLETED => ReturnCode::Completed(amt),
318+
CLOSED => ReturnCode::Closed(amt),
319+
CANCELLED => ReturnCode::Cancelled(amt),
320+
_ => panic!("unknown return code {val:#x}"),
321+
}
322+
}
323+
}
324+
290325
/// Starts execution of the `task` provided, an asynchronous computation.
291326
///
292327
/// This is used for async-lifted exports at their definition site. The
@@ -313,13 +348,6 @@ pub fn start_task(task: impl Future<Output = ()> + 'static) -> u32 {
313348
}
314349
}
315350

316-
/// stream/future read/write results defined by the Component Model ABI.
317-
mod results {
318-
pub const BLOCKED: u32 = 0xffff_ffff;
319-
pub const CLOSED: u32 = 0x8000_0000;
320-
pub const CANCELED: u32 = 0;
321-
}
322-
323351
/// Handle a progress notification from the host regarding either a call to an
324352
/// async-lowered import or a stream/future read/write operation.
325353
///

crates/guest-rust/rt/src/async_support/future_support.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@
8888
//! changing its layout. Currently this is par-for-the-course with bindings.
8989
9090
use {
91-
super::results,
9291
super::waitable::{WaitableOp, WaitableOperation},
92+
super::ReturnCode,
9393
crate::Cleanup,
9494
std::{
9595
alloc::Layout,
@@ -306,8 +306,8 @@ where
306306
.as_ref()
307307
.map(|c| c.ptr.as_ptr())
308308
.unwrap_or(ptr::null_mut());
309-
match code {
310-
results::BLOCKED => Err((writer, cleanup)),
309+
match ReturnCode::decode(code) {
310+
ReturnCode::Blocked => Err((writer, cleanup)),
311311

312312
// The other end has closed its end.
313313
//
@@ -316,11 +316,11 @@ where
316316
// instance of `T` which takes ownership of pointers and resources
317317
// and such. The allocation of `ptr` is then cleaned up naturally
318318
// when `cleanup` goes out of scope.
319-
results::CLOSED | results::CANCELED => {
319+
c @ ReturnCode::Closed(0) | c @ ReturnCode::Cancelled(0) => {
320320
// SAFETY: we're the ones managing `ptr` so we know it's safe to
321321
// pass here.
322322
let value = unsafe { (writer.vtable.lift)(ptr) };
323-
let status = if code == results::CLOSED {
323+
let status = if c == ReturnCode::Closed(0) {
324324
WriteComplete::Closed(value)
325325
} else {
326326
WriteComplete::Cancelled(value)
@@ -337,7 +337,7 @@ where
337337
//
338338
// Afterwards the `cleanup` itself is naturally dropped and cleaned
339339
// up.
340-
1 => {
340+
ReturnCode::Completed(1) | ReturnCode::Closed(1) | ReturnCode::Cancelled(1) => {
341341
// SAFETY: we're the ones managing `ptr` so we know it's safe to
342342
// pass here.
343343
unsafe {
@@ -346,7 +346,7 @@ where
346346
Ok((WriteComplete::Written, writer))
347347
}
348348

349-
other => unreachable!("unexpected code {other:#x}"),
349+
other => unreachable!("unexpected code {other:?}"),
350350
}
351351
}
352352

@@ -566,22 +566,22 @@ where
566566
(reader, cleanup): Self::InProgress,
567567
code: u32,
568568
) -> Result<Self::Result, Self::InProgress> {
569-
match code {
570-
results::BLOCKED => Err((reader, cleanup)),
569+
match ReturnCode::decode(code) {
570+
ReturnCode::Blocked => Err((reader, cleanup)),
571571

572572
// The read didn't complete, so `cleanup` is still uninitialized, so
573573
// let it fall out of scope.
574-
results::CLOSED => Ok((ReadComplete::Closed, reader)),
574+
ReturnCode::Closed(0) => Ok((ReadComplete::Closed, reader)),
575575

576576
// Like `in_progress_closed` the read operation has finished but
577577
// without a value, so let `cleanup` fall out of scope to clean up
578578
// its allocation.
579-
results::CANCELED => Ok((ReadComplete::Cancelled, reader)),
579+
ReturnCode::Cancelled(0) => Ok((ReadComplete::Cancelled, reader)),
580580

581581
// The read has completed, so lift the value from the stored memory and
582582
// `cleanup` naturally falls out of scope after transferring ownership of
583583
// everything to the returned `value`.
584-
1 => {
584+
ReturnCode::Completed(1) | ReturnCode::Closed(1) | ReturnCode::Cancelled(1) => {
585585
let ptr = cleanup
586586
.as_ref()
587587
.map(|c| c.ptr.as_ptr())
@@ -593,7 +593,7 @@ where
593593
Ok((ReadComplete::Value(value), reader))
594594
}
595595

596-
other => panic!("unexpected code {other:#x}"),
596+
other => panic!("unexpected code {other:?}"),
597597
}
598598
}
599599

crates/guest-rust/rt/src/async_support/stream_support.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! module documentation in `future_support.rs`.
33
44
use crate::async_support::waitable::{WaitableOp, WaitableOperation};
5-
use crate::async_support::{results, AbiBuffer};
5+
use crate::async_support::{AbiBuffer, ReturnCode};
66
use {
77
crate::Cleanup,
88
std::{
@@ -258,11 +258,11 @@ where
258258
(writer, mut buf): Self::InProgress,
259259
code: u32,
260260
) -> Result<Self::Result, Self::InProgress> {
261-
match code {
262-
results::BLOCKED => Err((writer, buf)),
263-
results::CLOSED => Ok((StreamResult::Closed, buf)),
264-
results::CANCELED => Ok((StreamResult::Cancelled, buf)),
265-
amt => {
261+
match ReturnCode::decode(code) {
262+
ReturnCode::Blocked => Err((writer, buf)),
263+
ReturnCode::Closed(0) => Ok((StreamResult::Closed, buf)),
264+
ReturnCode::Cancelled(0) => Ok((StreamResult::Cancelled, buf)),
265+
ReturnCode::Completed(amt) | ReturnCode::Closed(amt) | ReturnCode::Cancelled(amt) => {
266266
let amt = amt.try_into().unwrap();
267267
buf.advance(amt);
268268
Ok((StreamResult::Complete(amt), buf))
@@ -480,20 +480,20 @@ where
480480
(reader, mut buf, cleanup): Self::InProgress,
481481
code: u32,
482482
) -> Result<Self::Result, Self::InProgress> {
483-
match code {
484-
results::BLOCKED => Err((reader, buf, cleanup)),
483+
match ReturnCode::decode(code) {
484+
ReturnCode::Blocked => Err((reader, buf, cleanup)),
485485

486486
// Note that the `cleanup`, if any, is discarded here.
487-
results::CLOSED => Ok((StreamResult::Closed, buf)),
487+
ReturnCode::Closed(0) => Ok((StreamResult::Closed, buf)),
488488

489489
// When an in-progress read is successfully cancelled then the
490490
// allocation that was being read into, if any, is just discarded.
491491
//
492492
// TODO: should maybe thread this around like `AbiBuffer` to cache
493493
// the read allocation?
494-
results::CANCELED => Ok((StreamResult::Cancelled, buf)),
494+
ReturnCode::Cancelled(0) => Ok((StreamResult::Cancelled, buf)),
495495

496-
amt => {
496+
ReturnCode::Completed(amt) | ReturnCode::Closed(amt) | ReturnCode::Cancelled(amt) => {
497497
let amt = usize::try_from(amt).unwrap();
498498
let cur_len = buf.len();
499499
assert!(amt <= buf.capacity() - cur_len);

0 commit comments

Comments
 (0)