Skip to content

add stream.forward and future.forward builtins - #709

Draft
rvolosatovs wants to merge 2 commits into
WebAssembly:mainfrom
rvolosatovs:stream-future-forward
Draft

add stream.forward and future.forward builtins#709
rvolosatovs wants to merge 2 commits into
WebAssembly:mainfrom
rvolosatovs:stream-future-forward

Conversation

@rvolosatovs

Copy link
Copy Markdown
Contributor

refs #658
tests blocked on #708

The Explainer specifies that a component may call `future.drop-readable`
before reading a value to signal loss of interest, in which case a
blocked `future.write` completes with `future-write-result.dropped`. But
`SharedFutureImpl.drop` asserted that any pending buffer is a
`WritableBuffer`, i.e. a pending *read*, while the only pending buffer
actually possible at this point is the buffer of a pending *write*: a
reader cannot drop its end while its own read is pending (`CopyEnd.drop`
traps while copying) and a writer cannot drop its end before the write
resolves (`WritableFutureEnd.drop` traps unless DONE). Exercising this
spec-legal path failed the assert instead of notifying the writer with
DROPPED.

Flip the assert to expect a `ReadableBuffer` (the source buffer of the
pending write), make `ReadableBufferGuestImpl` actually subclass
`ReadableBuffer` (it previously only derived `BufferGuestImpl`, unlike
`WritableBufferGuestImpl`, which does mix in `WritableBuffer`), and add
a test reproducing the scenario.

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
Assisted-by: claude:claude-fable-5
Introduce the ⏩-gated `{stream,future}.forward` built-ins for zero-copy
forwarding: given the readable end of a source stream (resp., future) and
the writable end of a destination of the same type, both ends are
transferred out of the calling component and the destination is fused
with the source, delegating all subsequent reads, cancels and drops to
it. Elements rendezvous directly between the outer producer and consumer
with end-to-end backpressure and no read-ahead, and end-of-stream and
drops propagate in both directions, allowing hosts to remove the
calling component from the copy path entirely. Forwards may be chained;
a forward that would (transitively) make a stream or future its own
source traps.

In the binary format, `stream.forward` is assigned opcode 0x2e and
`future.forward` opcode 0x2f. The binary decode test is left to a
follow-up commit so that test/binary/binary.wast keeps passing against
engines that do not decode these opcodes yet.

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
Assisted-by: claude:claude-fable-5
@rvolosatovs
rvolosatovs force-pushed the stream-future-forward branch from 5eaa8d2 to 17dffe0 Compare August 24, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant