Skip to main content

wasmtime/runtime/component/concurrent/
futures_and_streams.rs

1use super::table::{TableDebug, TableId};
2use super::{Event, GlobalErrorContextRefCount, Waitable, WaitableCommon};
3use crate::component::concurrent::{
4    ConcurrentState, CurrentThread, QualifiedThreadId, WorkItem, tls,
5};
6use crate::component::func::{self, LiftContext, LowerContext};
7use crate::component::matching::InstanceType;
8use crate::component::resources::{HostResourceIndex, HostResourceTables};
9use crate::component::types;
10use crate::component::values::ErrorContextAny;
11use crate::component::{
12    AsAccessor, ComponentInstanceId, ComponentType, FutureAny, Instance, Lift, Lower,
13    RuntimeInstance, StreamAny, Val, WasmList,
14};
15use crate::prelude::*;
16use crate::store::{StoreOpaque, StoreToken};
17use crate::try_mutex::{TryMutex, TryMutexGuard};
18use crate::vm::component::{ComponentInstance, HandleCounter, HandleTable, TransmitLocalState};
19use crate::vm::{AlwaysMut, VMStore};
20use crate::{AsContext, AsContextMut, StoreContextMut, ValRaw};
21use crate::{
22    Error, Result, Trap, bail, bail_bug, ensure,
23    error::{Context as _, format_err},
24};
25use alloc::sync::Arc;
26use buffers::{Extender, SliceBuffer, UntypedWriteBuffer};
27use core::any::{Any, TypeId};
28use core::fmt;
29use core::future;
30use core::iter;
31use core::marker::PhantomData;
32use core::mem::{self, ManuallyDrop, MaybeUninit};
33use core::ops::{Deref, DerefMut};
34use core::pin::Pin;
35use core::task::{Context, Poll, Waker, ready};
36use futures::channel::oneshot;
37use futures::{FutureExt as _, stream};
38use wasmtime_environ::component::{
39    CanonicalAbiInfo, ComponentTypes, InterfaceType, OptionsIndex, RuntimeComponentInstanceIndex,
40    TypeComponentGlobalErrorContextTableIndex, TypeComponentLocalErrorContextTableIndex,
41    TypeFutureTableIndex, TypeStreamTableIndex,
42};
43
44pub use buffers::{ReadBuffer, VecBuffer, WriteBuffer};
45
46mod buffers;
47
48/// Enum for distinguishing between a stream or future in functions that handle
49/// both.
50#[derive(Copy, Clone, Debug)]
51pub enum TransmitKind {
52    Stream,
53    Future,
54}
55
56/// Represents `{stream,future}.{read,write}` results.
57#[derive(Copy, Clone, Debug, PartialEq)]
58pub enum ReturnCode {
59    Blocked,
60    Completed(ItemCount),
61    Dropped(ItemCount),
62    Cancelled(ItemCount),
63}
64
65impl ReturnCode {
66    /// Pack `self` into a single 32-bit integer that may be returned to the
67    /// guest.
68    ///
69    /// This corresponds to `pack_copy_result` in the Component Model spec.
70    pub fn encode(&self) -> u32 {
71        const BLOCKED: u32 = 0xffff_ffff;
72        const COMPLETED: u32 = 0x0;
73        const DROPPED: u32 = 0x1;
74        const CANCELLED: u32 = 0x2;
75        match self {
76            ReturnCode::Blocked => BLOCKED,
77            ReturnCode::Completed(n) => (n.as_u32() << 4) | COMPLETED,
78            ReturnCode::Dropped(n) => (n.as_u32() << 4) | DROPPED,
79            ReturnCode::Cancelled(n) => (n.as_u32() << 4) | CANCELLED,
80        }
81    }
82
83    /// Returns `Self::Completed` with the specified count (or zero if
84    /// `matches!(kind, TransmitKind::Future)`)
85    fn completed(kind: TransmitKind, count: ItemCount) -> Self {
86        Self::Completed(if let TransmitKind::Future = kind {
87            ItemCount::ZERO
88        } else {
89            count
90        })
91    }
92}
93
94/// Representation of how many items are being operated on in a stream read or
95/// write.
96///
97/// The component model requires that stream operations are limited to `1<<28`
98/// items in one go. This type is a newtype wrapper around `u32` with the
99/// invariant that the internal value is limited by this amount.
100#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
101#[repr(transparent)]
102pub struct ItemCount {
103    raw: u32,
104}
105
106impl ItemCount {
107    const MAX: u32 = 1 << 28;
108    const ZERO: ItemCount = ItemCount { raw: 0 };
109
110    /// Creates a new `ItemCount` with the specified count, or a trap if it's
111    /// too large.
112    fn new(count: u32) -> Result<Self, Trap> {
113        if count < Self::MAX {
114            Ok(Self { raw: count })
115        } else {
116            Err(Trap::StreamOpTooBig)
117        }
118    }
119
120    /// Same as `Self::new` but takes a `usize`.
121    fn new_usize(count: usize) -> Result<Self, Trap> {
122        let count = u32::try_from(count).map_err(|_| Trap::StreamOpTooBig)?;
123        Self::new(count)
124    }
125
126    fn as_u32(&self) -> u32 {
127        self.raw
128    }
129
130    fn as_usize(&self) -> usize {
131        usize::try_from(self.raw).unwrap()
132    }
133
134    /// Increments `self` by `amt`, returning a trap if the amount would exceed
135    /// the maximum item count.
136    fn inc(&mut self, amt: usize) -> Result<(), Trap> {
137        let amt = u32::try_from(amt).map_err(|_| Trap::StreamOpTooBig)?;
138        let new_raw = self.raw.checked_add(amt).ok_or(Trap::StreamOpTooBig)?;
139        if new_raw < Self::MAX {
140            self.raw = new_raw;
141            Ok(())
142        } else {
143            Err(Trap::StreamOpTooBig)
144        }
145    }
146
147    /// Helper to add two `ItemCount`s together, fallibly.
148    ///
149    /// It's considered a bug if this overflows, so this is only suitable in
150    /// situations where overflow and/or exceeding the total item count is known
151    /// that it may be possible.
152    fn add(&self, other: ItemCount) -> Result<ItemCount> {
153        match self.raw.checked_add(other.raw) {
154            Some(raw) => Ok(ItemCount::new(raw)?),
155            None => bail_bug!("overflow in `ItemCount::add`"),
156        }
157    }
158
159    /// Same as `add`, but for subtraction.
160    ///
161    /// Like with `add` this is only suitable for situations where the result is
162    /// known to not underflow.
163    fn sub(&self, other: ItemCount) -> Result<ItemCount> {
164        match self.raw.checked_sub(other.raw) {
165            Some(raw) => Ok(ItemCount { raw }),
166            None => bail_bug!("underflow in `ItemCount::sub`"),
167        }
168    }
169}
170
171impl fmt::Display for ItemCount {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        self.raw.fmt(f)
174    }
175}
176
177impl fmt::Debug for ItemCount {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        self.raw.fmt(f)
180    }
181}
182
183impl PartialEq<u32> for ItemCount {
184    fn eq(&self, other: &u32) -> bool {
185        self.raw == *other
186    }
187}
188
189impl PartialOrd<u32> for ItemCount {
190    fn partial_cmp(&self, other: &u32) -> Option<core::cmp::Ordering> {
191        self.raw.partial_cmp(other)
192    }
193}
194
195/// Represents a stream or future type index.
196///
197/// This is useful as a parameter type for functions which operate on either a
198/// future or a stream.
199#[derive(Copy, Clone, Debug)]
200pub enum TransmitIndex {
201    Stream(TypeStreamTableIndex),
202    Future(TypeFutureTableIndex),
203}
204
205impl TransmitIndex {
206    pub fn kind(&self) -> TransmitKind {
207        match self {
208            TransmitIndex::Stream(_) => TransmitKind::Stream,
209            TransmitIndex::Future(_) => TransmitKind::Future,
210        }
211    }
212
213    /// Retrieve the payload type of the specified stream or future, or `None`
214    /// if it has no payload type.
215    fn payload<'a>(&self, types: &'a ComponentTypes) -> Option<&'a InterfaceType> {
216        match self {
217            TransmitIndex::Stream(i) => {
218                let ty = types[*i].ty;
219                types[ty].payload.as_ref()
220            }
221            TransmitIndex::Future(i) => {
222                let ty = types[*i].ty;
223                types[ty].payload.as_ref()
224            }
225        }
226    }
227}
228
229/// Retrieve the host rep and state for the specified guest-visible waitable
230/// handle.
231fn get_mut_by_index_from(
232    handle_table: &mut HandleTable,
233    ty: TransmitIndex,
234    index: u32,
235) -> Result<(u32, &mut TransmitLocalState)> {
236    match ty {
237        TransmitIndex::Stream(ty) => handle_table.stream_rep(ty, index),
238        TransmitIndex::Future(ty) => handle_table.future_rep(ty, index),
239    }
240}
241
242fn lower<T: func::Lower + Send + 'static, B: WriteBuffer<T>, U: 'static>(
243    mut store: StoreContextMut<U>,
244    instance: Instance,
245    caller_thread: QualifiedThreadId,
246    options: OptionsIndex,
247    ty: TransmitIndex,
248    address: usize,
249    count: usize,
250    buffer: &mut B,
251) -> Result<()> {
252    let count = buffer.remaining().len().min(count);
253
254    // If lowering may call realloc in the guest, then the guest may need
255    // to access its thread context, so we need to set the current thread before lowering
256    // and restore the old one afterward.
257    let (lower, old_thread) = if T::MAY_REQUIRE_REALLOC {
258        let old_thread = store.0.set_thread(caller_thread)?;
259        (
260            &mut LowerContext::new(store.as_context_mut(), options, instance),
261            Some(old_thread),
262        )
263    } else {
264        (
265            &mut LowerContext::new_without_realloc(store.as_context_mut(), options, instance),
266            None,
267        )
268    };
269
270    // Note that validation only happens with operations that have a payload.
271    if let Some(ty) = ty.payload(lower.types).copied() {
272        if address % usize::try_from(T::ALIGN32)? != 0 {
273            bail!("read pointer not aligned");
274        }
275        lower
276            .as_slice_mut()
277            .get_mut(address..)
278            .and_then(|b| b.get_mut(..T::SIZE32 * count))
279            .ok_or_else(|| crate::format_err!("read pointer out of bounds of memory"))?;
280
281        T::linear_store_list_to_memory(lower, ty, address, &buffer.remaining()[..count])?;
282    }
283
284    if let Some(old_thread) = old_thread {
285        store.0.set_thread(old_thread)?;
286    }
287
288    buffer.skip(count);
289
290    Ok(())
291}
292
293fn lift<T: func::Lift + Send + 'static, B: ReadBuffer<T>>(
294    lift: &mut LiftContext<'_>,
295    ty: Option<InterfaceType>,
296    buffer: &mut B,
297    address: usize,
298    count: usize,
299) -> Result<()> {
300    let count = count.min(buffer.remaining_capacity());
301    if T::IS_RUST_UNIT_TYPE {
302        // SAFETY: `T::IS_RUST_UNIT_TYPE` is only true for `()`, a
303        // zero-sized type, so `MaybeUninit::uninit().assume_init()`
304        // is a valid way to populate the zero-sized buffer.
305        buffer.extend(
306            iter::repeat_with(|| unsafe { MaybeUninit::uninit().assume_init() }).take(count),
307        )
308    } else {
309        let ty = match ty {
310            Some(ty) => ty,
311            None => bail_bug!("type required for non-unit lift"),
312        };
313        if address % usize::try_from(T::ALIGN32)? != 0 {
314            bail!("write pointer not aligned");
315        }
316        lift.memory()
317            .get(address..)
318            .and_then(|b| b.get(..T::SIZE32 * count))
319            .ok_or_else(|| crate::format_err!("write pointer out of bounds of memory"))?;
320
321        let list = &WasmList::new(address, count, lift, ty)?;
322        T::linear_lift_into_from_memory(lift, list, &mut Extender(buffer))?
323    }
324    Ok(())
325}
326
327/// Represents the state associated with an error context
328#[derive(Debug, PartialEq, Eq, PartialOrd)]
329pub(super) struct ErrorContextState {
330    /// Debug message associated with the error context
331    pub(crate) debug_msg: String,
332}
333
334/// Represents the size and alignment for a "flat" Component Model type,
335/// i.e. one containing no pointers or handles.
336#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337pub(super) struct FlatAbi {
338    pub(super) size: u32,
339    pub(super) align: u32,
340}
341
342struct HostBuffer<'a> {
343    dst: &'a mut Vec<u8>,
344    marked_written: &'a mut usize,
345}
346
347impl HostBuffer<'_> {
348    fn reborrow(&mut self) -> HostBuffer<'_> {
349        HostBuffer {
350            dst: &mut *self.dst,
351            marked_written: &mut *self.marked_written,
352        }
353    }
354}
355
356/// Represents the buffer for a host- or guest-initiated stream read.
357pub struct Destination<'a, T, B> {
358    id: TableId<TransmitState>,
359    buffer: &'a mut B,
360    host_buffer: Option<HostBuffer<'a>>,
361    _phantom: PhantomData<fn() -> T>,
362}
363
364impl<'a, T, B> Destination<'a, T, B> {
365    /// Reborrow `self` so it can be used again later.
366    pub fn reborrow(&mut self) -> Destination<'_, T, B> {
367        Destination {
368            id: self.id,
369            buffer: &mut *self.buffer,
370            host_buffer: self.host_buffer.as_mut().map(|b| b.reborrow()),
371            _phantom: PhantomData,
372        }
373    }
374
375    /// Take the buffer out of `self`, leaving a default-initialized one in its
376    /// place.
377    ///
378    /// This can be useful for reusing the previously-stored buffer's capacity
379    /// instead of allocating a fresh one.
380    pub fn take_buffer(&mut self) -> B
381    where
382        B: Default,
383    {
384        mem::take(self.buffer)
385    }
386
387    /// Store the specified buffer in `self`.
388    ///
389    /// Any items contained in the buffer will be delivered to the reader after
390    /// the `StreamProducer::poll_produce` call to which this `Destination` was
391    /// passed returns (unless overwritten by another call to `set_buffer`).
392    ///
393    /// If items are stored via this buffer _and_ written via a
394    /// `DirectDestination` view of `self`, then the items in the buffer will be
395    /// delivered after the ones written using `DirectDestination`.
396    pub fn set_buffer(&mut self, buffer: B) {
397        *self.buffer = buffer;
398    }
399
400    /// Return the remaining number of items the current read has capacity to
401    /// accept, if known.
402    ///
403    /// This will return `Some(_)` if the reader is a guest; it will return
404    /// `None` if the reader is the host.
405    ///
406    /// Note that this can return `Some(0)`. This means that the guest is
407    /// attempting to perform a zero-length read which typically means that it's
408    /// trying to wait for this stream to be ready-to-read but is not actually
409    /// ready to receive the items yet. The host in this case is allowed to
410    /// either block waiting for readiness or immediately complete the
411    /// operation. The guest is expected to handle both cases. Some more
412    /// discussion about this case can be found in the discussion of ["Stream
413    /// Readiness" in the component-model repo][docs].
414    ///
415    /// [docs]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Concurrency.md#stream-readiness
416    pub fn remaining(&self, mut store: impl AsContextMut) -> Result<Option<usize>> {
417        self.remaining_(store.as_context_mut().0)
418    }
419
420    fn remaining_(&self, store: &mut StoreOpaque) -> Result<Option<usize>> {
421        let transmit = store.concurrent_state_mut()?.get_mut(self.id)?;
422
423        if let &ReadState::GuestReady { count, .. } = &transmit.read {
424            let &WriteState::HostReady { guest_offset, .. } = &transmit.write else {
425                bail_bug!("expected WriteState::HostReady")
426            };
427
428            Ok(Some(count.as_usize() - guest_offset.as_usize()))
429        } else {
430            Ok(None)
431        }
432    }
433}
434
435impl<'a, B> Destination<'a, u8, B> {
436    /// Return a `DirectDestination` view of `self`.
437    ///
438    /// If the reader is a guest, this will provide direct access to the guest's
439    /// read buffer.  If the reader is a host, this will provide access to a
440    /// buffer which will be delivered to the host before any items stored using
441    /// `Destination::set_buffer`.
442    ///
443    /// `capacity` will only be used if the reader is a host, in which case it
444    /// will update the length of the buffer, possibly zero-initializing the new
445    /// elements if the new length is larger than the old length.
446    pub fn as_direct<D>(
447        mut self,
448        store: StoreContextMut<'a, D>,
449        capacity: usize,
450    ) -> DirectDestination<'a, D> {
451        if let Some(buffer) = &mut self.host_buffer {
452            *buffer.marked_written = 0;
453            buffer.dst.resize(capacity, 0);
454        }
455
456        DirectDestination {
457            id: self.id,
458            host_buffer: self.host_buffer,
459            store,
460        }
461    }
462}
463
464/// Represents a read from a `stream<u8>`, providing direct access to the
465/// writer's buffer.
466pub struct DirectDestination<'a, D: 'static> {
467    id: TableId<TransmitState>,
468    host_buffer: Option<HostBuffer<'a>>,
469    store: StoreContextMut<'a, D>,
470}
471
472#[cfg(feature = "std")]
473impl<D: 'static> std::io::Write for DirectDestination<'_, D> {
474    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
475        let rem = self.remaining().map_err(std::io::Error::other)?;
476        let n = rem.len().min(buf.len());
477        rem[..n].copy_from_slice(&buf[..n]);
478        self.mark_written(n);
479        Ok(n)
480    }
481
482    fn flush(&mut self) -> std::io::Result<()> {
483        Ok(())
484    }
485}
486
487impl<D: 'static> DirectDestination<'_, D> {
488    /// Provide direct access to the writer's buffer.
489    pub fn remaining(&mut self) -> Result<&mut [u8]> {
490        if let Some(buffer) = self.host_buffer.as_mut() {
491            return Ok(buffer.dst);
492        }
493        let transmit = self
494            .store
495            .as_context_mut()
496            .0
497            .concurrent_state_mut()?
498            .get_mut(self.id)?;
499
500        let &ReadState::GuestReady {
501            address,
502            count,
503            options,
504            instance,
505            ..
506        } = &transmit.read
507        else {
508            bail_bug!("expected ReadState::GuestReady")
509        };
510
511        let &WriteState::HostReady { guest_offset, .. } = &transmit.write else {
512            bail_bug!("expected WriteState::HostReady")
513        };
514
515        let memory = instance
516            .options_memory_mut(self.store.0, options)
517            .get_mut(
518                if count == 0 {
519                    0
520                } else {
521                    address + guest_offset.as_usize()
522                }..,
523            )
524            .and_then(|b| b.get_mut(..(count.as_usize() - guest_offset.as_usize())));
525        match memory {
526            Some(memory) => Ok(memory),
527            None => bail_bug!("guest buffer unexpectedly out of bounds"),
528        }
529    }
530
531    /// Mark the specified number of bytes as written to the writer's buffer.
532    ///
533    /// # Panics
534    ///
535    /// This will panic if the count is larger than the size of the
536    /// buffer returned by `Self::remaining`.
537    pub fn mark_written(&mut self, count: usize) {
538        // Note that this unwrap should only trigger for bugs in Wasmtime, and
539        // this is modeled here to centralize the `.unwrap()` for this method in
540        // one location.
541        self.mark_written_(count).unwrap()
542    }
543
544    fn mark_written_(&mut self, count: usize) -> Result<()> {
545        if let Some(buffer) = self.host_buffer.as_mut() {
546            // Note that this `.unwrap` is a documented panic condition of
547            // `mark_written`.
548            *buffer.marked_written = buffer.marked_written.checked_add(count).unwrap();
549        } else {
550            let transmit = self
551                .store
552                .as_context_mut()
553                .0
554                .concurrent_state_mut()?
555                .get_mut(self.id)?;
556
557            let ReadState::GuestReady {
558                count: read_count, ..
559            } = &transmit.read
560            else {
561                bail_bug!("expected ReadState::GuestReady")
562            };
563
564            let WriteState::HostReady { guest_offset, .. } = &mut transmit.write else {
565                bail_bug!("expected WriteState::HostReady");
566            };
567
568            if guest_offset.as_usize() + count > read_count.as_usize() {
569                // Note that this `panic` is a documented panic condition of
570                // `mark_written`.
571                panic!(
572                    "write count ({count}) must be less than or equal to read count ({read_count})"
573                )
574            } else {
575                guest_offset.inc(count)?;
576            }
577        }
578        Ok(())
579    }
580}
581
582/// Represents the state of a `Stream{Producer,Consumer}`.
583#[derive(Copy, Clone, Debug)]
584pub enum StreamResult {
585    /// The operation completed normally, and the producer or consumer may be
586    /// able to produce or consume more items, respectively.
587    Completed,
588    /// The operation was interrupted (i.e. it wrapped up early after receiving
589    /// a `finish` parameter value of true in a call to `poll_produce` or
590    /// `poll_consume`), and the producer or consumer may be able to produce or
591    /// consume more items, respectively.
592    Cancelled,
593    /// The operation completed normally, but the producer or consumer will
594    /// _not_ able to produce or consume more items, respectively.
595    Dropped,
596}
597
598/// Represents the host-owned write end of a stream.
599pub trait StreamProducer<D>: Send + 'static {
600    /// The payload type of this stream.
601    type Item;
602
603    /// The `WriteBuffer` type to use when delivering items.
604    type Buffer: WriteBuffer<Self::Item> + Default;
605
606    /// Handle a host- or guest-initiated read by delivering zero or more items
607    /// to the specified destination.
608    ///
609    /// This will be called whenever the reader starts a read.
610    ///
611    /// # Arguments
612    ///
613    /// * `self` - a `Pin`'d version of self to perform Rust-level
614    ///   future-related operations on.
615    /// * `cx` - a Rust-related [`Context`] which is passed to other
616    ///   future-related operations or used to acquire a waker.
617    /// * `store` - the Wasmtime store that this operation is happening within.
618    ///   Used, for example, to consult the state `D` associated with the store.
619    /// * `destination` - the location that items are to be written to.
620    /// * `finish` - a flag indicating whether the host should strive to
621    ///   immediately complete/cancel any pending operation. See below for more
622    ///   details.
623    ///
624    /// # Behavior
625    ///
626    /// If the implementation is able to produce one or more items immediately,
627    /// it should write them to `destination` and return either
628    /// `Poll::Ready(Ok(StreamResult::Completed))` if it expects to produce more
629    /// items, or `Poll::Ready(Ok(StreamResult::Dropped))` if it cannot produce
630    /// any more items.
631    ///
632    /// If the implementation is unable to produce any items immediately, but
633    /// expects to do so later, and `finish` is _false_, it should store the
634    /// waker from `cx` for later and return `Poll::Pending` without writing
635    /// anything to `destination`.  Later, it should alert the waker when either
636    /// the items arrive, the stream has ended, or an error occurs.
637    ///
638    /// If more items are written to `destination` than the reader has immediate
639    /// capacity to accept, they will be retained in memory by the caller and
640    /// used to satisfy future reads, in which case `poll_produce` will only be
641    /// called again once all those items have been delivered.
642    ///
643    /// # Zero-length reads
644    ///
645    /// This function may be called with a zero-length capacity buffer
646    /// (i.e. `Destination::remaining` returns `Some(0)`). This indicates that
647    /// the guest wants to wait to see if an item is ready without actually
648    /// reading the item. For example think of a UNIX `poll` function run on a
649    /// TCP stream, seeing if it's readable without actually reading it.
650    ///
651    /// In this situation the host is allowed to either return immediately or
652    /// wait for readiness. Note that waiting for readiness is not always
653    /// possible. For example it's impossible to test if a Rust-native `Future`
654    /// is ready without actually reading the item. Stream-specific
655    /// optimizations, such as testing if a TCP stream is readable, may be
656    /// possible however.
657    ///
658    /// For a zero-length read, the host is allowed to:
659    ///
660    /// - Return `Poll::Ready(Ok(StreamResult::Completed))` without writing
661    ///   anything if it expects to be able to produce items immediately (i.e.
662    ///   without first returning `Poll::Pending`) the next time `poll_produce`
663    ///   is called with non-zero capacity. This is the best-case scenario of
664    ///   fulfilling the guest's desire -- items aren't read/buffered but the
665    ///   host is saying it's ready when the guest is.
666    ///
667    /// - Return `Poll::Ready(Ok(StreamResult::Completed))` without actually
668    ///   testing for readiness. The guest doesn't know this yet, but the guest
669    ///   will realize that zero-length reads won't work on this stream when a
670    ///   subsequent nonzero read attempt is made which returns `Poll::Pending`
671    ///   here.
672    ///
673    /// - Return `Poll::Pending` if the host has performed necessary async work
674    ///   to wait for this stream to be readable without actually reading
675    ///   anything. This is also a best-case scenario where the host is letting
676    ///   the guest know that nothing is ready yet. Later the zero-length read
677    ///   will complete and then the guest will attempt a nonzero-length read to
678    ///   actually read some bytes.
679    ///
680    /// - Return `Poll::Ready(Ok(StreamResult::Completed))` after calling
681    ///   `Destination::set_buffer` with one more more items. Note, however,
682    ///   that this creates the hazard that the items will never be received by
683    ///   the guest if it decides not to do another non-zero-length read before
684    ///   closing the stream.  Moreover, if `Self::Item` is e.g. a
685    ///   `Resource<_>`, they may end up leaking in that scenario. It is not
686    ///   recommended to do this and it's better to return
687    ///   `StreamResult::Completed` without buffering anything instead.
688    ///
689    /// For more discussion on zero-length reads see the [documentation in the
690    /// component-model repo itself][docs].
691    ///
692    /// [docs]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Concurrency.md#stream-readiness
693    ///
694    /// # Return
695    ///
696    /// This function can return a number of possible cases from this function:
697    ///
698    /// * `Poll::Pending` - this operation cannot complete at this time. The
699    ///   Rust-level `Future::poll` contract applies here where a waker should
700    ///   be stored from the `cx` argument and be arranged to receive a
701    ///   notification when this implementation can make progress. For example
702    ///   if you call `Future::poll` on a sub-future, that's enough. If items
703    ///   were written to `destination` then a trap in the guest will be raised.
704    ///
705    ///   Note that implementations should strive to avoid this return value
706    ///   when `finish` is `true`. In such a situation the guest is attempting
707    ///   to, for example, cancel a previous operation. By returning
708    ///   `Poll::Pending` the guest will be blocked during the cancellation
709    ///   request. If `finish` is `true` then `StreamResult::Cancelled` is
710    ///   favored to indicate that no items were read. If a short read happened,
711    ///   however, it's ok to return `StreamResult::Completed` indicating some
712    ///   items were read.
713    ///
714    /// * `Poll::Ok(StreamResult::Completed)` - items, if applicable, were
715    ///   written to the `destination`. Only zero-length reads (see above) may
716    ///   complete without writing anything; if nothing was written for a
717    ///   nonzero-length read, or for any read by the host, then a trap in the
718    ///   guest will be raised.
719    ///
720    /// * `Poll::Ok(StreamResult::Cancelled)` - used when `finish` is `true` and
721    ///   the implementation was able to successfully cancel any async work that
722    ///   a previous read kicked off, if any. The host should not buffer values
723    ///   received after returning `Cancelled` because the guest will not be
724    ///   aware of these values and the guest could close the stream after
725    ///   cancelling a read. Hosts should only return `Cancelled` when there are
726    ///   no more async operations in flight for a previous read.
727    ///
728    ///   If items were written to `destination` then a trap in the guest will
729    ///   be raised. If `finish` is `false` then this return value will raise a
730    ///   trap in the guest.
731    ///
732    /// * `Poll::Ok(StreamResult::Dropped)` - end-of-stream marker, indicating
733    ///   that this producer should not be polled again. Note that items may
734    ///   still be written to `destination`.
735    ///
736    /// # Errors
737    ///
738    /// The implementation may alternatively choose to return `Err(_)` to
739    /// indicate an unrecoverable error. This will cause the guest (if any) to
740    /// trap and render the component instance (if any) unusable. The
741    /// implementation should report errors that _are_ recoverable by other
742    /// means (e.g. by writing to a `future`) and return
743    /// `Poll::Ready(Ok(StreamResult::Dropped))`.
744    fn poll_produce<'a>(
745        self: Pin<&mut Self>,
746        cx: &mut Context<'_>,
747        store: StoreContextMut<'a, D>,
748        destination: Destination<'a, Self::Item, Self::Buffer>,
749        finish: bool,
750    ) -> Poll<Result<StreamResult>>;
751
752    /// Attempt to convert the specified object into a `Box<dyn Any>` which may
753    /// be downcast to the specified type.
754    ///
755    /// The implementation must ensure that, if it returns `Ok(_)`, a downcast
756    /// to the specified type is guaranteed to succeed.
757    fn try_into(me: Pin<Box<Self>>, _ty: TypeId) -> Result<Box<dyn Any>, Pin<Box<Self>>> {
758        Err(me)
759    }
760}
761
762impl<T, D> StreamProducer<D> for iter::Empty<T>
763where
764    T: Send + Sync + 'static,
765{
766    type Item = T;
767    type Buffer = Option<Self::Item>;
768
769    fn poll_produce<'a>(
770        self: Pin<&mut Self>,
771        _: &mut Context<'_>,
772        _: StoreContextMut<'a, D>,
773        _: Destination<'a, Self::Item, Self::Buffer>,
774        _: bool,
775    ) -> Poll<Result<StreamResult>> {
776        Poll::Ready(Ok(StreamResult::Dropped))
777    }
778}
779
780impl<T, D> StreamProducer<D> for stream::Empty<T>
781where
782    T: Send + Sync + 'static,
783{
784    type Item = T;
785    type Buffer = Option<Self::Item>;
786
787    fn poll_produce<'a>(
788        self: Pin<&mut Self>,
789        _: &mut Context<'_>,
790        _: StoreContextMut<'a, D>,
791        _: Destination<'a, Self::Item, Self::Buffer>,
792        _: bool,
793    ) -> Poll<Result<StreamResult>> {
794        Poll::Ready(Ok(StreamResult::Dropped))
795    }
796}
797
798impl<T, D> StreamProducer<D> for Vec<T>
799where
800    T: Unpin + Send + Sync + 'static,
801{
802    type Item = T;
803    type Buffer = VecBuffer<T>;
804
805    fn poll_produce<'a>(
806        self: Pin<&mut Self>,
807        _: &mut Context<'_>,
808        _: StoreContextMut<'a, D>,
809        mut dst: Destination<'a, Self::Item, Self::Buffer>,
810        _: bool,
811    ) -> Poll<Result<StreamResult>> {
812        dst.set_buffer(mem::take(self.get_mut()).into());
813        Poll::Ready(Ok(StreamResult::Dropped))
814    }
815}
816
817impl<T, D> StreamProducer<D> for Box<[T]>
818where
819    T: Unpin + Send + Sync + 'static,
820{
821    type Item = T;
822    type Buffer = VecBuffer<T>;
823
824    fn poll_produce<'a>(
825        self: Pin<&mut Self>,
826        _: &mut Context<'_>,
827        _: StoreContextMut<'a, D>,
828        mut dst: Destination<'a, Self::Item, Self::Buffer>,
829        _: bool,
830    ) -> Poll<Result<StreamResult>> {
831        dst.set_buffer(mem::take(self.get_mut()).into_vec().into());
832        Poll::Ready(Ok(StreamResult::Dropped))
833    }
834}
835
836#[cfg(feature = "component-model-bytes")]
837impl<D> StreamProducer<D> for bytes::Bytes {
838    type Item = u8;
839    type Buffer = Self;
840
841    fn poll_produce<'a>(
842        self: Pin<&mut Self>,
843        _: &mut Context<'_>,
844        _store: StoreContextMut<'a, D>,
845        mut dst: Destination<'a, Self::Item, Self::Buffer>,
846        _: bool,
847    ) -> Poll<Result<StreamResult>> {
848        dst.set_buffer(mem::take(self.get_mut()));
849        Poll::Ready(Ok(StreamResult::Dropped))
850    }
851}
852
853#[cfg(feature = "component-model-bytes")]
854impl<D> StreamProducer<D> for bytes::BytesMut {
855    type Item = u8;
856    type Buffer = Self;
857
858    fn poll_produce<'a>(
859        self: Pin<&mut Self>,
860        _: &mut Context<'_>,
861        _store: StoreContextMut<'a, D>,
862        mut dst: Destination<'a, Self::Item, Self::Buffer>,
863        _: bool,
864    ) -> Poll<Result<StreamResult>> {
865        dst.set_buffer(mem::take(self.get_mut()));
866        Poll::Ready(Ok(StreamResult::Dropped))
867    }
868}
869
870/// Represents the buffer for a host- or guest-initiated stream write.
871pub struct Source<'a, T> {
872    id: TableId<TransmitState>,
873    host_buffer: Option<&'a mut dyn WriteBuffer<T>>,
874}
875
876impl<'a, T> Source<'a, T> {
877    /// Reborrow `self` so it can be used again later.
878    pub fn reborrow(&mut self) -> Source<'_, T> {
879        Source {
880            id: self.id,
881            host_buffer: self.host_buffer.as_deref_mut(),
882        }
883    }
884
885    /// Accept zero or more items from the writer.
886    pub fn read<B, S: AsContextMut>(&mut self, mut store: S, buffer: &mut B) -> Result<()>
887    where
888        T: func::Lift + 'static,
889        B: ReadBuffer<T>,
890    {
891        if let Some(input) = &mut self.host_buffer {
892            let count = input.remaining().len().min(buffer.remaining_capacity());
893            buffer.move_from(*input, count);
894        } else {
895            let store = store.as_context_mut();
896            let transmit = store.0.concurrent_state_mut()?.get_mut(self.id)?;
897
898            let &ReadState::HostReady { guest_offset, .. } = &transmit.read else {
899                bail_bug!("expected ReadState::HostReady");
900            };
901
902            let &WriteState::GuestReady {
903                ty,
904                address,
905                count,
906                options,
907                instance,
908                ..
909            } = &transmit.write
910            else {
911                bail_bug!("expected WriteState::GuestReady");
912            };
913
914            let cx = &mut LiftContext::new(store.0.store_opaque_mut(), options, instance)?;
915            let ty = ty.payload(cx.types);
916            let old_remaining = buffer.remaining_capacity();
917            lift::<T, B>(
918                cx,
919                ty.copied(),
920                buffer,
921                address + (T::SIZE32 * guest_offset.as_usize()),
922                count.as_usize() - guest_offset.as_usize(),
923            )?;
924
925            let transmit = store.0.concurrent_state_mut()?.get_mut(self.id)?;
926
927            let ReadState::HostReady { guest_offset, .. } = &mut transmit.read else {
928                bail_bug!("expected ReadState::HostReady");
929            };
930
931            guest_offset.inc(old_remaining - buffer.remaining_capacity())?;
932        }
933
934        Ok(())
935    }
936
937    /// Return the number of items remaining to be read from the current write
938    /// operation.
939    pub fn remaining(&self, mut store: impl AsContextMut) -> Result<usize>
940    where
941        T: 'static,
942    {
943        self.remaining_(store.as_context_mut().0)
944    }
945
946    fn remaining_(&self, store: &mut StoreOpaque) -> Result<usize>
947    where
948        T: 'static,
949    {
950        let transmit = store.concurrent_state_mut()?.get_mut(self.id)?;
951
952        if let &WriteState::GuestReady { count, .. } = &transmit.write {
953            let &ReadState::HostReady { guest_offset, .. } = &transmit.read else {
954                bail_bug!("expected ReadState::HostReady")
955            };
956
957            Ok(count.as_usize() - guest_offset.as_usize())
958        } else if let Some(host_buffer) = &self.host_buffer {
959            Ok(host_buffer.remaining().len())
960        } else {
961            bail_bug!("expected either WriteState::GuestReady or host buffer")
962        }
963    }
964}
965
966impl<'a> Source<'a, u8> {
967    /// Return a `DirectSource` view of `self`.
968    pub fn as_direct<D>(self, store: StoreContextMut<'a, D>) -> DirectSource<'a, D> {
969        DirectSource {
970            id: self.id,
971            host_buffer: self.host_buffer,
972            store,
973        }
974    }
975}
976
977/// Represents a write to a `stream<u8>`, providing direct access to the
978/// writer's buffer.
979pub struct DirectSource<'a, D: 'static> {
980    id: TableId<TransmitState>,
981    host_buffer: Option<&'a mut dyn WriteBuffer<u8>>,
982    store: StoreContextMut<'a, D>,
983}
984
985#[cfg(feature = "std")]
986impl<D: 'static> std::io::Read for DirectSource<'_, D> {
987    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
988        let rem = self.remaining().map_err(std::io::Error::other)?;
989        let n = rem.len().min(buf.len());
990        buf[..n].copy_from_slice(&rem[..n]);
991        self.mark_read(n);
992        Ok(n)
993    }
994}
995
996impl<D: 'static> DirectSource<'_, D> {
997    /// Provide direct access to the writer's buffer.
998    pub fn remaining(&mut self) -> Result<&[u8]> {
999        if let Some(buffer) = self.host_buffer.as_deref_mut() {
1000            return Ok(buffer.remaining());
1001        }
1002        let transmit = self
1003            .store
1004            .as_context_mut()
1005            .0
1006            .concurrent_state_mut()?
1007            .get_mut(self.id)?;
1008
1009        let &WriteState::GuestReady {
1010            address,
1011            count,
1012            options,
1013            instance,
1014            ..
1015        } = &transmit.write
1016        else {
1017            bail_bug!("expected WriteState::GuestReady")
1018        };
1019
1020        let &ReadState::HostReady { guest_offset, .. } = &transmit.read else {
1021            bail_bug!("expected ReadState::HostReady")
1022        };
1023
1024        let memory = instance
1025            .options_memory(self.store.0, options)
1026            .get(
1027                if count == 0 {
1028                    0
1029                } else {
1030                    address + guest_offset.as_usize()
1031                }..,
1032            )
1033            .and_then(|b| b.get(..(count.as_usize() - guest_offset.as_usize())));
1034        match memory {
1035            Some(memory) => Ok(memory),
1036            None => bail_bug!("guest buffer unexpectedly out of bounds"),
1037        }
1038    }
1039
1040    /// Mark the specified number of bytes as read from the writer's buffer.
1041    ///
1042    /// # Panics
1043    ///
1044    /// This will panic if the count is larger than the size of the buffer
1045    /// returned by `Self::remaining`.
1046    pub fn mark_read(&mut self, count: usize) {
1047        // Note that this unwrap should only trigger for bugs in Wasmtime, and
1048        // this is modeled here to centralize the `.unwrap()` for this method in
1049        // one location.
1050        self.mark_read_(count).unwrap()
1051    }
1052
1053    fn mark_read_(&mut self, count: usize) -> Result<()> {
1054        if let Some(buffer) = self.host_buffer.as_deref_mut() {
1055            buffer.skip(count);
1056            return Ok(());
1057        }
1058
1059        let transmit = self
1060            .store
1061            .as_context_mut()
1062            .0
1063            .concurrent_state_mut()?
1064            .get_mut(self.id)?;
1065
1066        let WriteState::GuestReady {
1067            count: write_count, ..
1068        } = &transmit.write
1069        else {
1070            bail_bug!("expected WriteState::GuestReady");
1071        };
1072
1073        let ReadState::HostReady { guest_offset, .. } = &mut transmit.read else {
1074            bail_bug!("expected ReadState::HostReady");
1075        };
1076
1077        if guest_offset.as_usize() + count > write_count.as_usize() {
1078            // Note that this is a documented panic condition of `mark_read`.
1079            panic!("read count ({count}) must be less than or equal to write count ({write_count})")
1080        } else {
1081            guest_offset.inc(count)?;
1082        }
1083        Ok(())
1084    }
1085}
1086
1087/// Represents the host-owned read end of a stream.
1088pub trait StreamConsumer<D>: Send + 'static {
1089    /// The payload type of this stream.
1090    type Item;
1091
1092    /// Handle a host- or guest-initiated write by accepting zero or more items
1093    /// from the specified source.
1094    ///
1095    /// This will be called whenever the writer starts a write.
1096    ///
1097    /// If the implementation is able to consume one or more items immediately,
1098    /// it should take them from `source` and return either
1099    /// `Poll::Ready(Ok(StreamResult::Completed))` if it expects to be able to consume
1100    /// more items, or `Poll::Ready(Ok(StreamResult::Dropped))` if it cannot
1101    /// accept any more items.  Alternatively, it may return `Poll::Pending` to
1102    /// indicate that the caller should delay sending a `COMPLETED` event to the
1103    /// writer until a later call to this function returns `Poll::Ready(_)`.
1104    /// For more about that, see the `Backpressure` section below.
1105    ///
1106    /// If the implementation cannot consume any items immediately and `finish`
1107    /// is _false_, it should store the waker from `cx` for later and return
1108    /// `Poll::Pending` without writing anything to `destination`.  Later, it
1109    /// should alert the waker when either (1) the items arrive, (2) the stream
1110    /// has ended, or (3) an error occurs.
1111    ///
1112    /// If the implementation cannot consume any items immediately and `finish`
1113    /// is _true_, it should, if possible, return
1114    /// `Poll::Ready(Ok(StreamResult::Cancelled))` immediately without taking
1115    /// anything from `source`.  However, that might not be possible if an
1116    /// earlier call to `poll_consume` kicked off an asynchronous operation
1117    /// which needs to be completed (and possibly interrupted) gracefully, in
1118    /// which case the implementation may return `Poll::Pending` and later alert
1119    /// the waker as described above.  In other words, when `finish` is true,
1120    /// the implementation should prioritize returning a result to the reader
1121    /// (even if no items can be consumed) rather than wait indefinitely for at
1122    /// capacity to free up.
1123    ///
1124    /// In all of the above cases, the implementation may alternatively choose
1125    /// to return `Err(_)` to indicate an unrecoverable error.  This will cause
1126    /// the guest (if any) to trap and render the component instance (if any)
1127    /// unusable.  The implementation should report errors that _are_
1128    /// recoverable by other means (e.g. by writing to a `future`) and return
1129    /// `Poll::Ready(Ok(StreamResult::Dropped))`.
1130    ///
1131    /// Note that the implementation should only return
1132    /// `Poll::Ready(Ok(StreamResult::Cancelled))` without having taken any
1133    /// items from `source` if called with `finish` set to true.  If it does so
1134    /// when `finish` is false, the caller will trap.  Additionally, it should
1135    /// only return `Poll::Ready(Ok(StreamResult::Completed))` after taking at
1136    /// least one item from `source` if there is an item available; otherwise,
1137    /// the caller will trap.  Items taken during earlier calls for the same
1138    /// write which returned `Poll::Pending` count towards this, so it's fine
1139    /// to return `Completed` without taking more items once those have been
1140    /// forwarded (see "Backpressure" below).  If `poll_consume` is called with
1141    /// no items in
1142    /// `source`, it should only return `Poll::Ready(_)` once it is able to
1143    /// accept at least one item during the next call to `poll_consume`.
1144    ///
1145    /// Note that any items which the implementation of this trait takes from
1146    /// `source` become the responsibility of that implementation.  For that
1147    /// reason, an implementation which forwards items to an upstream sink
1148    /// should reserve capacity in that sink before taking items out of
1149    /// `source`, if possible.  Alternatively, it might buffer items which can't
1150    /// be forwarded immediately and send them once capacity is freed up.
1151    ///
1152    /// ## Backpressure
1153    ///
1154    /// As mentioned above, an implementation might choose to return
1155    /// `Poll::Pending` after taking items from `source`, which tells the caller
1156    /// to delay sending a `COMPLETED` event to the writer.  This can be used as
1157    /// a form of backpressure when the items are forwarded to an upstream sink
1158    /// asynchronously.  Note, however, that it's not possible to "put back"
1159    /// items into `source` once they've been taken out, so if the upstream sink
1160    /// is unable to accept all the items, that cannot be communicated to the
1161    /// writer at this level of abstraction.  Just as with application-specific,
1162    /// recoverable errors, information about which items could be forwarded and
1163    /// which could not must be communicated out-of-band, e.g. by writing to an
1164    /// application-specific `future`.
1165    ///
1166    /// Similarly, if the writer cancels the write after items have been taken
1167    /// from `source` but before the items have all been forwarded to an
1168    /// upstream sink, `poll_consume` will be called with `finish` set to true,
1169    /// and the implementation may either:
1170    ///
1171    /// - Interrupt the forwarding process gracefully.  This may be preferable
1172    /// if there is an out-of-band channel for communicating to the writer how
1173    /// many items were forwarded before being interrupted.
1174    ///
1175    /// - Allow the forwarding to complete without interrupting it.  This is
1176    /// usually preferable if there's no out-of-band channel for reporting back
1177    /// to the writer how many items were forwarded.
1178    fn poll_consume(
1179        self: Pin<&mut Self>,
1180        cx: &mut Context<'_>,
1181        store: StoreContextMut<D>,
1182        source: Source<'_, Self::Item>,
1183        finish: bool,
1184    ) -> Poll<Result<StreamResult>>;
1185}
1186
1187/// Represents a host-owned write end of a future.
1188pub trait FutureProducer<D>: Send + 'static {
1189    /// The payload type of this future.
1190    type Item;
1191
1192    /// Handle a host- or guest-initiated read by producing a value.
1193    ///
1194    /// This is equivalent to `StreamProducer::poll_produce`, but with a
1195    /// simplified interface for futures.
1196    ///
1197    /// If `finish` is true, the implementation may return
1198    /// `Poll::Ready(Ok(None))` to indicate the operation was canceled before it
1199    /// could produce a value.  Otherwise, it must either return
1200    /// `Poll::Ready(Ok(Some(_)))`, `Poll::Ready(Err(_))`, or `Poll::Pending`.
1201    fn poll_produce(
1202        self: Pin<&mut Self>,
1203        cx: &mut Context<'_>,
1204        store: StoreContextMut<D>,
1205        finish: bool,
1206    ) -> Poll<Result<Option<Self::Item>>>;
1207}
1208
1209impl<T, E, D, Fut> FutureProducer<D> for Fut
1210where
1211    E: Into<Error>,
1212    Fut: Future<Output = Result<T, E>> + ?Sized + Send + 'static,
1213{
1214    type Item = T;
1215
1216    fn poll_produce<'a>(
1217        self: Pin<&mut Self>,
1218        cx: &mut Context<'_>,
1219        _: StoreContextMut<'a, D>,
1220        finish: bool,
1221    ) -> Poll<Result<Option<T>>> {
1222        match self.poll(cx) {
1223            Poll::Ready(Ok(v)) => Poll::Ready(Ok(Some(v))),
1224            Poll::Ready(Err(err)) => Poll::Ready(Err(err.into())),
1225            Poll::Pending if finish => Poll::Ready(Ok(None)),
1226            Poll::Pending => Poll::Pending,
1227        }
1228    }
1229}
1230
1231/// Represents a host-owned read end of a future.
1232pub trait FutureConsumer<D>: Send + 'static {
1233    /// The payload type of this future.
1234    type Item;
1235
1236    /// Handle a host- or guest-initiated write by consuming a value.
1237    ///
1238    /// This is equivalent to `StreamProducer::poll_produce`, but with a
1239    /// simplified interface for futures.
1240    ///
1241    /// If `finish` is true, the implementation may return `Poll::Ready(Ok(()))`
1242    /// without taking the item from `source`, which indicates the operation was
1243    /// canceled before it could consume the value.  Otherwise, it must either
1244    /// take the item from `source` and return `Poll::Ready(Ok(()))`, or else
1245    /// return `Poll::Ready(Err(_))` or `Poll::Pending` (with or without taking
1246    /// the item).
1247    fn poll_consume(
1248        self: Pin<&mut Self>,
1249        cx: &mut Context<'_>,
1250        store: StoreContextMut<D>,
1251        source: Source<'_, Self::Item>,
1252        finish: bool,
1253    ) -> Poll<Result<()>>;
1254}
1255
1256/// Represents the readable end of a Component Model `future`.
1257///
1258/// Note that `FutureReader` instances must be disposed of using either `pipe`
1259/// or `close`; otherwise the in-store representation will leak and the writer
1260/// end will hang indefinitely.  Consider using [`GuardedFutureReader`] to
1261/// ensure that disposal happens automatically.
1262pub struct FutureReader<T> {
1263    idx: HostResourceIndex,
1264    _phantom: PhantomData<T>,
1265}
1266
1267impl<T> FutureReader<T> {
1268    /// Create a new future with the specified producer.
1269    ///
1270    /// # Errors
1271    ///
1272    /// Returns an error if the resource table for this store is full or if
1273    /// [`Config::concurrency_support`] is not enabled.
1274    ///
1275    /// [`Config::concurrency_support`]: crate::Config::concurrency_support
1276    pub fn new<S: AsContextMut>(
1277        mut store: S,
1278        producer: impl FutureProducer<S::Data, Item = T>,
1279    ) -> Result<Self>
1280    where
1281        T: func::Lower + func::Lift + Send + Sync + 'static,
1282    {
1283        ensure!(
1284            store.as_context().0.concurrency_support(),
1285            "concurrency support is not enabled"
1286        );
1287
1288        struct Producer<P>(P);
1289
1290        impl<D, T: func::Lower + 'static, P: FutureProducer<D, Item = T>> StreamProducer<D>
1291            for Producer<P>
1292        {
1293            type Item = P::Item;
1294            type Buffer = Option<P::Item>;
1295
1296            fn poll_produce<'a>(
1297                self: Pin<&mut Self>,
1298                cx: &mut Context<'_>,
1299                store: StoreContextMut<D>,
1300                mut destination: Destination<'a, Self::Item, Self::Buffer>,
1301                finish: bool,
1302            ) -> Poll<Result<StreamResult>> {
1303                // SAFETY: This is a standard pin-projection, and we never move
1304                // out of `self`.
1305                let producer = unsafe { self.map_unchecked_mut(|v| &mut v.0) };
1306
1307                Poll::Ready(Ok(
1308                    if let Some(value) = ready!(producer.poll_produce(cx, store, finish))? {
1309                        destination.set_buffer(Some(value));
1310
1311                        // Here we return `StreamResult::Completed` even though
1312                        // we've produced the last item we'll ever produce.
1313                        // That's because the ABI expects
1314                        // `ReturnCode::Completed(1)` rather than
1315                        // `ReturnCode::Dropped(1)`.  In any case, we won't be
1316                        // called again since the future will have resolved.
1317                        StreamResult::Completed
1318                    } else {
1319                        StreamResult::Cancelled
1320                    },
1321                ))
1322            }
1323        }
1324
1325        Ok(Self::new_(
1326            store
1327                .as_context_mut()
1328                .new_transmit(TransmitKind::Future, Producer(producer))?,
1329        ))
1330    }
1331
1332    pub(super) fn new_(idx: HostResourceIndex) -> Self {
1333        Self {
1334            idx,
1335            _phantom: PhantomData,
1336        }
1337    }
1338
1339    pub(super) fn idx(&self) -> HostResourceIndex {
1340        self.idx
1341    }
1342
1343    /// Set the consumer that accepts the result of this future.
1344    ///
1345    /// # Errors
1346    ///
1347    /// Returns an error if this future has already been closed or otherwise
1348    /// transferred (e.g. lowered into a guest), or if it does not belong to
1349    /// `store`.
1350    pub fn pipe<S: AsContextMut>(
1351        self,
1352        mut store: S,
1353        consumer: impl FutureConsumer<S::Data, Item = T> + Unpin,
1354    ) -> Result<()>
1355    where
1356        T: func::Lift + 'static,
1357    {
1358        struct Consumer<C>(C);
1359
1360        impl<D: 'static, T: func::Lift + 'static, C: FutureConsumer<D, Item = T>> StreamConsumer<D>
1361            for Consumer<C>
1362        {
1363            type Item = T;
1364
1365            fn poll_consume(
1366                self: Pin<&mut Self>,
1367                cx: &mut Context<'_>,
1368                mut store: StoreContextMut<D>,
1369                mut source: Source<Self::Item>,
1370                finish: bool,
1371            ) -> Poll<Result<StreamResult>> {
1372                // SAFETY: This is a standard pin-projection, and we never move
1373                // out of `self`.
1374                let consumer = unsafe { self.map_unchecked_mut(|v| &mut v.0) };
1375
1376                ready!(consumer.poll_consume(
1377                    cx,
1378                    store.as_context_mut(),
1379                    source.reborrow(),
1380                    finish
1381                ))?;
1382
1383                Poll::Ready(Ok(if source.remaining(store)? == 0 {
1384                    // Here we return `StreamResult::Completed` even though
1385                    // we've consumed the last item we'll ever consume.  That's
1386                    // because the ABI expects `ReturnCode::Completed(1)` rather
1387                    // than `ReturnCode::Dropped(1)`.  In any case, we won't be
1388                    // called again since the future will have resolved.
1389                    StreamResult::Completed
1390                } else {
1391                    StreamResult::Cancelled
1392                }))
1393            }
1394        }
1395
1396        store
1397            .as_context_mut()
1398            .set_consumer(self.idx, TransmitKind::Future, Consumer(consumer))
1399    }
1400
1401    /// Transfer ownership of the read end of a future from a guest to the host.
1402    fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
1403        Ok(Self::new_(lift_index_to_future(cx, ty, index)?))
1404    }
1405
1406    /// Close this `FutureReader`.
1407    ///
1408    /// This will close this half of the future which will signal to a pending
1409    /// write, if any, that the reader side is dropped. If the writer half has
1410    /// not yet written a value then when it attempts to write a value it will
1411    /// see that this end is closed.
1412    ///
1413    /// # Errors
1414    ///
1415    /// Returns an error if this future has already been closed or otherwise
1416    /// transferred (e.g. lowered into a guest), or if it does not belong to
1417    /// `store`.
1418    pub fn close(&mut self, mut store: impl AsContextMut) -> Result<()> {
1419        future_close(store.as_context_mut().0, self.idx)
1420    }
1421
1422    /// Convenience method around [`Self::close`].
1423    pub fn close_with(&mut self, accessor: impl AsAccessor) -> Result<()> {
1424        accessor.as_accessor().with(|access| self.close(access))
1425    }
1426
1427    /// Returns a [`GuardedFutureReader`] which will auto-close this future on
1428    /// drop and clean it up from the store.
1429    ///
1430    /// Note that the `accessor` provided must own this future and is
1431    /// additionally transferred to the `GuardedFutureReader` return value.
1432    pub fn guard<A>(self, accessor: A) -> GuardedFutureReader<T, A>
1433    where
1434        A: AsAccessor,
1435    {
1436        GuardedFutureReader::new(accessor, self)
1437    }
1438
1439    /// Attempts to convert this [`FutureReader<T>`] to a [`FutureAny`].
1440    ///
1441    /// # Errors
1442    ///
1443    /// This function will return an error if `self` does not belong to
1444    /// `store`.
1445    pub fn try_into_future_any(self, store: impl AsContextMut) -> Result<FutureAny>
1446    where
1447        T: ComponentType + 'static,
1448    {
1449        FutureAny::try_from_future_reader(store, self)
1450    }
1451
1452    /// Attempts to convert a [`FutureAny`] into a [`FutureReader<T>`].
1453    ///
1454    /// # Errors
1455    ///
1456    /// This function will fail if `T` doesn't match the type of the value that
1457    /// `future` is sending.
1458    pub fn try_from_future_any(future: FutureAny) -> Result<Self>
1459    where
1460        T: ComponentType + 'static,
1461    {
1462        future.try_into_future_reader()
1463    }
1464}
1465
1466impl<T> fmt::Debug for FutureReader<T> {
1467    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1468        f.debug_struct("FutureReader")
1469            .field("idx", &self.idx)
1470            .finish()
1471    }
1472}
1473
1474pub(super) fn future_close(store: &mut StoreOpaque, idx: HostResourceIndex) -> Result<()> {
1475    let id = store.host_reader_take(idx)?;
1476    store.host_drop_reader(id, TransmitKind::Future)
1477}
1478
1479/// Transfer ownership of the read end of a future from a guest to the host.
1480pub(super) fn lift_index_to_future(
1481    cx: &mut LiftContext<'_>,
1482    ty: InterfaceType,
1483    index: u32,
1484) -> Result<HostResourceIndex> {
1485    match ty {
1486        InterfaceType::Future(src) => {
1487            let id = {
1488                let (state, instance, counter) = cx.concurrent_state_and_instance_mut();
1489                lift_index_to_transmit(instance, counter, state, TransmitIndex::Future(src), index)?
1490            };
1491            cx.host_resource_lower_own(id.rep(), None, None)
1492        }
1493        _ => func::bad_type_info(),
1494    }
1495}
1496
1497/// Checks that the host-owned read end `idx` may be lowered into a guest as a
1498/// future or stream with the payload type `payload`.
1499///
1500/// Note that this is technically redundant for `StreamReader<T>` where its
1501/// static typecheck already verified this, but this is otherwise required in
1502/// the face of the `{Stream,Future}Any` abstraction to handle various use cases
1503/// of types dynamically being labeled or possibly switched.
1504fn typecheck_lowered_transmit<U>(
1505    idx: HostResourceIndex,
1506    cx: &mut LowerContext<'_, U>,
1507    payload: Option<&InterfaceType>,
1508) -> Result<()> {
1509    let origin = cx.store.0.transmit_origin(idx)?;
1510    let dst = cx.instance_type();
1511    let equivalent = match origin {
1512        TransmitOrigin::Host { typecheck } => {
1513            return typecheck(payload, &dst).context("future or stream payload types differ");
1514        }
1515        TransmitOrigin::GuestFuture(id, ty) => {
1516            let src = InstanceType::new(cx.store.0.component_instance(id));
1517            types::FutureType::from(src.types[ty].ty, &src).equivalent_payload_guest(&dst, payload)
1518        }
1519        TransmitOrigin::GuestStream(id, ty) => {
1520            let src = InstanceType::new(cx.store.0.component_instance(id));
1521            types::StreamType::from(src.types[ty].ty, &src).equivalent_payload_guest(&dst, payload)
1522        }
1523    };
1524    if !equivalent {
1525        bail!("future or stream payload types differ");
1526    }
1527    Ok(())
1528}
1529
1530/// Transfer ownership of the read end of a future from the host to a guest.
1531pub(super) fn lower_future_to_index<U>(
1532    idx: HostResourceIndex,
1533    cx: &mut LowerContext<'_, U>,
1534    ty: InterfaceType,
1535) -> Result<u32> {
1536    match ty {
1537        InterfaceType::Future(dst) => {
1538            let types = cx.types;
1539            typecheck_lowered_transmit(idx, cx, types[types[dst].ty].payload.as_ref())?;
1540            let id = cx.store.0.host_reader_take(idx)?;
1541            cx.instance_handle()
1542                .lower_transmit_to_index(cx.store.0, TransmitIndex::Future(dst), id)
1543        }
1544        _ => func::bad_type_info(),
1545    }
1546}
1547
1548// SAFETY: This relies on the `ComponentType` implementation for `u32` being
1549// safe and correct since we lift and lower future handles as `u32`s.
1550unsafe impl<T: ComponentType> ComponentType for FutureReader<T> {
1551    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1552
1553    type Lower = <u32 as func::ComponentType>::Lower;
1554
1555    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1556        match ty {
1557            InterfaceType::Future(ty) => {
1558                let ty = types.types[*ty].ty;
1559                types::typecheck_payload::<T>(types.types[ty].payload.as_ref(), types)
1560            }
1561            other => bail!("expected `future`, found `{}`", func::desc(other)),
1562        }
1563    }
1564}
1565
1566// SAFETY: See the comment on the `ComponentType` `impl` for this type.
1567unsafe impl<T: ComponentType> func::Lower for FutureReader<T> {
1568    fn linear_lower_to_flat<U>(
1569        &self,
1570        cx: &mut LowerContext<'_, U>,
1571        ty: InterfaceType,
1572        dst: &mut MaybeUninit<Self::Lower>,
1573    ) -> Result<()> {
1574        lower_future_to_index(self.idx, cx, ty)?.linear_lower_to_flat(cx, InterfaceType::U32, dst)
1575    }
1576
1577    fn linear_lower_to_memory<U>(
1578        &self,
1579        cx: &mut LowerContext<'_, U>,
1580        ty: InterfaceType,
1581        offset: usize,
1582    ) -> Result<()> {
1583        lower_future_to_index(self.idx, cx, ty)?.linear_lower_to_memory(
1584            cx,
1585            InterfaceType::U32,
1586            offset,
1587        )
1588    }
1589}
1590
1591// SAFETY: See the comment on the `ComponentType` `impl` for this type.
1592unsafe impl<T: ComponentType> func::Lift for FutureReader<T> {
1593    fn linear_lift_from_flat(
1594        cx: &mut LiftContext<'_>,
1595        ty: InterfaceType,
1596        src: &Self::Lower,
1597    ) -> Result<Self> {
1598        let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
1599        Self::lift_from_index(cx, ty, index)
1600    }
1601
1602    fn linear_lift_from_memory(
1603        cx: &mut LiftContext<'_>,
1604        ty: InterfaceType,
1605        bytes: &[u8],
1606    ) -> Result<Self> {
1607        let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
1608        Self::lift_from_index(cx, ty, index)
1609    }
1610}
1611
1612/// A [`FutureReader`] paired with an [`Accessor`].
1613///
1614/// This is an RAII wrapper around [`FutureReader`] that ensures it is closed
1615/// when dropped. This can be created through [`GuardedFutureReader::new`] or
1616/// [`FutureReader::guard`].
1617///
1618/// [`Accessor`]: crate::component::Accessor
1619pub struct GuardedFutureReader<T, A>
1620where
1621    A: AsAccessor,
1622{
1623    // This field is `None` to implement the conversion from this guard back to
1624    // `FutureReader`. When `None` is seen in the destructor it will cause the
1625    // destructor to do nothing.
1626    reader: Option<FutureReader<T>>,
1627    accessor: A,
1628}
1629
1630impl<T, A> GuardedFutureReader<T, A>
1631where
1632    A: AsAccessor,
1633{
1634    /// Create a new `GuardedFutureReader` with the specified `accessor` and `reader`.
1635    ///
1636    /// # Panics
1637    ///
1638    /// Panics if [`Config::concurrency_support`] is not enabled.
1639    ///
1640    /// [`Config::concurrency_support`]: crate::Config::concurrency_support
1641    pub fn new(accessor: A, reader: FutureReader<T>) -> Self {
1642        assert!(
1643            accessor
1644                .as_accessor()
1645                .with(|a| a.as_context().0.concurrency_support())
1646        );
1647        Self {
1648            reader: Some(reader),
1649            accessor,
1650        }
1651    }
1652
1653    /// Extracts the underlying [`FutureReader`] from this guard, returning it
1654    /// back.
1655    pub fn into_future(self) -> FutureReader<T> {
1656        self.into()
1657    }
1658}
1659
1660impl<T, A> From<GuardedFutureReader<T, A>> for FutureReader<T>
1661where
1662    A: AsAccessor,
1663{
1664    fn from(mut guard: GuardedFutureReader<T, A>) -> Self {
1665        guard.reader.take().unwrap()
1666    }
1667}
1668
1669impl<T, A> Drop for GuardedFutureReader<T, A>
1670where
1671    A: AsAccessor,
1672{
1673    fn drop(&mut self) {
1674        if let Some(reader) = &mut self.reader {
1675            // Currently this can only fail if the future is closed twice or
1676            // the handle was cloned/closed elsewhere, all of which the embedder
1677            // is responsible for when using this guard. Hint during
1678            // development that's a bad idea, but otherwise ignore the error in
1679            // release builds.
1680            let result = reader.close_with(&self.accessor);
1681            debug_assert!(result.is_ok());
1682        }
1683    }
1684}
1685
1686/// Represents the readable end of a Component Model `stream`.
1687///
1688/// Note that `StreamReader` instances must be disposed of using `close`;
1689/// otherwise the in-store representation will leak and the writer end will hang
1690/// indefinitely.  Consider using [`GuardedStreamReader`] to ensure that
1691/// disposal happens automatically.
1692pub struct StreamReader<T> {
1693    idx: HostResourceIndex,
1694    _phantom: PhantomData<T>,
1695}
1696
1697impl<T> StreamReader<T> {
1698    /// Create a new stream with the specified producer.
1699    ///
1700    /// # Errors
1701    ///
1702    /// Returns an error if the resource table for this store is full or if
1703    /// [`Config::concurrency_support`] is not enabled.
1704    ///
1705    /// [`Config::concurrency_support`]: crate::Config::concurrency_support
1706    pub fn new<S: AsContextMut>(
1707        mut store: S,
1708        producer: impl StreamProducer<S::Data, Item = T>,
1709    ) -> Result<Self>
1710    where
1711        T: func::Lower + func::Lift + Send + Sync + 'static,
1712    {
1713        ensure!(
1714            store.as_context().0.concurrency_support(),
1715            "concurrency support is not enabled",
1716        );
1717        Ok(Self::new_(
1718            store
1719                .as_context_mut()
1720                .new_transmit(TransmitKind::Stream, producer)?,
1721        ))
1722    }
1723
1724    pub(super) fn new_(idx: HostResourceIndex) -> Self {
1725        Self {
1726            idx,
1727            _phantom: PhantomData,
1728        }
1729    }
1730
1731    pub(super) fn idx(&self) -> HostResourceIndex {
1732        self.idx
1733    }
1734
1735    /// Attempt to consume this object by converting it into the specified type.
1736    ///
1737    /// This can be useful for "short-circuiting" host-to-host streams,
1738    /// bypassing the guest entirely.  For example, if a guest task returns a
1739    /// host-created stream and then exits, this function may be used to
1740    /// retrieve the write end, after which the guest instance and store may be
1741    /// disposed of if no longer needed.
1742    ///
1743    /// This will return `Ok(_)` if and only if the following conditions are
1744    /// met:
1745    ///
1746    /// - The stream was created by the host (i.e. not by the guest).
1747    ///
1748    /// - The `StreamProducer::try_into` function returns `Ok(_)` when given the
1749    /// producer provided to `StreamReader::new` when the stream was created,
1750    /// along with `TypeId::of::<V>()`.
1751    ///
1752    /// # Panics
1753    ///
1754    /// Panics if this stream has already been closed, or if this stream doesn't
1755    /// belong to the specified `store`.
1756    pub fn try_into<V: 'static>(mut self, mut store: impl AsContextMut) -> Result<V, Self> {
1757        let store = store.as_context_mut();
1758        let id = store.0.host_reader_rep(self.idx).unwrap();
1759        let state = store.0.concurrent_state_mut_already_forced_current_thread();
1760        let id = state.get_mut(id).unwrap().state;
1761        if let WriteState::HostReady { try_into, .. } = &state.get_mut(id).unwrap().write {
1762            match try_into(TypeId::of::<V>()) {
1763                Some(result) => {
1764                    self.close(store).unwrap();
1765                    Ok(*result.downcast::<V>().unwrap())
1766                }
1767                None => Err(self),
1768            }
1769        } else {
1770            Err(self)
1771        }
1772    }
1773
1774    /// Set the consumer that accepts the items delivered to this stream.
1775    ///
1776    /// # Errors
1777    ///
1778    /// Returns an error if this stream has already been closed or otherwise
1779    /// transferred (e.g. lowered into a guest), or if it does not belong to
1780    /// `store`.
1781    pub fn pipe<S: AsContextMut>(
1782        self,
1783        mut store: S,
1784        consumer: impl StreamConsumer<S::Data, Item = T>,
1785    ) -> Result<()>
1786    where
1787        T: 'static,
1788    {
1789        store
1790            .as_context_mut()
1791            .set_consumer(self.idx, TransmitKind::Stream, consumer)
1792    }
1793
1794    /// Transfer ownership of the read end of a stream from a guest to the host.
1795    fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
1796        Ok(Self::new_(lift_index_to_stream(cx, ty, index)?))
1797    }
1798
1799    /// Close this `StreamReader`.
1800    ///
1801    /// This will signal that this portion of the stream is closed causing all
1802    /// future writes to return immediately with "DROPPED".
1803    ///
1804    /// # Errors
1805    ///
1806    /// Returns an error if this stream has already been closed or otherwise
1807    /// transferred (e.g. lowered into a guest), or if it does not belong to
1808    /// `store`.
1809    pub fn close(&mut self, mut store: impl AsContextMut) -> Result<()> {
1810        stream_close(store.as_context_mut().0, self.idx)
1811    }
1812
1813    /// Convenience method around [`Self::close`].
1814    pub fn close_with(&mut self, accessor: impl AsAccessor) -> Result<()> {
1815        accessor.as_accessor().with(|access| self.close(access))
1816    }
1817
1818    /// Returns a [`GuardedStreamReader`] which will auto-close this stream on
1819    /// drop and clean it up from the store.
1820    ///
1821    /// Note that the `accessor` provided must own this future and is
1822    /// additionally transferred to the `GuardedStreamReader` return value.
1823    pub fn guard<A>(self, accessor: A) -> GuardedStreamReader<T, A>
1824    where
1825        A: AsAccessor,
1826    {
1827        GuardedStreamReader::new(accessor, self)
1828    }
1829
1830    /// Attempts to convert this [`StreamReader<T>`] to a [`StreamAny`].
1831    ///
1832    /// # Errors
1833    ///
1834    /// This function will return an error if `self` does not belong to
1835    /// `store`.
1836    pub fn try_into_stream_any(self, store: impl AsContextMut) -> Result<StreamAny>
1837    where
1838        T: ComponentType + 'static,
1839    {
1840        StreamAny::try_from_stream_reader(store, self)
1841    }
1842
1843    /// Attempts to convert a [`StreamAny`] into a [`StreamReader<T>`].
1844    ///
1845    /// # Errors
1846    ///
1847    /// This function will fail if `T` doesn't match the type of the value that
1848    /// `stream` is sending.
1849    pub fn try_from_stream_any(stream: StreamAny) -> Result<Self>
1850    where
1851        T: ComponentType + 'static,
1852    {
1853        stream.try_into_stream_reader()
1854    }
1855}
1856
1857impl<T> fmt::Debug for StreamReader<T> {
1858    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1859        f.debug_struct("StreamReader")
1860            .field("idx", &self.idx)
1861            .finish()
1862    }
1863}
1864
1865pub(super) fn stream_close(store: &mut StoreOpaque, idx: HostResourceIndex) -> Result<()> {
1866    let id = store.host_reader_take(idx)?;
1867    store.host_drop_reader(id, TransmitKind::Stream)
1868}
1869
1870/// Transfer ownership of the read end of a stream from a guest to the host.
1871pub(super) fn lift_index_to_stream(
1872    cx: &mut LiftContext<'_>,
1873    ty: InterfaceType,
1874    index: u32,
1875) -> Result<HostResourceIndex> {
1876    match ty {
1877        InterfaceType::Stream(src) => {
1878            let id = {
1879                let (state, instance, counter) = cx.concurrent_state_and_instance_mut();
1880                lift_index_to_transmit(instance, counter, state, TransmitIndex::Stream(src), index)?
1881            };
1882            cx.host_resource_lower_own(id.rep(), None, None)
1883        }
1884        _ => func::bad_type_info(),
1885    }
1886}
1887
1888/// Transfer ownership of the read end of a stream from the host to a guest.
1889pub(super) fn lower_stream_to_index<U>(
1890    idx: HostResourceIndex,
1891    cx: &mut LowerContext<'_, U>,
1892    ty: InterfaceType,
1893) -> Result<u32> {
1894    match ty {
1895        InterfaceType::Stream(dst) => {
1896            let types = cx.types;
1897            typecheck_lowered_transmit(idx, cx, types[types[dst].ty].payload.as_ref())?;
1898            let id = cx.store.0.host_reader_take(idx)?;
1899            cx.instance_handle()
1900                .lower_transmit_to_index(cx.store.0, TransmitIndex::Stream(dst), id)
1901        }
1902        _ => func::bad_type_info(),
1903    }
1904}
1905
1906// SAFETY: This relies on the `ComponentType` implementation for `u32` being
1907// safe and correct since we lift and lower stream handles as `u32`s.
1908unsafe impl<T: ComponentType> ComponentType for StreamReader<T> {
1909    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1910
1911    type Lower = <u32 as func::ComponentType>::Lower;
1912
1913    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1914        match ty {
1915            InterfaceType::Stream(ty) => {
1916                let ty = types.types[*ty].ty;
1917                types::typecheck_payload::<T>(types.types[ty].payload.as_ref(), types)
1918            }
1919            other => bail!("expected `stream`, found `{}`", func::desc(other)),
1920        }
1921    }
1922}
1923
1924// SAFETY: See the comment on the `ComponentType` `impl` for this type.
1925unsafe impl<T: ComponentType> func::Lower for StreamReader<T> {
1926    fn linear_lower_to_flat<U>(
1927        &self,
1928        cx: &mut LowerContext<'_, U>,
1929        ty: InterfaceType,
1930        dst: &mut MaybeUninit<Self::Lower>,
1931    ) -> Result<()> {
1932        lower_stream_to_index(self.idx, cx, ty)?.linear_lower_to_flat(cx, InterfaceType::U32, dst)
1933    }
1934
1935    fn linear_lower_to_memory<U>(
1936        &self,
1937        cx: &mut LowerContext<'_, U>,
1938        ty: InterfaceType,
1939        offset: usize,
1940    ) -> Result<()> {
1941        lower_stream_to_index(self.idx, cx, ty)?.linear_lower_to_memory(
1942            cx,
1943            InterfaceType::U32,
1944            offset,
1945        )
1946    }
1947}
1948
1949// SAFETY: See the comment on the `ComponentType` `impl` for this type.
1950unsafe impl<T: ComponentType> func::Lift for StreamReader<T> {
1951    fn linear_lift_from_flat(
1952        cx: &mut LiftContext<'_>,
1953        ty: InterfaceType,
1954        src: &Self::Lower,
1955    ) -> Result<Self> {
1956        let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
1957        Self::lift_from_index(cx, ty, index)
1958    }
1959
1960    fn linear_lift_from_memory(
1961        cx: &mut LiftContext<'_>,
1962        ty: InterfaceType,
1963        bytes: &[u8],
1964    ) -> Result<Self> {
1965        let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
1966        Self::lift_from_index(cx, ty, index)
1967    }
1968}
1969
1970/// A [`StreamReader`] paired with an [`Accessor`].
1971///
1972/// This is an RAII wrapper around [`StreamReader`] that ensures it is closed
1973/// when dropped. This can be created through [`GuardedStreamReader::new`] or
1974/// [`StreamReader::guard`].
1975///
1976/// [`Accessor`]: crate::component::Accessor
1977pub struct GuardedStreamReader<T, A>
1978where
1979    A: AsAccessor,
1980{
1981    // This field is `None` to implement the conversion from this guard back to
1982    // `StreamReader`. When `None` is seen in the destructor it will cause the
1983    // destructor to do nothing.
1984    reader: Option<StreamReader<T>>,
1985    accessor: A,
1986}
1987
1988impl<T, A> GuardedStreamReader<T, A>
1989where
1990    A: AsAccessor,
1991{
1992    /// Create a new `GuardedStreamReader` with the specified `accessor` and
1993    /// `reader`.
1994    ///
1995    /// # Panics
1996    ///
1997    /// Panics if [`Config::concurrency_support`] is not enabled.
1998    ///
1999    /// [`Config::concurrency_support`]: crate::Config::concurrency_support
2000    pub fn new(accessor: A, reader: StreamReader<T>) -> Self {
2001        assert!(
2002            accessor
2003                .as_accessor()
2004                .with(|a| a.as_context().0.concurrency_support())
2005        );
2006        Self {
2007            reader: Some(reader),
2008            accessor,
2009        }
2010    }
2011
2012    /// Extracts the underlying [`StreamReader`] from this guard, returning it
2013    /// back.
2014    pub fn into_stream(self) -> StreamReader<T> {
2015        self.into()
2016    }
2017}
2018
2019impl<T, A> From<GuardedStreamReader<T, A>> for StreamReader<T>
2020where
2021    A: AsAccessor,
2022{
2023    fn from(mut guard: GuardedStreamReader<T, A>) -> Self {
2024        guard.reader.take().unwrap()
2025    }
2026}
2027
2028impl<T, A> Drop for GuardedStreamReader<T, A>
2029where
2030    A: AsAccessor,
2031{
2032    fn drop(&mut self) {
2033        if let Some(reader) = &mut self.reader {
2034            // See comments in `Drop for GuardedFutureReader` for this assert.
2035            let result = reader.close_with(&self.accessor);
2036            debug_assert!(result.is_ok());
2037        }
2038    }
2039}
2040
2041/// Represents a Component Model `error-context`.
2042pub struct ErrorContext {
2043    rep: u32,
2044}
2045
2046impl ErrorContext {
2047    pub(crate) fn new(rep: u32) -> Self {
2048        Self { rep }
2049    }
2050
2051    /// Convert this `ErrorContext` into a [`Val`].
2052    pub fn into_val(self) -> Val {
2053        Val::ErrorContext(ErrorContextAny(self.rep))
2054    }
2055
2056    /// Attempt to convert the specified [`Val`] to a `ErrorContext`.
2057    pub fn from_val(_: impl AsContextMut, value: &Val) -> Result<Self> {
2058        let Val::ErrorContext(ErrorContextAny(rep)) = value else {
2059            bail!("expected `error-context`; got `{}`", value.desc());
2060        };
2061        Ok(Self::new(*rep))
2062    }
2063
2064    fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
2065        match ty {
2066            InterfaceType::ErrorContext(src) => {
2067                let rep = cx
2068                    .instance_mut()
2069                    .table_for_error_context(src)
2070                    .error_context_rep(index)?;
2071
2072                Ok(Self { rep })
2073            }
2074            _ => func::bad_type_info(),
2075        }
2076    }
2077}
2078
2079pub(crate) fn lower_error_context_to_index<U>(
2080    rep: u32,
2081    cx: &mut LowerContext<'_, U>,
2082    ty: InterfaceType,
2083) -> Result<u32> {
2084    match ty {
2085        InterfaceType::ErrorContext(dst) => {
2086            let (instance, counter) = cx
2087                .instance_handle()
2088                .id()
2089                .get_mut_and_handle_counter(cx.store.0);
2090            instance
2091                .table_for_error_context(dst)
2092                .error_context_insert(counter, rep)
2093        }
2094        _ => func::bad_type_info(),
2095    }
2096}
2097// SAFETY: This relies on the `ComponentType` implementation for `u32` being
2098// safe and correct since we lift and lower future handles as `u32`s.
2099unsafe impl func::ComponentType for ErrorContext {
2100    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
2101
2102    type Lower = <u32 as func::ComponentType>::Lower;
2103
2104    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
2105        match ty {
2106            InterfaceType::ErrorContext(_) => Ok(()),
2107            other => bail!("expected `error`, found `{}`", func::desc(other)),
2108        }
2109    }
2110}
2111
2112// SAFETY: See the comment on the `ComponentType` `impl` for this type.
2113unsafe impl func::Lower for ErrorContext {
2114    fn linear_lower_to_flat<T>(
2115        &self,
2116        cx: &mut LowerContext<'_, T>,
2117        ty: InterfaceType,
2118        dst: &mut MaybeUninit<Self::Lower>,
2119    ) -> Result<()> {
2120        lower_error_context_to_index(self.rep, cx, ty)?.linear_lower_to_flat(
2121            cx,
2122            InterfaceType::U32,
2123            dst,
2124        )
2125    }
2126
2127    fn linear_lower_to_memory<T>(
2128        &self,
2129        cx: &mut LowerContext<'_, T>,
2130        ty: InterfaceType,
2131        offset: usize,
2132    ) -> Result<()> {
2133        lower_error_context_to_index(self.rep, cx, ty)?.linear_lower_to_memory(
2134            cx,
2135            InterfaceType::U32,
2136            offset,
2137        )
2138    }
2139}
2140
2141// SAFETY: See the comment on the `ComponentType` `impl` for this type.
2142unsafe impl func::Lift for ErrorContext {
2143    fn linear_lift_from_flat(
2144        cx: &mut LiftContext<'_>,
2145        ty: InterfaceType,
2146        src: &Self::Lower,
2147    ) -> Result<Self> {
2148        let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
2149        Self::lift_from_index(cx, ty, index)
2150    }
2151
2152    fn linear_lift_from_memory(
2153        cx: &mut LiftContext<'_>,
2154        ty: InterfaceType,
2155        bytes: &[u8],
2156    ) -> Result<Self> {
2157        let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
2158        Self::lift_from_index(cx, ty, index)
2159    }
2160}
2161
2162/// Represents the read or write end of a stream or future.
2163pub(super) struct TransmitHandle {
2164    pub(super) common: WaitableCommon,
2165    /// See `TransmitState`
2166    state: TableId<TransmitState>,
2167}
2168
2169impl TransmitHandle {
2170    fn new(state: TableId<TransmitState>) -> Self {
2171        Self {
2172            common: WaitableCommon::default(),
2173            state,
2174        }
2175    }
2176}
2177
2178impl TableDebug for TransmitHandle {
2179    fn type_name() -> &'static str {
2180        "TransmitHandle"
2181    }
2182}
2183
2184/// Represents the state of a stream or future.
2185struct TransmitState {
2186    /// The write end of the stream or future.
2187    write_handle: TableId<TransmitHandle>,
2188    /// The read end of the stream or future.
2189    read_handle: TableId<TransmitHandle>,
2190    /// See `WriteState`
2191    write: WriteState,
2192    /// See `ReadState`
2193    read: ReadState,
2194    /// Whether further values may be transmitted via this stream or future.
2195    done: bool,
2196    /// The original creator of this stream or future, whose payload type is
2197    /// checked against a guest's whenever the host lowers the read end into
2198    /// that guest, and which `{Future,Stream}Any` use as their initial type.
2199    pub(super) origin: TransmitOrigin,
2200}
2201
2202#[derive(Copy, Clone)]
2203pub(super) enum TransmitOrigin {
2204    Host {
2205        /// Type-checks the producer's items against the guest-supplied payload.
2206        typecheck: fn(Option<&InterfaceType>, &InstanceType<'_>) -> Result<()>,
2207    },
2208    GuestFuture(ComponentInstanceId, TypeFutureTableIndex),
2209    GuestStream(ComponentInstanceId, TypeStreamTableIndex),
2210}
2211
2212impl TransmitState {
2213    fn new(origin: TransmitOrigin) -> Self {
2214        Self {
2215            write_handle: TableId::new(u32::MAX),
2216            read_handle: TableId::new(u32::MAX),
2217            read: ReadState::Open,
2218            write: WriteState::Open,
2219            done: false,
2220            origin,
2221        }
2222    }
2223}
2224
2225impl TableDebug for TransmitState {
2226    fn type_name() -> &'static str {
2227        "TransmitState"
2228    }
2229}
2230
2231impl TransmitOrigin {
2232    fn guest(id: ComponentInstanceId, index: TransmitIndex) -> Self {
2233        match index {
2234            TransmitIndex::Future(ty) => TransmitOrigin::GuestFuture(id, ty),
2235            TransmitIndex::Stream(ty) => TransmitOrigin::GuestStream(id, ty),
2236        }
2237    }
2238}
2239
2240type PollStream = Box<
2241    dyn Fn() -> Pin<Box<dyn Future<Output = Result<StreamResult>> + Send + 'static>> + Send + Sync,
2242>;
2243
2244type TryInto = Box<dyn Fn(TypeId) -> Option<Box<dyn Any>> + Send + Sync>;
2245
2246/// Represents the state of the write end of a stream or future.
2247enum WriteState {
2248    /// The write end is open, but no write is pending.
2249    Open,
2250    /// The write end is owned by a guest task and a write is pending.
2251    GuestReady {
2252        instance: Instance,
2253        caller: RuntimeComponentInstanceIndex,
2254        ty: TransmitIndex,
2255        flat_abi: Option<FlatAbi>,
2256        options: OptionsIndex,
2257        address: usize,
2258        count: ItemCount,
2259        handle: u32,
2260    },
2261    /// The write end is owned by the host, which is ready to produce items.
2262    HostReady {
2263        produce: PollStream,
2264        try_into: TryInto,
2265        guest_offset: ItemCount,
2266        cancel: bool,
2267        cancel_waker: Option<Waker>,
2268    },
2269    /// The write end has been dropped.
2270    Dropped,
2271}
2272
2273impl fmt::Debug for WriteState {
2274    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2275        match self {
2276            Self::Open => f.debug_tuple("Open").finish(),
2277            Self::GuestReady { .. } => f.debug_tuple("GuestReady").finish(),
2278            Self::HostReady { .. } => f.debug_tuple("HostReady").finish(),
2279            Self::Dropped => f.debug_tuple("Dropped").finish(),
2280        }
2281    }
2282}
2283
2284/// Represents the state of the read end of a stream or future.
2285enum ReadState {
2286    /// The read end is open, but no read is pending.
2287    Open,
2288    /// The read end is owned by a guest task and a read is pending.
2289    GuestReady {
2290        ty: TransmitIndex,
2291        caller_instance: RuntimeComponentInstanceIndex,
2292        caller_thread: QualifiedThreadId,
2293        flat_abi: Option<FlatAbi>,
2294        instance: Instance,
2295        options: OptionsIndex,
2296        address: usize,
2297        count: ItemCount,
2298        handle: u32,
2299    },
2300    /// The read end is owned by a host task, and it is ready to consume items.
2301    HostReady {
2302        consume: PollStream,
2303        guest_offset: ItemCount,
2304        cancel: bool,
2305        cancel_waker: Option<Waker>,
2306    },
2307    /// Both the read and write ends are owned by the host.
2308    HostToHost {
2309        accept: Box<
2310            dyn for<'a> Fn(
2311                    &'a mut UntypedWriteBuffer<'a>,
2312                )
2313                    -> Pin<Box<dyn Future<Output = Result<StreamResult>> + Send + 'a>>
2314                + Send
2315                + Sync,
2316        >,
2317        buffer: Vec<u8>,
2318        limit: usize,
2319    },
2320    /// The read end has been dropped.
2321    Dropped,
2322}
2323
2324impl fmt::Debug for ReadState {
2325    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2326        match self {
2327            Self::Open => f.debug_tuple("Open").finish(),
2328            Self::GuestReady { .. } => f.debug_tuple("GuestReady").finish(),
2329            Self::HostReady { .. } => f.debug_tuple("HostReady").finish(),
2330            Self::HostToHost { .. } => f.debug_tuple("HostToHost").finish(),
2331            Self::Dropped => f.debug_tuple("Dropped").finish(),
2332        }
2333    }
2334}
2335
2336fn return_code(kind: TransmitKind, state: StreamResult, count: ItemCount) -> Result<ReturnCode> {
2337    Ok(match state {
2338        StreamResult::Dropped => ReturnCode::Dropped(count),
2339        StreamResult::Completed => ReturnCode::completed(kind, count),
2340        StreamResult::Cancelled => ReturnCode::Cancelled(count),
2341    })
2342}
2343
2344fn settle_host_read(
2345    transmit: &mut TransmitState,
2346    kind: TransmitKind,
2347    state: StreamResult,
2348) -> Result<ReturnCode> {
2349    let ReadState::HostReady {
2350        consume,
2351        guest_offset,
2352        ..
2353    } = mem::replace(&mut transmit.read, ReadState::Open)
2354    else {
2355        bail_bug!("expected ReadState::HostReady")
2356    };
2357    let code = return_code(kind, state, guest_offset)?;
2358    transmit.read = match state {
2359        StreamResult::Dropped => ReadState::Dropped,
2360        StreamResult::Completed | StreamResult::Cancelled => ReadState::HostReady {
2361            consume,
2362            guest_offset: ItemCount::ZERO,
2363            cancel: false,
2364            cancel_waker: None,
2365        },
2366    };
2367    Ok(code)
2368}
2369
2370fn settle_host_write(
2371    transmit: &mut TransmitState,
2372    kind: TransmitKind,
2373    state: StreamResult,
2374) -> Result<ReturnCode> {
2375    let WriteState::HostReady {
2376        produce,
2377        try_into,
2378        guest_offset,
2379        ..
2380    } = mem::replace(&mut transmit.write, WriteState::Open)
2381    else {
2382        bail_bug!("expected WriteState::HostReady")
2383    };
2384    let code = return_code(kind, state, guest_offset)?;
2385    transmit.write = match state {
2386        StreamResult::Dropped => WriteState::Dropped,
2387        StreamResult::Completed | StreamResult::Cancelled => WriteState::HostReady {
2388            produce,
2389            try_into,
2390            guest_offset: ItemCount::ZERO,
2391            cancel: false,
2392            cancel_waker: None,
2393        },
2394    };
2395    Ok(code)
2396}
2397
2398impl StoreOpaque {
2399    fn pipe_from_guest(
2400        &mut self,
2401        kind: TransmitKind,
2402        id: TableId<TransmitState>,
2403        future: Pin<Box<dyn Future<Output = Result<StreamResult>> + Send + 'static>>,
2404    ) {
2405        let future = async move {
2406            let stream_state = future.await?;
2407            tls::get(|store| {
2408                let state = store.concurrent_state_mut()?;
2409                let transmit = state.get_mut(id)?;
2410                let code = settle_host_read(transmit, kind, stream_state)?;
2411                let WriteState::GuestReady { ty, handle, .. } =
2412                    mem::replace(&mut transmit.write, WriteState::Open)
2413                else {
2414                    bail_bug!("expected WriteState::GuestReady")
2415                };
2416                state.send_write_result(ty, id, handle, code)?;
2417                Ok(())
2418            })
2419        };
2420
2421        self.concurrent_state_mut_already_forced_current_thread()
2422            .push_future(future.boxed());
2423    }
2424
2425    fn pipe_to_guest(
2426        &mut self,
2427        kind: TransmitKind,
2428        id: TableId<TransmitState>,
2429        future: Pin<Box<dyn Future<Output = Result<StreamResult>> + Send + 'static>>,
2430    ) {
2431        let future = async move {
2432            let stream_state = future.await?;
2433            tls::get(|store| {
2434                let state = store.concurrent_state_mut()?;
2435                let transmit = state.get_mut(id)?;
2436                let code = settle_host_write(transmit, kind, stream_state)?;
2437                let ReadState::GuestReady { ty, handle, .. } =
2438                    mem::replace(&mut transmit.read, ReadState::Open)
2439                else {
2440                    bail_bug!("expected ReadState::GuestReady")
2441                };
2442                state.send_read_result(ty, id, handle, code)?;
2443                Ok(())
2444            })
2445        };
2446
2447        self.concurrent_state_mut_already_forced_current_thread()
2448            .push_future(future.boxed());
2449    }
2450
2451    /// Drop the read end of a stream or future read from the host.
2452    fn host_drop_reader(&mut self, id: TableId<TransmitHandle>, kind: TransmitKind) -> Result<()> {
2453        let state = self.concurrent_state_mut()?;
2454        Waitable::Transmit(id).join(state, None)?;
2455        let transmit_id = state.get_mut(id)?.state;
2456        let transmit = state
2457            .get_mut(transmit_id)
2458            .with_context(|| format!("error closing reader {transmit_id:?}"))?;
2459        log::trace!(
2460            "host_drop_reader state {transmit_id:?}; read state {:?} write state {:?}",
2461            transmit.read,
2462            transmit.write
2463        );
2464
2465        transmit.read = ReadState::Dropped;
2466
2467        // If the write end is already dropped, it should stay dropped,
2468        // otherwise, it should be opened.
2469        let new_state = if let WriteState::Dropped = &transmit.write {
2470            WriteState::Dropped
2471        } else {
2472            WriteState::Open
2473        };
2474
2475        let write_handle = transmit.write_handle;
2476        let done = transmit.done;
2477
2478        match mem::replace(&mut transmit.write, new_state) {
2479            // If a guest is waiting to write, notify it that the read end has
2480            // been dropped.
2481            WriteState::GuestReady { ty, handle, .. } => {
2482                state.update_event(
2483                    write_handle.rep(),
2484                    match ty {
2485                        TransmitIndex::Future(ty) => Event::FutureWrite {
2486                            code: ReturnCode::Dropped(ItemCount::ZERO),
2487                            pending: Some((ty, handle)),
2488                        },
2489                        TransmitIndex::Stream(ty) => Event::StreamWrite {
2490                            code: ReturnCode::Dropped(ItemCount::ZERO),
2491                            pending: Some((ty, handle)),
2492                        },
2493                    },
2494                )?;
2495            }
2496
2497            // Otherwise notify the idle write end that the read end has been
2498            // dropped, unless it's already done.
2499            WriteState::Open if done => {}
2500            WriteState::Open => {
2501                state.update_event(
2502                    write_handle.rep(),
2503                    match kind {
2504                        TransmitKind::Future => Event::FutureWrite {
2505                            code: ReturnCode::Dropped(ItemCount::ZERO),
2506                            pending: None,
2507                        },
2508                        TransmitKind::Stream => Event::StreamWrite {
2509                            code: ReturnCode::Dropped(ItemCount::ZERO),
2510                            pending: None,
2511                        },
2512                    },
2513                )?;
2514            }
2515
2516            // If the writer has already been dropped, then this cleans out the
2517            // state that the reader is using. If the write is host-owned then
2518            // by cleaning this out we run the host's `Drop` implementation
2519            // which notifies it of this drop.
2520            WriteState::Dropped | WriteState::HostReady { .. } => {
2521                log::trace!("host_drop_reader delete {transmit_id:?}");
2522                state.delete_transmit(transmit_id)?;
2523            }
2524        }
2525        Ok(())
2526    }
2527
2528    /// Drop the write end of a stream or future read from the host.
2529    fn host_drop_writer(
2530        &mut self,
2531        id: TableId<TransmitHandle>,
2532        on_drop_open: Option<fn() -> Result<()>>,
2533    ) -> Result<()> {
2534        let state = self.concurrent_state_mut()?;
2535        Waitable::Transmit(id).join(state, None)?;
2536        let transmit_id = state.get_mut(id)?.state;
2537        let transmit = state
2538            .get_mut(transmit_id)
2539            .with_context(|| format!("error closing writer {transmit_id:?}"))?;
2540        log::trace!(
2541            "host_drop_writer state {transmit_id:?}; read state {:?} writer state {:?}",
2542            transmit.read,
2543            transmit.write
2544        );
2545
2546        // Existing queued transmits must be updated with information for the impending writer closure
2547        match &mut transmit.write {
2548            WriteState::GuestReady { .. } => {
2549                bail_bug!("can't call `host_drop_writer` on a guest-owned writer");
2550            }
2551            WriteState::HostReady { .. } => {}
2552            v @ WriteState::Open => {
2553                if let (Some(on_drop_open), false) = (on_drop_open, transmit.done) {
2554                    on_drop_open()?;
2555                } else {
2556                    *v = WriteState::Dropped;
2557                }
2558            }
2559            WriteState::Dropped => bail_bug!("write state is already dropped"),
2560        }
2561
2562        let transmit = self.concurrent_state_mut()?.get_mut(transmit_id)?;
2563
2564        // If the existing read state is dropped, then there's nothing to read
2565        // and we can keep it that way.
2566        //
2567        // If the read state was any other state, then we must set the new state to open
2568        // to indicate that there *is* data to be read
2569        let new_state = if let ReadState::Dropped = &transmit.read {
2570            ReadState::Dropped
2571        } else {
2572            ReadState::Open
2573        };
2574
2575        let read_handle = transmit.read_handle;
2576        let done = transmit.done;
2577
2578        // Swap in the new read state
2579        match mem::replace(&mut transmit.read, new_state) {
2580            // If the guest was ready to read, then we cannot drop the reader (or writer);
2581            // we must deliver the event, and update the state associated with the handle to
2582            // represent that a read must be performed
2583            ReadState::GuestReady { ty, handle, .. } => {
2584                // Ensure the final read of the guest is queued, with appropriate closure indicator
2585                self.concurrent_state_mut()?.update_event(
2586                    read_handle.rep(),
2587                    match ty {
2588                        TransmitIndex::Future(ty) => Event::FutureRead {
2589                            code: ReturnCode::Dropped(ItemCount::ZERO),
2590                            pending: Some((ty, handle)),
2591                        },
2592                        TransmitIndex::Stream(ty) => Event::StreamRead {
2593                            code: ReturnCode::Dropped(ItemCount::ZERO),
2594                            pending: Some((ty, handle)),
2595                        },
2596                    },
2597                )?;
2598            }
2599
2600            // Notify the read-end of the drop, unless we're already done.
2601            ReadState::Open if done => {}
2602            ReadState::Open => {
2603                self.concurrent_state_mut()?.update_event(
2604                    read_handle.rep(),
2605                    match on_drop_open {
2606                        Some(_) => Event::FutureRead {
2607                            code: ReturnCode::Dropped(ItemCount::ZERO),
2608                            pending: None,
2609                        },
2610                        None => Event::StreamRead {
2611                            code: ReturnCode::Dropped(ItemCount::ZERO),
2612                            pending: None,
2613                        },
2614                    },
2615                )?;
2616            }
2617
2618            // If the read state was already dropped, then we can remove the
2619            // transmit state completely (both writer and reader have been
2620            // dropped). If the read state is host-owned then it's additionally
2621            // deleted here as a notification that the read end has gone away.
2622            // Running the host's `Drop` implementation is what notifies it of
2623            // this event.
2624            ReadState::Dropped | ReadState::HostReady { .. } | ReadState::HostToHost { .. } => {
2625                log::trace!("host_drop_writer delete {transmit_id:?}");
2626                self.concurrent_state_mut()?.delete_transmit(transmit_id)?;
2627            }
2628        }
2629        Ok(())
2630    }
2631
2632    pub(super) fn transmit_origin(&mut self, idx: HostResourceIndex) -> Result<TransmitOrigin> {
2633        let id = self.host_reader_rep(idx)?;
2634        let state = self.concurrent_state_mut()?;
2635        let state_id = state.get_mut(id)?.state;
2636        Ok(state.get_mut(state_id)?.origin)
2637    }
2638
2639    /// Insert `id` within the store, returning a `HostResourceIndex` suitable
2640    /// to re-acquire it via the `host_reader_take` and `host_reader_rep`
2641    /// methods below.
2642    fn host_reader_insert(&mut self, id: TableId<TransmitHandle>) -> Result<HostResourceIndex> {
2643        HostResourceTables::new_host(self)?.host_resource_lower_own(id.rep(), None, None)
2644    }
2645
2646    /// Removes `idx` from the store, returning the internal `id` it was
2647    /// created with.
2648    fn host_reader_take(&mut self, idx: HostResourceIndex) -> Result<TableId<TransmitHandle>> {
2649        let rep = HostResourceTables::new_host(self)?.host_resource_lift_own(idx)?;
2650        Ok(TableId::new(rep))
2651    }
2652
2653    /// Looks up `idx` within the store, returning the internal `id` it was
2654    /// created with.
2655    fn host_reader_rep(&mut self, idx: HostResourceIndex) -> Result<TableId<TransmitHandle>> {
2656        let rep = HostResourceTables::new_host(self)?.host_resource_rep(idx)?;
2657        Ok(TableId::new(rep))
2658    }
2659}
2660
2661impl<T> StoreContextMut<'_, T> {
2662    fn new_transmit<P: StreamProducer<T>>(
2663        mut self,
2664        kind: TransmitKind,
2665        producer: P,
2666    ) -> Result<HostResourceIndex>
2667    where
2668        P::Item: func::Lower,
2669    {
2670        let token = StoreToken::new(self.as_context_mut());
2671        let state = self.0.concurrent_state_mut()?;
2672        let (_, read) = state.new_transmit(TransmitOrigin::Host {
2673            typecheck: types::typecheck_payload::<P::Item>,
2674        })?;
2675        let producer = Arc::new(LockedState::new((Box::pin(producer), P::Buffer::default())));
2676        let id = state.get_mut(read)?.state;
2677        let mut dropped = false;
2678        let produce = Box::new({
2679            let producer = producer.clone();
2680            move || {
2681                let producer = producer.clone();
2682                async move {
2683                    let mut state = producer.take()?;
2684                    let (mine, buffer) = &mut *state;
2685
2686                    let (result, cancelled) = if buffer.remaining().is_empty() {
2687                        future::poll_fn(|cx| {
2688                            tls::get(|store| {
2689                                let transmit = store.concurrent_state_mut()?.get_mut(id)?;
2690
2691                                let &WriteState::HostReady { cancel, .. } = &transmit.write else {
2692                                    bail_bug!("expected WriteState::HostReady")
2693                                };
2694
2695                                let mut host_written = 0;
2696                                let mut host_buffer =
2697                                    if let ReadState::HostToHost { buffer, .. } = &mut transmit.read {
2698                                        Some(mem::take(buffer))
2699                                    } else {
2700                                        None
2701                                    };
2702
2703                                let poll = mine.as_mut().poll_produce(
2704                                    cx,
2705                                    token.as_context_mut(store),
2706                                    Destination {
2707                                        id,
2708                                        buffer,
2709                                        host_buffer: host_buffer.as_mut().map(|b| {
2710                                            HostBuffer {
2711                                                dst: b,
2712                                                marked_written: &mut host_written,
2713                                            }
2714                                        }),
2715                                        _phantom: PhantomData,
2716                                    },
2717                                    cancel,
2718                                );
2719
2720                                let transmit = store.concurrent_state_mut()?.get_mut(id)?;
2721
2722                                let host_offset = if let (
2723                                    Some(host_buffer),
2724                                    ReadState::HostToHost { buffer, limit, .. },
2725                                ) = (host_buffer, &mut transmit.read)
2726                                {
2727                                    *limit = host_written;
2728                                    *buffer = host_buffer;
2729                                    *limit
2730                                } else {
2731                                    0
2732                                };
2733
2734                                {
2735                                    let WriteState::HostReady {
2736                                        guest_offset,
2737                                        cancel,
2738                                        cancel_waker,
2739                                        ..
2740                                    } = &mut transmit.write
2741                                    else {
2742                                        bail_bug!("expected WriteState::HostReady")
2743                                    };
2744
2745                                    if poll.is_pending() {
2746                                        if !buffer.remaining().is_empty()
2747                                            || *guest_offset > 0
2748                                            || host_offset > 0
2749                                        {
2750                                            bail!(
2751                                                "StreamProducer::poll_produce returned Poll::Pending \
2752                                                 after producing at least one item"
2753                                            )
2754                                        }
2755                                        *cancel_waker = Some(cx.waker().clone());
2756                                    } else {
2757                                        *cancel_waker = None;
2758                                        *cancel = false;
2759                                    }
2760                                }
2761
2762                                Ok(poll.map(|v| v.map(|result| (result, cancel))))
2763                            })?
2764                        })
2765                            .await?
2766                    } else {
2767                        (StreamResult::Completed, false)
2768                    };
2769
2770                    let (guest_offset, host_offset, count) = tls::get(|store| {
2771                        let transmit = store.concurrent_state_mut()?.get_mut(id)?;
2772                        let (count, host_offset) = match &transmit.read {
2773                            &ReadState::GuestReady { count, .. } => (count.as_u32(), 0),
2774                            &ReadState::HostToHost { limit, .. } => (1, limit),
2775                            _ => bail_bug!("invalid read state"),
2776                        };
2777                        let guest_offset = match &transmit.write {
2778                            &WriteState::HostReady { guest_offset, .. } => guest_offset,
2779                            _ => bail_bug!("invalid write state"),
2780                        };
2781                        Ok((guest_offset, host_offset, count))
2782                    })?;
2783
2784                    let produced =
2785                        !buffer.remaining().is_empty() || guest_offset > 0 || host_offset > 0;
2786
2787                    match result {
2788                        StreamResult::Completed => {
2789                            // Only zero-length reads may complete without
2790                            // producing anything. Note that host-to-host reads
2791                            // always have a nonzero `count`.
2792                            if count > 0 && !produced {
2793                                bail!(
2794                                    "StreamProducer::poll_produce returned StreamResult::Completed \
2795                                     without producing any items"
2796                                );
2797                            }
2798                        }
2799                        StreamResult::Cancelled => {
2800                            if !cancelled {
2801                                bail!(
2802                                    "StreamProducer::poll_produce returned StreamResult::Cancelled \
2803                                     without being given a `finish` parameter value of true"
2804                                );
2805                            }
2806                            if produced {
2807                                bail!(
2808                                    "StreamProducer::poll_produce returned StreamResult::Cancelled \
2809                                     after producing at least one item"
2810                                );
2811                            }
2812                        }
2813                        StreamResult::Dropped => {
2814                            dropped = true;
2815                        }
2816                    }
2817
2818                    let write_buffer = !buffer.remaining().is_empty() || host_offset > 0;
2819
2820                    drop(state);
2821
2822                    if write_buffer {
2823                        write(token, id, producer.clone(), kind).await?;
2824                    }
2825
2826                    Ok(if dropped {
2827                        if producer.with(|p| p.1.remaining().is_empty())?  {
2828                            StreamResult::Dropped
2829                        } else {
2830                            StreamResult::Completed
2831                        }
2832                    } else {
2833                        result
2834                    })
2835                }
2836                .boxed()
2837            }
2838        });
2839        let try_into = Box::new(move |ty| {
2840            let (mine, buffer) = producer.try_lock().ok()?.take()?;
2841            match P::try_into(mine, ty) {
2842                Ok(value) => Some(value),
2843                Err(mine) => {
2844                    *producer.try_lock().ok()? = Some((mine, buffer));
2845                    None
2846                }
2847            }
2848        });
2849        state.get_mut(id)?.write = WriteState::HostReady {
2850            produce,
2851            try_into,
2852            guest_offset: ItemCount::ZERO,
2853            cancel: false,
2854            cancel_waker: None,
2855        };
2856        self.0.host_reader_insert(read)
2857    }
2858
2859    fn set_consumer<C: StreamConsumer<T>>(
2860        mut self,
2861        idx: HostResourceIndex,
2862        kind: TransmitKind,
2863        consumer: C,
2864    ) -> Result<()> {
2865        let token = StoreToken::new(self.as_context_mut());
2866        let id = self.0.host_reader_take(idx)?;
2867        let state = self.0.concurrent_state_mut()?;
2868        let id = state.get_mut(id)?.state;
2869        let transmit = state.get_mut(id)?;
2870        let consumer = Arc::new(LockedState::new(Box::pin(consumer)));
2871        let consume_with_buffer = {
2872            let consumer = consumer.clone();
2873            async move |mut host_buffer: Option<&mut dyn WriteBuffer<C::Item>>| {
2874                let mut mine = consumer.take()?;
2875
2876                let host_buffer_remaining_before =
2877                    host_buffer.as_deref_mut().map(|v| v.remaining().len());
2878
2879                let (result, cancelled) = future::poll_fn(|cx| {
2880                    tls::get(|store| {
2881                        let cancel = match &store.concurrent_state_mut()?.get_mut(id)?.read {
2882                            &ReadState::HostReady { cancel, .. } => cancel,
2883                            ReadState::Open => false,
2884                            _ => bail_bug!("unexpected read state"),
2885                        };
2886
2887                        let poll = mine.as_mut().poll_consume(
2888                            cx,
2889                            token.as_context_mut(store),
2890                            Source {
2891                                id,
2892                                host_buffer: host_buffer.as_deref_mut(),
2893                            },
2894                            cancel,
2895                        );
2896
2897                        if let ReadState::HostReady {
2898                            cancel_waker,
2899                            cancel,
2900                            ..
2901                        } = &mut store.concurrent_state_mut()?.get_mut(id)?.read
2902                        {
2903                            if poll.is_pending() {
2904                                *cancel_waker = Some(cx.waker().clone());
2905                            } else {
2906                                *cancel_waker = None;
2907                                *cancel = false;
2908                            }
2909                        }
2910
2911                        Ok(poll.map(|v| v.map(|result| (result, cancel))))
2912                    })?
2913                })
2914                .await?;
2915
2916                let (guest_offset, count) = tls::get(|store| {
2917                    let transmit = store.concurrent_state_mut()?.get_mut(id)?;
2918                    Ok((
2919                        match &transmit.read {
2920                            &ReadState::HostReady { guest_offset, .. } => guest_offset,
2921                            ReadState::Open => ItemCount::ZERO,
2922                            _ => bail_bug!("invalid read state"),
2923                        },
2924                        match &transmit.write {
2925                            WriteState::GuestReady { count, .. } => count.as_usize(),
2926                            WriteState::HostReady { .. } => match host_buffer_remaining_before {
2927                                Some(n) => n,
2928                                None => bail_bug!("host_buffer_remaining_before should be set"),
2929                            },
2930                            _ => bail_bug!("invalid write state"),
2931                        },
2932                    ))
2933                })?;
2934
2935                match result {
2936                    StreamResult::Completed => {
2937                        // Progress for a host writer is tracked by its buffer
2938                        // shrinking, whereas for a guest writer it's tracked
2939                        // in `guest_offset`.
2940                        let consumed = match (host_buffer_remaining_before, host_buffer) {
2941                            (Some(before), Some(after)) => before != after.remaining().len(),
2942                            _ => guest_offset > 0,
2943                        };
2944                        if count > 0 && !consumed {
2945                            bail!(
2946                                "StreamConsumer::poll_consume returned StreamResult::Completed \
2947                                 without consuming any items"
2948                            );
2949                        }
2950
2951                        if let TransmitKind::Future = kind {
2952                            tls::get(|store| {
2953                                store.concurrent_state_mut()?.get_mut(id)?.done = true;
2954                                crate::error::Ok(())
2955                            })?;
2956                        }
2957                    }
2958                    StreamResult::Cancelled => {
2959                        if !cancelled {
2960                            bail!(
2961                                "StreamConsumer::poll_consume returned StreamResult::Cancelled \
2962                                 without being given a `finish` parameter value of true"
2963                            );
2964                        }
2965                    }
2966                    StreamResult::Dropped => {}
2967                }
2968
2969                Ok(result)
2970            }
2971        };
2972        let consume = {
2973            let consume = consume_with_buffer.clone();
2974            Box::new(move || {
2975                let consume = consume.clone();
2976                async move { consume(None).await }.boxed()
2977            })
2978        };
2979
2980        match &transmit.write {
2981            WriteState::Open => {
2982                transmit.read = ReadState::HostReady {
2983                    consume,
2984                    guest_offset: ItemCount::ZERO,
2985                    cancel: false,
2986                    cancel_waker: None,
2987                };
2988            }
2989            &WriteState::GuestReady { .. } => {
2990                // If the guest writer has a pending event, then don't start
2991                // another read event here even if there's some partial data
2992                // available. Wait for that to be delivered and wait for the
2993                // writer to do something else before a read is triggered.
2994                let write_handle = transmit.write_handle;
2995                let write_has_event = Waitable::Transmit(write_handle)
2996                    .common(state)?
2997                    .event
2998                    .is_some();
2999                let future = if write_has_event {
3000                    None
3001                } else {
3002                    Some(consume())
3003                };
3004                state.get_mut(id)?.read = ReadState::HostReady {
3005                    consume,
3006                    guest_offset: ItemCount::ZERO,
3007                    cancel: false,
3008                    cancel_waker: None,
3009                };
3010                if let Some(future) = future {
3011                    self.0.pipe_from_guest(kind, id, future);
3012                }
3013            }
3014            WriteState::HostReady { .. } => {
3015                let WriteState::HostReady { produce, .. } = mem::replace(
3016                    &mut transmit.write,
3017                    WriteState::HostReady {
3018                        produce: Box::new(|| {
3019                            Box::pin(async { bail_bug!("unexpected invocation of `produce`") })
3020                        }),
3021                        try_into: Box::new(|_| None),
3022                        guest_offset: ItemCount::ZERO,
3023                        cancel: false,
3024                        cancel_waker: None,
3025                    },
3026                ) else {
3027                    bail_bug!("expected WriteState::HostReady")
3028                };
3029
3030                transmit.read = ReadState::HostToHost {
3031                    accept: Box::new(move |input| {
3032                        let consume = consume_with_buffer.clone();
3033                        async move { consume(Some(input.get_mut::<C::Item>()?)).await }.boxed()
3034                    }),
3035                    buffer: Vec::new(),
3036                    limit: 0,
3037                };
3038
3039                let future = async move {
3040                    loop {
3041                        if tls::get(|store| {
3042                            crate::error::Ok(matches!(
3043                                store.concurrent_state_mut()?.get_mut(id)?.read,
3044                                ReadState::Dropped
3045                            ))
3046                        })? {
3047                            break Ok(());
3048                        }
3049
3050                        match produce().await? {
3051                            StreamResult::Completed | StreamResult::Cancelled => {}
3052                            StreamResult::Dropped => break Ok(()),
3053                        }
3054
3055                        if let TransmitKind::Future = kind {
3056                            break Ok(());
3057                        }
3058                    }
3059                }
3060                .map(move |result| {
3061                    tls::get(|store| store.concurrent_state_mut()?.delete_transmit(id))?;
3062                    result
3063                });
3064
3065                state.push_future(Box::pin(future));
3066            }
3067            WriteState::Dropped => {
3068                let reader = transmit.read_handle;
3069                self.0.host_drop_reader(reader, kind)?;
3070            }
3071        }
3072        Ok(())
3073    }
3074}
3075
3076async fn write<D: 'static, P: Send + 'static, T: func::Lower + 'static, B: WriteBuffer<T>>(
3077    token: StoreToken<D>,
3078    id: TableId<TransmitState>,
3079    pair: Arc<LockedState<(P, B)>>,
3080    kind: TransmitKind,
3081) -> Result<()> {
3082    let (read, guest_offset) = tls::get(|store| {
3083        let transmit = store.concurrent_state_mut()?.get_mut(id)?;
3084
3085        let guest_offset = if let &WriteState::HostReady { guest_offset, .. } = &transmit.write {
3086            Some(guest_offset)
3087        } else {
3088            None
3089        };
3090
3091        crate::error::Ok((
3092            mem::replace(&mut transmit.read, ReadState::Open),
3093            guest_offset,
3094        ))
3095    })?;
3096
3097    match read {
3098        ReadState::GuestReady {
3099            ty,
3100            flat_abi,
3101            options,
3102            address,
3103            count,
3104            handle,
3105            instance,
3106            caller_instance,
3107            caller_thread,
3108        } => {
3109            let guest_offset = match guest_offset {
3110                Some(i) => i,
3111                None => bail_bug!("guest_offset should be present if ready"),
3112            };
3113
3114            if let TransmitKind::Future = kind {
3115                tls::get(|store| {
3116                    store.concurrent_state_mut()?.get_mut(id)?.done = true;
3117                    crate::error::Ok(())
3118                })?;
3119            }
3120
3121            let old_remaining = pair.with(|p| p.1.remaining().len())?;
3122            let accept = {
3123                let pair = pair.clone();
3124                move |mut store: StoreContextMut<D>| {
3125                    let mut state = pair.take()?;
3126                    lower::<T, B, D>(
3127                        store.as_context_mut(),
3128                        instance,
3129                        caller_thread,
3130                        options,
3131                        ty,
3132                        address + (T::SIZE32 * guest_offset.as_usize()),
3133                        count.as_usize() - guest_offset.as_usize(),
3134                        &mut state.1,
3135                    )?;
3136                    crate::error::Ok(())
3137                }
3138            };
3139
3140            if guest_offset < count {
3141                if T::MAY_REQUIRE_REALLOC {
3142                    // For payloads which may require a realloc call, use a
3143                    // oneshot::channel and background task.  This is
3144                    // necessary because calling the guest while there are
3145                    // host embedder frames on the stack is unsound.
3146                    let (tx, rx) = oneshot::channel();
3147                    tls::get(move |store| {
3148                        store
3149                            .concurrent_state_mut()?
3150                            .push_high_priority(WorkItem::WorkerFunction(AlwaysMut::new(
3151                                Box::new(move |store| {
3152                                    _ = tx.send(accept(token.as_context_mut(store))?);
3153                                    Ok(())
3154                                }),
3155                            )));
3156                        crate::error::Ok(())
3157                    })?;
3158                    match rx.await {
3159                        Ok(r) => r,
3160                        // The worker function was dropped without sending a
3161                        // result, which can happen when lowering trapped. This
3162                        // isn't a bug but this specific handling here might be
3163                        // the last hurray of this task in the event queue, so
3164                        // don't kill anything other than our caller. The
3165                        // original trap should make its way back to the best
3166                        // location naturally.
3167                        Err(oneshot::Canceled) => {
3168                            bail!("stream write cancelled before it could complete")
3169                        }
3170                    }
3171                } else {
3172                    // Optimize flat payloads (i.e. those which do not
3173                    // require calling the guest's realloc function) by
3174                    // lowering directly instead of using a oneshot::channel
3175                    // and background task.
3176                    tls::get(|store| accept(token.as_context_mut(store)))?
3177                }
3178            }
3179
3180            tls::get(|store| {
3181                let count = old_remaining - pair.with(|p| p.1.remaining().len())?;
3182
3183                let transmit = store.concurrent_state_mut()?.get_mut(id)?;
3184
3185                let WriteState::HostReady { guest_offset, .. } = &mut transmit.write else {
3186                    bail_bug!("expected WriteState::HostReady")
3187                };
3188
3189                guest_offset.inc(count)?;
3190
3191                transmit.read = ReadState::GuestReady {
3192                    ty,
3193                    flat_abi,
3194                    options,
3195                    address,
3196                    count: ItemCount::new_usize(count)?,
3197                    handle,
3198                    instance,
3199                    caller_instance,
3200                    caller_thread,
3201                };
3202
3203                crate::error::Ok(())
3204            })?;
3205
3206            Ok(())
3207        }
3208
3209        ReadState::HostToHost {
3210            accept,
3211            mut buffer,
3212            limit,
3213        } => {
3214            let mut state = StreamResult::Completed;
3215            let mut position = 0;
3216
3217            while !matches!(state, StreamResult::Dropped) && position < limit {
3218                let mut slice_buffer = SliceBuffer::new(buffer, position, limit);
3219                state = accept(&mut UntypedWriteBuffer::new(&mut slice_buffer)).await?;
3220                (buffer, position, _) = slice_buffer.into_parts();
3221            }
3222
3223            {
3224                let mut pair = pair.take()?;
3225                let (_, buffer) = &mut *pair;
3226
3227                while !(matches!(state, StreamResult::Dropped) || buffer.remaining().is_empty()) {
3228                    state = accept(&mut UntypedWriteBuffer::new(buffer)).await?;
3229                }
3230            }
3231
3232            tls::get(|store| {
3233                store.concurrent_state_mut()?.get_mut(id)?.read = match state {
3234                    StreamResult::Dropped => ReadState::Dropped,
3235                    StreamResult::Completed | StreamResult::Cancelled => ReadState::HostToHost {
3236                        accept,
3237                        buffer,
3238                        limit: 0,
3239                    },
3240                };
3241
3242                crate::error::Ok(())
3243            })?;
3244            Ok(())
3245        }
3246
3247        _ => bail_bug!("unexpected read state"),
3248    }
3249}
3250
3251/// Polls a `StreamProducer` or `StreamConsumer` future once, inline, from
3252/// within a guest's `{stream,future}.{read,write}` intrinsic.
3253///
3254/// The producer or consumer is embedder code which doesn't belong to the
3255/// reading or writing guest's task, so it's polled as though from the
3256/// top-level host, just as it is when it's later polled from the event loop.
3257fn poll_inline(
3258    store: &mut dyn VMStore,
3259    future: &mut Pin<Box<dyn Future<Output = Result<StreamResult>> + Send + 'static>>,
3260) -> Result<Poll<Result<StreamResult>>> {
3261    let old_thread = store.set_thread(CurrentThread::None)?;
3262    let poll = tls::set(store, || {
3263        future
3264            .as_mut()
3265            .poll(&mut Context::from_waker(&Waker::noop()))
3266    });
3267    store.set_thread(old_thread)?;
3268    Ok(poll)
3269}
3270
3271impl Instance {
3272    /// Handle a guest-initiated write by delivering the item(s) to the
3273    /// `StreamConsumer` for the specified stream or future.
3274    fn consume(
3275        self,
3276        store: &mut dyn VMStore,
3277        kind: TransmitKind,
3278        transmit_id: TableId<TransmitState>,
3279        consume: PollStream,
3280        guest_offset: ItemCount,
3281        cancel: bool,
3282    ) -> Result<ReturnCode> {
3283        let mut future = consume();
3284        store.concurrent_state_mut()?.get_mut(transmit_id)?.read = ReadState::HostReady {
3285            consume,
3286            guest_offset,
3287            cancel,
3288            cancel_waker: None,
3289        };
3290        let poll = poll_inline(store, &mut future)?;
3291
3292        Ok(match poll {
3293            Poll::Ready(state) => {
3294                let transmit = store.concurrent_state_mut()?.get_mut(transmit_id)?;
3295                let code = settle_host_read(transmit, kind, state?)?;
3296                transmit.write = WriteState::Open;
3297                code
3298            }
3299            Poll::Pending => {
3300                store.pipe_from_guest(kind, transmit_id, future);
3301                ReturnCode::Blocked
3302            }
3303        })
3304    }
3305
3306    /// Handle a guest-initiated read by polling the `StreamProducer` for the
3307    /// specified stream or future for items.
3308    fn produce(
3309        self,
3310        store: &mut dyn VMStore,
3311        kind: TransmitKind,
3312        transmit_id: TableId<TransmitState>,
3313        produce: PollStream,
3314        try_into: TryInto,
3315        guest_offset: ItemCount,
3316        cancel: bool,
3317    ) -> Result<ReturnCode> {
3318        let mut future = produce();
3319        store.concurrent_state_mut()?.get_mut(transmit_id)?.write = WriteState::HostReady {
3320            produce,
3321            try_into,
3322            guest_offset,
3323            cancel,
3324            cancel_waker: None,
3325        };
3326        let poll = poll_inline(store, &mut future)?;
3327
3328        Ok(match poll {
3329            Poll::Ready(state) => {
3330                let transmit = store.concurrent_state_mut()?.get_mut(transmit_id)?;
3331                let code = settle_host_write(transmit, kind, state?)?;
3332                transmit.read = ReadState::Open;
3333                code
3334            }
3335            Poll::Pending => {
3336                store.pipe_to_guest(kind, transmit_id, future);
3337                ReturnCode::Blocked
3338            }
3339        })
3340    }
3341
3342    /// Drop the writable end of the specified stream or future from the guest.
3343    pub(super) fn guest_drop_writable(
3344        self,
3345        store: &mut StoreOpaque,
3346        ty: TransmitIndex,
3347        writer: u32,
3348    ) -> Result<()> {
3349        let (instance, counter) = self.id().get_mut_and_handle_counter(store);
3350        let table = instance.table_for_transmit(ty);
3351        let (transmit_rep, is_done) = match ty {
3352            TransmitIndex::Future(ty) => table.future_remove_writable(counter, ty, writer)?,
3353            TransmitIndex::Stream(ty) => {
3354                (table.stream_remove_writable(counter, ty, writer)?, false)
3355            }
3356        };
3357
3358        let id = TableId::<TransmitHandle>::new(transmit_rep);
3359        log::trace!("guest_drop_writable: drop writer {id:?}");
3360        match ty {
3361            TransmitIndex::Stream(_) => store.host_drop_writer(id, None),
3362            TransmitIndex::Future(_) => store.host_drop_writer(
3363                id,
3364                if is_done {
3365                    None
3366                } else {
3367                    Some(|| {
3368                        Err(format_err!(
3369                            "cannot drop future write end without first writing a value"
3370                        ))
3371                    })
3372                },
3373            ),
3374        }
3375    }
3376
3377    /// Copy `count` items from `read_address` to `write_address` for the
3378    /// specified stream or future.
3379    fn copy<T: 'static>(
3380        store: StoreContextMut<T>,
3381        flat_abi: Option<FlatAbi>,
3382        write_runtime_instance: RuntimeInstance,
3383        write_ty: TransmitIndex,
3384        write_options: OptionsIndex,
3385        write_address: usize,
3386        read_runtime_instance: RuntimeInstance,
3387        read_caller_thread: QualifiedThreadId,
3388        read_ty: TransmitIndex,
3389        read_options: OptionsIndex,
3390        read_address: usize,
3391        count: ItemCount,
3392        rep: u32,
3393    ) -> Result<()> {
3394        let write_instance = Instance::from_runtime_instance(store.0, write_runtime_instance);
3395        let read_instance = Instance::from_runtime_instance(store.0, read_runtime_instance);
3396        let (write_component, store) = write_instance.component_and_store_mut(store.0);
3397        let (read_component, mut store) = read_instance.component_and_store_mut(store);
3398        let write_types = write_component.types();
3399        let read_types = read_component.types();
3400        let count = count.as_usize();
3401
3402        // Validate `write_ty` w.r.t. `write_address` to ensure it's properly
3403        // aligned and in-bounds.
3404        //
3405        // FIXME(#4311): this and the rest of this function use the 32-bit
3406        // layout of payloads, which needs memory64 handling.
3407        let write_payload_ty = write_ty.payload(write_types);
3408        let write_abi = match write_payload_ty {
3409            Some(ty) => write_types.canonical_abi(ty),
3410            None => &CanonicalAbiInfo::ZERO,
3411        };
3412        let write_length_in_bytes = match flat_abi {
3413            Some(abi) => usize::try_from(abi.size)? * count,
3414            None => usize::try_from(write_abi.size32)? * count,
3415        };
3416        if write_length_in_bytes > 0 {
3417            if write_address % usize::try_from(write_abi.align32)? != 0 {
3418                bail!("write pointer not aligned");
3419            }
3420            write_instance
3421                .options_memory(store, write_options)
3422                .get(write_address..)
3423                .and_then(|b| b.get(..write_length_in_bytes))
3424                .ok_or_else(|| crate::format_err!("write pointer out of bounds"))?;
3425        }
3426
3427        let read_payload_ty = read_ty.payload(read_types);
3428        let read_abi = match read_payload_ty {
3429            Some(ty) => read_types.canonical_abi(ty),
3430            None => &CanonicalAbiInfo::ZERO,
3431        };
3432        let read_length_in_bytes = match flat_abi {
3433            Some(abi) => usize::try_from(abi.size)? * count,
3434            None => usize::try_from(read_abi.size32)? * count,
3435        };
3436        if read_length_in_bytes > 0 {
3437            if read_address % usize::try_from(read_abi.align32)? != 0 {
3438                bail!("read pointer not aligned");
3439            }
3440            read_instance
3441                .options_memory(store, read_options)
3442                .get(read_address..)
3443                .and_then(|b| b.get(..read_length_in_bytes))
3444                .ok_or_else(|| crate::format_err!("read pointer out of bounds"))?;
3445        }
3446
3447        if write_runtime_instance == read_runtime_instance
3448            && !allow_intra_component_read_write(write_payload_ty)
3449        {
3450            bail!(
3451                "cannot read from and write to intra-component future/stream with non-numeric payload"
3452            )
3453        }
3454
3455        match (write_ty, read_ty) {
3456            (TransmitIndex::Future(_), TransmitIndex::Future(_)) => {
3457                if count != 1 {
3458                    bail_bug!("futures can only send 1 item");
3459                }
3460
3461                let val = write_payload_ty
3462                    .map(|ty| {
3463                        let lift = &mut LiftContext::new(store, write_options, write_instance)?;
3464                        let bytes = &lift.memory()[write_address..][..write_length_in_bytes];
3465                        Val::load(lift, *ty, bytes)
3466                    })
3467                    .transpose()?;
3468
3469                if let Some(val) = val {
3470                    // Serializing the value may require calling the guest's realloc function, so we
3471                    // set the guest's thread context in case realloc requires it, and restore the original
3472                    // thread context after the copy is complete.
3473                    let old_thread = store.set_thread(read_caller_thread)?;
3474                    let lower =
3475                        &mut LowerContext::new(store.as_context_mut(), read_options, read_instance);
3476                    let ptr = func::validate_inbounds_dynamic(
3477                        read_abi,
3478                        lower.as_slice_mut(),
3479                        &ValRaw::u32(read_address.try_into()?),
3480                    )?;
3481                    let ty = match read_payload_ty {
3482                        Some(ty) => ty,
3483                        None => bail_bug!("expected read payload type to be present"),
3484                    };
3485                    val.store(lower, *ty, ptr)?;
3486                    store.set_thread(old_thread)?;
3487                }
3488            }
3489            (TransmitIndex::Stream(_), TransmitIndex::Stream(_)) => {
3490                if write_length_in_bytes == 0 {
3491                    return Ok(());
3492                }
3493                let write_payload_ty = match write_payload_ty {
3494                    Some(ty) => ty,
3495                    None => bail_bug!("expected write payload type to be present"),
3496                };
3497                let read_payload_ty = match read_payload_ty {
3498                    Some(ty) => ty,
3499                    None => bail_bug!("expected read payload type to be present"),
3500                };
3501                if flat_abi.is_some() {
3502                    // Fast path memcpy for "flat" (i.e. no pointers or handles) payloads:
3503                    let store_opaque = store.store_opaque_mut();
3504
3505                    assert_eq!(read_length_in_bytes, write_length_in_bytes);
3506
3507                    if read_instance
3508                        .options_memory(store_opaque, read_options)
3509                        .as_ptr()
3510                        == write_instance
3511                            .options_memory(store_opaque, write_options)
3512                            .as_ptr()
3513                    {
3514                        let memory = read_instance.options_memory_mut(store_opaque, read_options);
3515                        memory.copy_within(
3516                            write_address..write_address + write_length_in_bytes,
3517                            read_address,
3518                        );
3519                    } else {
3520                        let src = write_instance.options_memory(store_opaque, write_options)
3521                            [write_address..][..write_length_in_bytes]
3522                            .as_ptr();
3523                        let dst = read_instance.options_memory_mut(store_opaque, read_options)
3524                            [read_address..][..read_length_in_bytes]
3525                            .as_mut_ptr();
3526
3527                        // SAFETY: Both `src` and `dst` have been validated
3528                        // above to be valid pointers as they're derived from
3529                        // slices that have the desired length with the desired
3530                        // read/write permission. The `unsafe` bit here is that
3531                        // the memories are disjoint (different base pointers)
3532                        // and there's no easy way to borrow both
3533                        // simultaneously from the store. Different memories
3534                        // are guaranteed to be disjoint, however, so the
3535                        // `unsafe` here should be ok.
3536                        unsafe {
3537                            src.copy_to_nonoverlapping(dst, write_length_in_bytes);
3538                        }
3539                    }
3540                } else {
3541                    let store_opaque = store.store_opaque_mut();
3542                    let lift = &mut LiftContext::new(store_opaque, write_options, write_instance)?;
3543                    let bytes = &lift.memory()[write_address..][..write_length_in_bytes];
3544                    lift.consume_fuel_array(count, size_of::<Val>())?;
3545
3546                    let values = (0..count)
3547                        .map(|index| {
3548                            let size = usize::try_from(write_abi.size32)?;
3549                            Val::load(lift, *write_payload_ty, &bytes[(index * size)..][..size])
3550                        })
3551                        .collect::<Result<Vec<_>>>()?;
3552
3553                    let id = TableId::<TransmitHandle>::new(rep);
3554                    log::trace!("copy values {values:?} for {id:?}");
3555
3556                    // Serializing the value may require calling the guest's realloc function, so we
3557                    // set the guest's thread context in case realloc requires it, and restore the original
3558                    // thread context after the copy is complete.
3559                    let old_thread = store.set_thread(read_caller_thread)?;
3560                    let lower =
3561                        &mut LowerContext::new(store.as_context_mut(), read_options, read_instance);
3562                    let mut ptr = read_address;
3563                    for value in values {
3564                        value.store(lower, *read_payload_ty, ptr)?;
3565                        ptr += usize::try_from(read_abi.size32)?;
3566                    }
3567                    store.set_thread(old_thread)?;
3568                }
3569            }
3570            _ => bail_bug!("mismatched transmit types in copy"),
3571        }
3572
3573        Ok(())
3574    }
3575
3576    fn check_bounds(
3577        self,
3578        store: &StoreOpaque,
3579        options: OptionsIndex,
3580        ty: TransmitIndex,
3581        address: usize,
3582        count: usize,
3583    ) -> Result<()> {
3584        let types = self.id().get(store).component().types();
3585        let payload = match ty {
3586            TransmitIndex::Future(ty) => types[types[ty].ty].payload,
3587            TransmitIndex::Stream(ty) => types[types[ty].ty].payload,
3588        };
3589        let Some(payload) = payload else {
3590            return Ok(());
3591        };
3592        // As-written the spec currently exempts zero-length reads/writes from
3593        // bounds/alignment checks.
3594        if count == 0 {
3595            return Ok(());
3596        }
3597        let abi = types.canonical_abi(&payload);
3598        // FIXME(#4311): needs memory64 handling
3599        let size = usize::try_from(abi.size32)?;
3600        let align = usize::try_from(abi.align32)?;
3601        if address % align != 0 {
3602            bail!("buffer pointer not aligned");
3603        }
3604        self.options_memory(store, options)
3605            .get(address..)
3606            .and_then(|b| b.get(..size.checked_mul(count)?))
3607            .map(drop)
3608            .ok_or_else(|| crate::format_err!("buffer pointer out of bounds of memory"))
3609    }
3610
3611    /// Write to the specified stream or future from the guest.
3612    pub(super) fn guest_write<T: 'static>(
3613        self,
3614        mut store: StoreContextMut<T>,
3615        caller: RuntimeComponentInstanceIndex,
3616        ty: TransmitIndex,
3617        options: OptionsIndex,
3618        flat_abi: Option<FlatAbi>,
3619        handle: u32,
3620        address: u32,
3621        count: u32,
3622    ) -> Result<ReturnCode> {
3623        let count = ItemCount::new(count)?;
3624
3625        let address = usize::try_from(address)?;
3626        self.check_bounds(store.0, options, ty, address, count.as_usize())?;
3627        let async_ = self.options(store.0, options).async_;
3628        let (rep, state) = self.id().get_mut(store.0).get_mut_by_index(ty, handle)?;
3629        let TransmitLocalState::Write { done } = *state else {
3630            bail!(Trap::ConcurrentFutureStreamOp);
3631        };
3632
3633        *state = TransmitLocalState::Busy;
3634        let transmit_handle = TableId::<TransmitHandle>::new(rep);
3635        let concurrent_state = store.0.concurrent_state_mut()?;
3636        let transmit_id = concurrent_state.get_mut(transmit_handle)?.state;
3637        let transmit = concurrent_state.get_mut(transmit_id)?;
3638        log::trace!(
3639            "guest_write {count} to {transmit_handle:?} (handle {handle}; state {transmit_id:?}); {:?}",
3640            transmit.read
3641        );
3642
3643        if done || transmit.done {
3644            bail!(match ty {
3645                TransmitIndex::Future(_) => Trap::WriteToDroppedFuture,
3646                TransmitIndex::Stream(_) => Trap::WriteToDroppedStream,
3647            });
3648        }
3649
3650        if !async_ {
3651            Waitable::Transmit(transmit_handle).trap_if_in_waitable_set(concurrent_state)?;
3652        }
3653        let transmit = concurrent_state.get_mut(transmit_id)?;
3654
3655        let new_state = if let ReadState::Dropped = &transmit.read {
3656            ReadState::Dropped
3657        } else {
3658            ReadState::Open
3659        };
3660
3661        let set_guest_ready = |me: &mut ConcurrentState| {
3662            let transmit = me.get_mut(transmit_id)?;
3663            if !matches!(&transmit.write, WriteState::Open) {
3664                bail_bug!("expected `WriteState::Open`; got `{:?}`", transmit.write);
3665            }
3666            transmit.write = WriteState::GuestReady {
3667                instance: self,
3668                caller,
3669                ty,
3670                flat_abi,
3671                options,
3672                address,
3673                count,
3674                handle,
3675            };
3676            Ok::<_, crate::Error>(())
3677        };
3678
3679        let mut result = match mem::replace(&mut transmit.read, new_state) {
3680            ReadState::GuestReady {
3681                ty: read_ty,
3682                flat_abi: read_flat_abi,
3683                options: read_options,
3684                address: read_address,
3685                count: read_count,
3686                handle: read_handle,
3687                instance: read_instance,
3688                caller_instance: read_caller_instance,
3689                caller_thread: read_caller_thread,
3690            } => {
3691                if flat_abi != read_flat_abi {
3692                    bail_bug!("expected flat ABI calculations to be the same");
3693                }
3694
3695                if let TransmitIndex::Future(_) = ty {
3696                    transmit.done = true;
3697                }
3698
3699                // Note that zero-length reads and writes are handling specially
3700                // by the spec to allow each end to signal readiness to the
3701                // other.  Quoting the spec:
3702                //
3703                // ```
3704                // The meaning of a read or write when the length is 0 is that
3705                // the caller is querying the "readiness" of the other
3706                // side. When a 0-length read/write rendezvous with a
3707                // non-0-length read/write, only the 0-length read/write
3708                // completes; the non-0-length read/write is kept pending (and
3709                // ready for a subsequent rendezvous).
3710                //
3711                // In the corner case where a 0-length read and write
3712                // rendezvous, only the writer is notified of readiness. To
3713                // avoid livelock, the Canonical ABI requires that a writer must
3714                // (eventually) follow a completed 0-length write with a
3715                // non-0-length write that is allowed to block (allowing the
3716                // reader end to run and rendezvous with its own non-0-length
3717                // read).
3718                // ```
3719
3720                let write_count = count;
3721                let write_complete = count == 0 || read_count > 0;
3722                let read_complete = count > 0;
3723                let read_buffer_remaining = count < read_count;
3724
3725                let read_handle_rep = transmit.read_handle.rep();
3726
3727                let count = count.min(read_count);
3728
3729                Instance::copy(
3730                    store.as_context_mut(),
3731                    flat_abi,
3732                    self.runtime_instance(caller),
3733                    ty,
3734                    options,
3735                    address,
3736                    read_instance.runtime_instance(read_caller_instance),
3737                    read_caller_thread,
3738                    read_ty,
3739                    read_options,
3740                    read_address,
3741                    count,
3742                    rep,
3743                )?;
3744
3745                let instance = read_instance.id().get(store.0);
3746                let types = instance.component().types();
3747                // FIXME(#4311): needs memory64 handling
3748                let item_size = match read_ty.payload(types) {
3749                    Some(ty) => usize::try_from(types.canonical_abi(ty).size32)?,
3750                    None => 0,
3751                };
3752                let concurrent_state = store.0.concurrent_state_mut()?;
3753                if read_complete {
3754                    let total = if let Some(Event::StreamRead {
3755                        code: ReturnCode::Completed(old_total),
3756                        ..
3757                    }) = concurrent_state.take_event(read_handle_rep)?
3758                    {
3759                        count.add(old_total)?
3760                    } else {
3761                        count
3762                    };
3763
3764                    let code = ReturnCode::completed(ty.kind(), total);
3765
3766                    concurrent_state.send_read_result(read_ty, transmit_id, read_handle, code)?;
3767                }
3768
3769                // If the reader still has buffer remaining, or if this was a
3770                // zero-length rendezvous, then restore the state of the reader
3771                // back to what it was when we found it. Note that for the
3772                // zero-length rendezvous case this specifically won't execute
3773                // the `read_complete` logic above, which is intentional, as the
3774                // reader remains blocked.
3775                if read_buffer_remaining || (write_count == 0 && read_count == 0) {
3776                    let transmit = concurrent_state.get_mut(transmit_id)?;
3777                    transmit.read = ReadState::GuestReady {
3778                        ty: read_ty,
3779                        flat_abi: read_flat_abi,
3780                        options: read_options,
3781                        address: read_address + (count.as_usize() * item_size),
3782                        count: read_count.sub(count)?,
3783                        handle: read_handle,
3784                        instance: read_instance,
3785                        caller_instance: read_caller_instance,
3786                        caller_thread: read_caller_thread,
3787                    };
3788                }
3789
3790                if write_complete {
3791                    ReturnCode::completed(ty.kind(), count)
3792                } else {
3793                    set_guest_ready(concurrent_state)?;
3794                    ReturnCode::Blocked
3795                }
3796            }
3797
3798            ReadState::HostReady {
3799                consume,
3800                guest_offset,
3801                cancel,
3802                cancel_waker,
3803            } => {
3804                if cancel_waker.is_some() {
3805                    bail_bug!("expected cancel_waker to be none");
3806                }
3807                if cancel {
3808                    bail_bug!("expected cancel to be false");
3809                }
3810                if guest_offset != 0 {
3811                    bail_bug!("expected guest_offset to be 0");
3812                }
3813
3814                set_guest_ready(concurrent_state)?;
3815                self.consume(
3816                    store.0,
3817                    ty.kind(),
3818                    transmit_id,
3819                    consume,
3820                    ItemCount::ZERO,
3821                    false,
3822                )?
3823            }
3824
3825            ReadState::HostToHost { .. } => bail_bug!("unexpected HostToHost"),
3826
3827            ReadState::Open => {
3828                set_guest_ready(concurrent_state)?;
3829                ReturnCode::Blocked
3830            }
3831
3832            ReadState::Dropped => {
3833                if let TransmitIndex::Future(_) = ty {
3834                    transmit.done = true;
3835                }
3836
3837                match Waitable::Transmit(transmit_handle).take_event(concurrent_state)? {
3838                    Some(
3839                        Event::StreamWrite {
3840                            code: ReturnCode::Dropped(ItemCount::ZERO),
3841                            ..
3842                        }
3843                        | Event::FutureWrite {
3844                            code: ReturnCode::Dropped(ItemCount::ZERO),
3845                            ..
3846                        },
3847                    ) => {}
3848                    event => bail_bug!("expected pending dropped event for writer; got {event:?}"),
3849                }
3850
3851                ReturnCode::Dropped(ItemCount::ZERO)
3852            }
3853        };
3854
3855        if result == ReturnCode::Blocked && !async_ {
3856            result = self.wait_for_write(store.0, caller, transmit_handle)?;
3857        }
3858
3859        if result != ReturnCode::Blocked {
3860            *self.id().get_mut(store.0).get_mut_by_index(ty, handle)?.1 =
3861                TransmitLocalState::Write {
3862                    done: matches!(result, ReturnCode::Dropped(_)),
3863                };
3864        }
3865
3866        log::trace!(
3867            "guest_write result for {transmit_handle:?} (handle {handle}; state {transmit_id:?}): {result:?}",
3868        );
3869
3870        Ok(result)
3871    }
3872
3873    /// Read from the specified stream or future from the guest.
3874    pub(super) fn guest_read<T: 'static>(
3875        self,
3876        mut store: StoreContextMut<T>,
3877        caller_instance: RuntimeComponentInstanceIndex,
3878        ty: TransmitIndex,
3879        options: OptionsIndex,
3880        flat_abi: Option<FlatAbi>,
3881        handle: u32,
3882        address: u32,
3883        count: u32,
3884    ) -> Result<ReturnCode> {
3885        let count = ItemCount::new(count)?;
3886
3887        let address = usize::try_from(address)?;
3888        self.check_bounds(store.0, options, ty, address, count.as_usize())?;
3889        let async_ = self.options(store.0, options).async_;
3890        let (rep, state) = self.id().get_mut(store.0).get_mut_by_index(ty, handle)?;
3891        let TransmitLocalState::Read { done } = *state else {
3892            bail!(Trap::ConcurrentFutureStreamOp);
3893        };
3894
3895        *state = TransmitLocalState::Busy;
3896        let transmit_handle = TableId::<TransmitHandle>::new(rep);
3897        let caller_thread = store.0.current_guest_thread()?;
3898        let concurrent_state = store.0.concurrent_state_mut()?;
3899        let transmit_id = concurrent_state.get_mut(transmit_handle)?.state;
3900        let transmit = concurrent_state.get_mut(transmit_id)?;
3901        log::trace!(
3902            "guest_read {count} from {transmit_handle:?} (handle {handle}; state {transmit_id:?}); {:?}",
3903            transmit.write
3904        );
3905
3906        if done || transmit.done {
3907            match ty {
3908                TransmitIndex::Future(_) => {
3909                    bail!("cannot read from future after previous read succeeded")
3910                }
3911                TransmitIndex::Stream(_) => bail!(Trap::ReadFromDroppedStream),
3912            }
3913        }
3914
3915        if !async_ {
3916            Waitable::Transmit(transmit_handle).trap_if_in_waitable_set(concurrent_state)?;
3917        }
3918        let transmit = concurrent_state.get_mut(transmit_id)?;
3919
3920        let new_state = if let WriteState::Dropped = &transmit.write {
3921            WriteState::Dropped
3922        } else {
3923            WriteState::Open
3924        };
3925
3926        let set_guest_ready = |me: &mut ConcurrentState| {
3927            let transmit = me.get_mut(transmit_id)?;
3928            if !matches!(&transmit.read, ReadState::Open) {
3929                bail_bug!("expected `ReadState::Open`; got `{:?}`", transmit.read);
3930            }
3931            transmit.read = ReadState::GuestReady {
3932                ty,
3933                flat_abi,
3934                options,
3935                address,
3936                count,
3937                handle,
3938                instance: self,
3939                caller_instance,
3940                caller_thread,
3941            };
3942            Ok::<_, crate::Error>(())
3943        };
3944
3945        let mut result = match mem::replace(&mut transmit.write, new_state) {
3946            WriteState::GuestReady {
3947                instance: write_instance,
3948                ty: write_ty,
3949                flat_abi: write_flat_abi,
3950                options: write_options,
3951                address: write_address,
3952                count: write_count,
3953                handle: write_handle,
3954                caller: write_caller,
3955            } => {
3956                if flat_abi != write_flat_abi {
3957                    bail_bug!("expected flat ABI calculations to be the same");
3958                }
3959
3960                if let TransmitIndex::Future(_) = ty {
3961                    transmit.done = true;
3962                }
3963
3964                let write_handle_rep = transmit.write_handle.rep();
3965
3966                // See the comment in `guest_write` for the
3967                // `ReadState::GuestReady` case concerning zero-length reads and
3968                // writes.
3969
3970                let write_complete = write_count == 0 || count > 0;
3971                let read_complete = write_count > 0;
3972                let write_buffer_remaining = count < write_count;
3973
3974                let count = count.min(write_count);
3975
3976                Instance::copy(
3977                    store.as_context_mut(),
3978                    flat_abi,
3979                    write_instance.runtime_instance(write_caller),
3980                    write_ty,
3981                    write_options,
3982                    write_address,
3983                    self.runtime_instance(caller_instance),
3984                    caller_thread,
3985                    ty,
3986                    options,
3987                    address,
3988                    count,
3989                    rep,
3990                )?;
3991
3992                let instance = write_instance.id().get(store.0);
3993                let types = instance.component().types();
3994                // FIXME(#4311): needs memory64 handling
3995                let item_size = match write_ty.payload(types) {
3996                    Some(ty) => usize::try_from(types.canonical_abi(ty).size32)?,
3997                    None => 0,
3998                };
3999                let concurrent_state = store.0.concurrent_state_mut()?;
4000
4001                if write_complete {
4002                    let total = if let Some(Event::StreamWrite {
4003                        code: ReturnCode::Completed(old_total),
4004                        ..
4005                    }) = concurrent_state.take_event(write_handle_rep)?
4006                    {
4007                        count.add(old_total)?
4008                    } else {
4009                        count
4010                    };
4011
4012                    let code = ReturnCode::completed(ty.kind(), total);
4013
4014                    concurrent_state.send_write_result(
4015                        write_ty,
4016                        transmit_id,
4017                        write_handle,
4018                        code,
4019                    )?;
4020                }
4021
4022                if write_buffer_remaining {
4023                    let transmit = concurrent_state.get_mut(transmit_id)?;
4024                    transmit.write = WriteState::GuestReady {
4025                        instance: write_instance,
4026                        caller: write_caller,
4027                        ty: write_ty,
4028                        flat_abi: write_flat_abi,
4029                        options: write_options,
4030                        address: write_address + (count.as_usize() * item_size),
4031                        count: write_count.sub(count)?,
4032                        handle: write_handle,
4033                    };
4034                }
4035
4036                if read_complete {
4037                    ReturnCode::completed(ty.kind(), count)
4038                } else {
4039                    set_guest_ready(concurrent_state)?;
4040                    ReturnCode::Blocked
4041                }
4042            }
4043
4044            WriteState::HostReady {
4045                produce,
4046                try_into,
4047                guest_offset,
4048                cancel,
4049                cancel_waker,
4050            } => {
4051                if cancel_waker.is_some() {
4052                    bail_bug!("expected cancel_waker to be none");
4053                }
4054                if cancel {
4055                    bail_bug!("expected cancel to be false");
4056                }
4057                if guest_offset != 0 {
4058                    bail_bug!("expected guest_offset to be 0");
4059                }
4060
4061                set_guest_ready(concurrent_state)?;
4062
4063                let code = self.produce(
4064                    store.0,
4065                    ty.kind(),
4066                    transmit_id,
4067                    produce,
4068                    try_into,
4069                    ItemCount::ZERO,
4070                    false,
4071                )?;
4072
4073                if let (TransmitIndex::Future(_), ReturnCode::Completed(_)) = (ty, code) {
4074                    store.0.concurrent_state_mut()?.get_mut(transmit_id)?.done = true;
4075                }
4076
4077                code
4078            }
4079
4080            WriteState::Open => {
4081                set_guest_ready(concurrent_state)?;
4082                ReturnCode::Blocked
4083            }
4084
4085            WriteState::Dropped => {
4086                if let TransmitIndex::Future(_) = ty {
4087                    bail_bug!(
4088                        "should not be possible to read from a future whose write end was dropped"
4089                    );
4090                }
4091
4092                match Waitable::Transmit(transmit_handle).take_event(concurrent_state)? {
4093                    Some(Event::StreamRead {
4094                        code: ReturnCode::Dropped(ItemCount::ZERO),
4095                        ..
4096                    }) => {}
4097                    event => bail_bug!("expected pending dropped event for reader; got {event:?}"),
4098                }
4099
4100                ReturnCode::Dropped(ItemCount::ZERO)
4101            }
4102        };
4103
4104        if result == ReturnCode::Blocked && !async_ {
4105            result = self.wait_for_read(store.0, caller_instance, transmit_handle)?;
4106        }
4107
4108        if result != ReturnCode::Blocked {
4109            *self.id().get_mut(store.0).get_mut_by_index(ty, handle)?.1 =
4110                TransmitLocalState::Read {
4111                    done: matches!(
4112                        (result, ty),
4113                        (ReturnCode::Dropped(_), TransmitIndex::Stream(_))
4114                    ),
4115                };
4116        }
4117
4118        log::trace!(
4119            "guest_read result for {transmit_handle:?} (handle {handle}; state {transmit_id:?}): {result:?}",
4120        );
4121
4122        Ok(result)
4123    }
4124
4125    fn wait_for_write(
4126        self,
4127        store: &mut StoreOpaque,
4128        caller: RuntimeComponentInstanceIndex,
4129        handle: TableId<TransmitHandle>,
4130    ) -> Result<ReturnCode> {
4131        let waitable = Waitable::Transmit(handle);
4132        store.wait_for_event(self.runtime_instance(caller), waitable)?;
4133        let event = waitable.take_event(store.concurrent_state_mut()?)?;
4134        if let Some(event @ (Event::StreamWrite { code, .. } | Event::FutureWrite { code, .. })) =
4135            event
4136        {
4137            waitable.on_delivery(store, self, event)?;
4138            Ok(code)
4139        } else {
4140            bail_bug!("expected either a stream or future write event")
4141        }
4142    }
4143
4144    /// Cancel a pending stream or future write.
4145    fn cancel_write(
4146        self,
4147        store: &mut StoreOpaque,
4148        caller: RuntimeComponentInstanceIndex,
4149        transmit_id: TableId<TransmitState>,
4150        async_: bool,
4151    ) -> Result<ReturnCode> {
4152        let state = store.concurrent_state_mut()?;
4153        let transmit = state.get_mut(transmit_id)?;
4154        log::trace!(
4155            "host_cancel_write state {transmit_id:?}; write state {:?} read state {:?}",
4156            transmit.read,
4157            transmit.write
4158        );
4159        let waitable = Waitable::Transmit(transmit.write_handle);
4160
4161        waitable.trap_if_has_sync_waiter(state)?;
4162        if !async_ {
4163            waitable.trap_if_in_waitable_set(state)?;
4164        }
4165
4166        let code = if let Some(event) = waitable.take_event(state)? {
4167            let (Event::FutureWrite { code, .. } | Event::StreamWrite { code, .. }) = event else {
4168                bail_bug!("expected either a stream or future write event")
4169            };
4170            waitable.on_delivery(store, self, event)?;
4171            match (code, event) {
4172                (ReturnCode::Completed(count), Event::StreamWrite { .. }) => {
4173                    ReturnCode::Cancelled(count)
4174                }
4175                (ReturnCode::Dropped(_) | ReturnCode::Completed(_), _) => code,
4176                _ => bail_bug!("unexpected code/event combo"),
4177            }
4178        } else if let ReadState::HostReady {
4179            cancel,
4180            cancel_waker,
4181            ..
4182        } = &mut state.get_mut(transmit_id)?.read
4183        {
4184            *cancel = true;
4185            if let Some(waker) = cancel_waker.take() {
4186                waker.wake();
4187            }
4188
4189            if async_ {
4190                ReturnCode::Blocked
4191            } else {
4192                let handle = store
4193                    .concurrent_state_mut()?
4194                    .get_mut(transmit_id)?
4195                    .write_handle;
4196                self.wait_for_write(store, caller, handle)?
4197            }
4198        } else {
4199            ReturnCode::Cancelled(ItemCount::ZERO)
4200        };
4201
4202        if !matches!(code, ReturnCode::Blocked) {
4203            let transmit = store.concurrent_state_mut()?.get_mut(transmit_id)?;
4204
4205            match &transmit.write {
4206                WriteState::GuestReady { .. } => {
4207                    transmit.write = WriteState::Open;
4208                }
4209                WriteState::HostReady { .. } => bail_bug!("support host write cancellation"),
4210                WriteState::Open | WriteState::Dropped => {}
4211            }
4212        }
4213
4214        log::trace!("cancelled write {transmit_id:?}: {code:?}");
4215
4216        Ok(code)
4217    }
4218
4219    fn wait_for_read(
4220        self,
4221        store: &mut StoreOpaque,
4222        caller: RuntimeComponentInstanceIndex,
4223        handle: TableId<TransmitHandle>,
4224    ) -> Result<ReturnCode> {
4225        let waitable = Waitable::Transmit(handle);
4226        store.wait_for_event(self.runtime_instance(caller), waitable)?;
4227        let event = waitable.take_event(store.concurrent_state_mut()?)?;
4228        if let Some(event @ (Event::StreamRead { code, .. } | Event::FutureRead { code, .. })) =
4229            event
4230        {
4231            waitable.on_delivery(store, self, event)?;
4232            Ok(code)
4233        } else {
4234            bail_bug!("expected either a stream or future read event")
4235        }
4236    }
4237
4238    /// Cancel a pending stream or future read.
4239    fn cancel_read(
4240        self,
4241        store: &mut StoreOpaque,
4242        caller: RuntimeComponentInstanceIndex,
4243        transmit_id: TableId<TransmitState>,
4244        async_: bool,
4245    ) -> Result<ReturnCode> {
4246        let state = store.concurrent_state_mut()?;
4247        let transmit = state.get_mut(transmit_id)?;
4248        log::trace!(
4249            "host_cancel_read state {transmit_id:?}; read state {:?} write state {:?}",
4250            transmit.read,
4251            transmit.write
4252        );
4253
4254        let waitable = Waitable::Transmit(transmit.read_handle);
4255
4256        waitable.trap_if_has_sync_waiter(state)?;
4257        if !async_ {
4258            waitable.trap_if_in_waitable_set(state)?;
4259        }
4260
4261        let code = if let Some(event) = waitable.take_event(state)? {
4262            let (Event::FutureRead { code, .. } | Event::StreamRead { code, .. }) = event else {
4263                bail_bug!("expected either a stream or future read event")
4264            };
4265            waitable.on_delivery(store, self, event)?;
4266            match (code, event) {
4267                (ReturnCode::Completed(count), Event::StreamRead { .. }) => {
4268                    ReturnCode::Cancelled(count)
4269                }
4270                (ReturnCode::Dropped(_) | ReturnCode::Completed(_), _) => code,
4271                _ => bail_bug!("unexpected code/event combo"),
4272            }
4273        } else if let WriteState::HostReady {
4274            cancel,
4275            cancel_waker,
4276            ..
4277        } = &mut state.get_mut(transmit_id)?.write
4278        {
4279            *cancel = true;
4280            if let Some(waker) = cancel_waker.take() {
4281                waker.wake();
4282            }
4283
4284            if async_ {
4285                ReturnCode::Blocked
4286            } else {
4287                let handle = store
4288                    .concurrent_state_mut()?
4289                    .get_mut(transmit_id)?
4290                    .read_handle;
4291                self.wait_for_read(store, caller, handle)?
4292            }
4293        } else {
4294            ReturnCode::Cancelled(ItemCount::ZERO)
4295        };
4296
4297        if !matches!(code, ReturnCode::Blocked) {
4298            let transmit = store.concurrent_state_mut()?.get_mut(transmit_id)?;
4299
4300            match &transmit.read {
4301                ReadState::GuestReady { .. } => {
4302                    transmit.read = ReadState::Open;
4303                }
4304                ReadState::HostReady { .. } | ReadState::HostToHost { .. } => {
4305                    bail_bug!("support host read cancellation")
4306                }
4307                ReadState::Open | ReadState::Dropped => {}
4308            }
4309        }
4310
4311        log::trace!("cancelled read {transmit_id:?}: {code:?}");
4312
4313        Ok(code)
4314    }
4315
4316    /// Cancel a pending write for the specified stream or future from the guest.
4317    fn guest_cancel_write(
4318        self,
4319        store: &mut StoreOpaque,
4320        caller: RuntimeComponentInstanceIndex,
4321        ty: TransmitIndex,
4322        async_: bool,
4323        writer: u32,
4324    ) -> Result<ReturnCode> {
4325        let (rep, state) =
4326            get_mut_by_index_from(self.id().get_mut(store).table_for_transmit(ty), ty, writer)?;
4327        let id = TableId::<TransmitHandle>::new(rep);
4328        log::trace!("guest cancel write {id:?} (handle {writer})");
4329        match state {
4330            TransmitLocalState::Write { .. } => {
4331                bail!("stream or future write cancelled when no write is pending")
4332            }
4333            TransmitLocalState::Read { .. } => {
4334                bail!("passed read end to `{{stream|future}}.cancel-write`")
4335            }
4336            TransmitLocalState::Cancelling => {
4337                bail!("stream or future write cancelled when a cancellation is already pending")
4338            }
4339            TransmitLocalState::Busy => {}
4340        }
4341        let transmit_id = store.concurrent_state_mut()?.get_mut(id)?.state;
4342        let code = self.cancel_write(store, caller, transmit_id, async_)?;
4343        let state =
4344            get_mut_by_index_from(self.id().get_mut(store).table_for_transmit(ty), ty, writer)?.1;
4345        if let TransmitLocalState::Busy = state {
4346            *state = if matches!(code, ReturnCode::Blocked) {
4347                TransmitLocalState::Cancelling
4348            } else {
4349                TransmitLocalState::Write { done: false }
4350            };
4351        }
4352        Ok(code)
4353    }
4354
4355    /// Cancel a pending read for the specified stream or future from the guest.
4356    fn guest_cancel_read(
4357        self,
4358        store: &mut StoreOpaque,
4359        caller: RuntimeComponentInstanceIndex,
4360        ty: TransmitIndex,
4361        async_: bool,
4362        reader: u32,
4363    ) -> Result<ReturnCode> {
4364        let (rep, state) =
4365            get_mut_by_index_from(self.id().get_mut(store).table_for_transmit(ty), ty, reader)?;
4366        let id = TableId::<TransmitHandle>::new(rep);
4367        log::trace!("guest cancel read {id:?} (handle {reader})");
4368        match state {
4369            TransmitLocalState::Read { .. } => {
4370                bail!("stream or future read cancelled when no read is pending")
4371            }
4372            TransmitLocalState::Write { .. } => {
4373                bail!("passed write end to `{{stream|future}}.cancel-read`")
4374            }
4375            TransmitLocalState::Cancelling => {
4376                bail!("stream or future read cancelled when a cancellation is already pending")
4377            }
4378            TransmitLocalState::Busy => {}
4379        }
4380        let transmit_id = store.concurrent_state_mut()?.get_mut(id)?.state;
4381        let code = self.cancel_read(store, caller, transmit_id, async_)?;
4382        let state =
4383            get_mut_by_index_from(self.id().get_mut(store).table_for_transmit(ty), ty, reader)?.1;
4384        if let TransmitLocalState::Busy = state {
4385            *state = if matches!(code, ReturnCode::Blocked) {
4386                TransmitLocalState::Cancelling
4387            } else {
4388                TransmitLocalState::Read { done: false }
4389            };
4390        }
4391        Ok(code)
4392    }
4393
4394    /// Drop the readable end of the specified stream or future from the guest.
4395    fn guest_drop_readable(
4396        self,
4397        store: &mut StoreOpaque,
4398        ty: TransmitIndex,
4399        reader: u32,
4400    ) -> Result<()> {
4401        let (instance, counter) = self.id().get_mut_and_handle_counter(store);
4402        let table = instance.table_for_transmit(ty);
4403        let (rep, _is_done) = match ty {
4404            TransmitIndex::Stream(ty) => table.stream_remove_readable(counter, ty, reader)?,
4405            TransmitIndex::Future(ty) => table.future_remove_readable(counter, ty, reader)?,
4406        };
4407        let kind = match ty {
4408            TransmitIndex::Stream(_) => TransmitKind::Stream,
4409            TransmitIndex::Future(_) => TransmitKind::Future,
4410        };
4411        let id = TableId::<TransmitHandle>::new(rep);
4412        log::trace!("guest_drop_readable: drop reader {id:?}");
4413        store.host_drop_reader(id, kind)
4414    }
4415
4416    /// Create a new error context for the given component.
4417    pub(crate) fn error_context_new(
4418        self,
4419        store: &mut StoreOpaque,
4420        ty: TypeComponentLocalErrorContextTableIndex,
4421        options: OptionsIndex,
4422        debug_msg_address: u32,
4423        debug_msg_len: u32,
4424    ) -> Result<u32> {
4425        let lift_ctx = &mut LiftContext::new(store, options, self)?;
4426        let debug_msg = String::linear_lift_from_flat(
4427            lift_ctx,
4428            InterfaceType::String,
4429            &[ValRaw::u32(debug_msg_address), ValRaw::u32(debug_msg_len)],
4430        )?;
4431
4432        // Create a new ErrorContext that is tracked along with other concurrent state
4433        let err_ctx = ErrorContextState { debug_msg };
4434        let state = store.concurrent_state_mut()?;
4435        let table_id = state.push(err_ctx)?;
4436        let global_ref_count_idx =
4437            TypeComponentGlobalErrorContextTableIndex::from_u32(table_id.rep());
4438
4439        // Add to the global error context ref counts
4440        let _ = state
4441            .global_error_context_ref_counts
4442            .insert(global_ref_count_idx, GlobalErrorContextRefCount(1));
4443
4444        // Error context are tracked both locally (to a single component instance) and globally
4445        // the counts for both must stay in sync.
4446        //
4447        // Here we reflect the newly created global concurrent error context state into the
4448        // component instance's locally tracked count, along with the appropriate key into the global
4449        // ref tracking data structures to enable later lookup
4450        let (instance, counter) = self.id().get_mut_and_handle_counter(store);
4451        let local_idx = instance
4452            .table_for_error_context(ty)
4453            .error_context_insert(counter, table_id.rep())?;
4454
4455        Ok(local_idx)
4456    }
4457
4458    /// Retrieve the debug message from the specified error context.
4459    pub(super) fn error_context_debug_message<T>(
4460        self,
4461        store: StoreContextMut<T>,
4462        ty: TypeComponentLocalErrorContextTableIndex,
4463        options: OptionsIndex,
4464        err_ctx_handle: u32,
4465        debug_msg_address: u32,
4466    ) -> Result<()> {
4467        // Retrieve the error context and internal debug message
4468        let handle_table_id_rep = self
4469            .id()
4470            .get_mut(store.0)
4471            .table_for_error_context(ty)
4472            .error_context_rep(err_ctx_handle)?;
4473
4474        let state = store.0.concurrent_state_mut()?;
4475        // Get the state associated with the error context
4476        let ErrorContextState { debug_msg } =
4477            state.get_mut(TableId::<ErrorContextState>::new(handle_table_id_rep))?;
4478        let debug_msg = debug_msg.clone();
4479
4480        let lower_cx = &mut LowerContext::new(store, options, self);
4481        let debug_msg_address = usize::try_from(debug_msg_address)?;
4482        if debug_msg_address % usize::try_from(<str as ComponentType>::ALIGN32)? != 0 {
4483            bail!("invalid debug message pointer: not aligned");
4484        }
4485        // Lower the string into the component's memory.
4486        //
4487        // Note that the "8" here is the size of a WIT `string` in linear
4488        // memory, the ptr+length. This'll need to be updated when `memory64`
4489        // comes along. (FIXME(#4311))
4490        let offset = lower_cx
4491            .as_slice_mut()
4492            .get(debug_msg_address..)
4493            .and_then(|b| b.get(..8))
4494            .map(|_| debug_msg_address)
4495            .ok_or_else(|| crate::format_err!("invalid debug message pointer: out of bounds"))?;
4496        debug_msg
4497            .as_str()
4498            .linear_lower_to_memory(lower_cx, InterfaceType::String, offset)?;
4499
4500        Ok(())
4501    }
4502
4503    /// Implements the `future.cancel-read` intrinsic.
4504    pub(crate) fn future_cancel_read(
4505        self,
4506        store: &mut StoreOpaque,
4507        caller: RuntimeComponentInstanceIndex,
4508        ty: TypeFutureTableIndex,
4509        async_: bool,
4510        reader: u32,
4511    ) -> Result<u32> {
4512        self.guest_cancel_read(store, caller, TransmitIndex::Future(ty), async_, reader)
4513            .map(|v| v.encode())
4514    }
4515
4516    /// Implements the `future.cancel-write` intrinsic.
4517    pub(crate) fn future_cancel_write(
4518        self,
4519        store: &mut StoreOpaque,
4520        caller: RuntimeComponentInstanceIndex,
4521        ty: TypeFutureTableIndex,
4522        async_: bool,
4523        writer: u32,
4524    ) -> Result<u32> {
4525        self.guest_cancel_write(store, caller, TransmitIndex::Future(ty), async_, writer)
4526            .map(|v| v.encode())
4527    }
4528
4529    /// Implements the `stream.cancel-read` intrinsic.
4530    pub(crate) fn stream_cancel_read(
4531        self,
4532        store: &mut StoreOpaque,
4533        caller: RuntimeComponentInstanceIndex,
4534        ty: TypeStreamTableIndex,
4535        async_: bool,
4536        reader: u32,
4537    ) -> Result<u32> {
4538        self.guest_cancel_read(store, caller, TransmitIndex::Stream(ty), async_, reader)
4539            .map(|v| v.encode())
4540    }
4541
4542    /// Implements the `stream.cancel-write` intrinsic.
4543    pub(crate) fn stream_cancel_write(
4544        self,
4545        store: &mut StoreOpaque,
4546        caller: RuntimeComponentInstanceIndex,
4547        ty: TypeStreamTableIndex,
4548        async_: bool,
4549        writer: u32,
4550    ) -> Result<u32> {
4551        self.guest_cancel_write(store, caller, TransmitIndex::Stream(ty), async_, writer)
4552            .map(|v| v.encode())
4553    }
4554
4555    /// Implements the `future.drop-readable` intrinsic.
4556    pub(crate) fn future_drop_readable(
4557        self,
4558        store: &mut StoreOpaque,
4559        ty: TypeFutureTableIndex,
4560        reader: u32,
4561    ) -> Result<()> {
4562        self.guest_drop_readable(store, TransmitIndex::Future(ty), reader)
4563    }
4564
4565    /// Implements the `stream.drop-readable` intrinsic.
4566    pub(crate) fn stream_drop_readable(
4567        self,
4568        store: &mut StoreOpaque,
4569        ty: TypeStreamTableIndex,
4570        reader: u32,
4571    ) -> Result<()> {
4572        self.guest_drop_readable(store, TransmitIndex::Stream(ty), reader)
4573    }
4574
4575    /// Allocate a new future or stream and grant ownership of both the read and
4576    /// write ends to the (sub-)component instance to which the specified
4577    /// `TransmitIndex` belongs.
4578    fn guest_new(self, store: &mut StoreOpaque, ty: TransmitIndex) -> Result<ResourcePair> {
4579        let (write, read) = store
4580            .concurrent_state_mut()?
4581            .new_transmit(TransmitOrigin::guest(self.id().instance(), ty))?;
4582
4583        let (instance, counter) = self.id().get_mut_and_handle_counter(store);
4584        let table = instance.table_for_transmit(ty);
4585        let (read_handle, write_handle) = match ty {
4586            TransmitIndex::Future(ty) => (
4587                table.future_insert_read(counter, ty, read.rep())?,
4588                table.future_insert_write(counter, ty, write.rep())?,
4589            ),
4590            TransmitIndex::Stream(ty) => (
4591                table.stream_insert_read(counter, ty, read.rep())?,
4592                table.stream_insert_write(counter, ty, write.rep())?,
4593            ),
4594        };
4595
4596        let state = store.concurrent_state_mut()?;
4597        state.get_mut(read)?.common.handle = Some(read_handle);
4598        state.get_mut(write)?.common.handle = Some(write_handle);
4599
4600        Ok(ResourcePair {
4601            write: write_handle,
4602            read: read_handle,
4603        })
4604    }
4605
4606    /// Drop the specified error context.
4607    pub(crate) fn error_context_drop(
4608        self,
4609        store: &mut StoreOpaque,
4610        ty: TypeComponentLocalErrorContextTableIndex,
4611        error_context: u32,
4612    ) -> Result<()> {
4613        let (instance, counter) = self.id().get_mut_and_handle_counter(store);
4614
4615        let local_handle_table = instance.table_for_error_context(ty);
4616
4617        let rep = local_handle_table.error_context_drop(counter, error_context)?;
4618
4619        let global_ref_count_idx = TypeComponentGlobalErrorContextTableIndex::from_u32(rep);
4620
4621        let state = store.concurrent_state_mut()?;
4622        let Some(GlobalErrorContextRefCount(global_ref_count)) = state
4623            .global_error_context_ref_counts
4624            .get_mut(&global_ref_count_idx)
4625        else {
4626            bail_bug!("retrieve concurrent state for error context during drop")
4627        };
4628
4629        // Reduce the component-global ref count, removing tracking if necessary
4630        if *global_ref_count < 1 {
4631            bail_bug!("ref count unexpectedly zero");
4632        }
4633        *global_ref_count -= 1;
4634        if *global_ref_count == 0 {
4635            state
4636                .global_error_context_ref_counts
4637                .remove(&global_ref_count_idx);
4638
4639            state
4640                .delete(TableId::<ErrorContextState>::new(rep))
4641                .context("deleting component-global error context data")?;
4642        }
4643
4644        Ok(())
4645    }
4646
4647    /// Transfer ownership of the specified stream or future read end from one
4648    /// guest to another.
4649    fn guest_transfer(
4650        self,
4651        store: &mut StoreOpaque,
4652        src_idx: u32,
4653        src: TransmitIndex,
4654        dst: TransmitIndex,
4655    ) -> Result<u32> {
4656        let id = self.lift_index_to_transmit(store, src, src_idx)?;
4657        self.lower_transmit_to_index(store, dst, id)
4658    }
4659
4660    fn lift_index_to_transmit(
4661        self,
4662        store: &mut StoreOpaque,
4663        ty: TransmitIndex,
4664        src_idx: u32,
4665    ) -> Result<TableId<TransmitHandle>> {
4666        let (state, _, counter, _, instance) = store.lift_context_parts(self);
4667        lift_index_to_transmit(instance, counter, state.concurrent_state_mut(), ty, src_idx)
4668    }
4669
4670    fn lower_transmit_to_index(
4671        self,
4672        store: &mut StoreOpaque,
4673        ty: TransmitIndex,
4674        id: TableId<TransmitHandle>,
4675    ) -> Result<u32> {
4676        let (state, _, counter, _, instance) = store.lift_context_parts(self);
4677        lower_transmit_to_index(instance, counter, state.concurrent_state_mut(), ty, id)
4678    }
4679
4680    /// Implements the `future.new` intrinsic.
4681    pub(crate) fn future_new(
4682        self,
4683        store: &mut StoreOpaque,
4684        ty: TypeFutureTableIndex,
4685    ) -> Result<ResourcePair> {
4686        self.guest_new(store, TransmitIndex::Future(ty))
4687    }
4688
4689    /// Implements the `stream.new` intrinsic.
4690    pub(crate) fn stream_new(
4691        self,
4692        store: &mut StoreOpaque,
4693        ty: TypeStreamTableIndex,
4694    ) -> Result<ResourcePair> {
4695        self.guest_new(store, TransmitIndex::Stream(ty))
4696    }
4697
4698    /// Transfer ownership of the specified future read end from one guest to
4699    /// another.
4700    pub(crate) fn future_transfer(
4701        self,
4702        store: &mut StoreOpaque,
4703        src_idx: u32,
4704        src: TypeFutureTableIndex,
4705        dst: TypeFutureTableIndex,
4706    ) -> Result<u32> {
4707        self.guest_transfer(
4708            store,
4709            src_idx,
4710            TransmitIndex::Future(src),
4711            TransmitIndex::Future(dst),
4712        )
4713    }
4714
4715    /// Transfer ownership of the specified stream read end from one guest to
4716    /// another.
4717    pub(crate) fn stream_transfer(
4718        self,
4719        store: &mut StoreOpaque,
4720        src_idx: u32,
4721        src: TypeStreamTableIndex,
4722        dst: TypeStreamTableIndex,
4723    ) -> Result<u32> {
4724        self.guest_transfer(
4725            store,
4726            src_idx,
4727            TransmitIndex::Stream(src),
4728            TransmitIndex::Stream(dst),
4729        )
4730    }
4731
4732    /// Copy the specified error context from one component to another.
4733    pub(crate) fn error_context_transfer(
4734        self,
4735        store: &mut StoreOpaque,
4736        src_idx: u32,
4737        src: TypeComponentLocalErrorContextTableIndex,
4738        dst: TypeComponentLocalErrorContextTableIndex,
4739    ) -> Result<u32> {
4740        let (mut instance, counter) = self.id().get_mut_and_handle_counter(store);
4741        let rep = instance
4742            .as_mut()
4743            .table_for_error_context(src)
4744            .error_context_rep(src_idx)?;
4745        let dst_idx = instance
4746            .table_for_error_context(dst)
4747            .error_context_insert(counter, rep)?;
4748
4749        // Update the global (cross-subcomponent) count for error contexts
4750        // as the new component has essentially created a new reference that will
4751        // be dropped/handled independently
4752        let global_ref_count = store
4753            .concurrent_state_mut()?
4754            .global_error_context_ref_counts
4755            .get_mut(&TypeComponentGlobalErrorContextTableIndex::from_u32(rep))
4756            .context("global ref count present for existing (sub)component error context")?;
4757
4758        global_ref_count.0 = global_ref_count
4759            .0
4760            .checked_add(1)
4761            .ok_or_else(|| format_err!(Trap::ReferenceCountOverflow))?;
4762
4763        Ok(dst_idx)
4764    }
4765}
4766
4767/// Performs the opertion of lifting a future or stream from and instance into
4768/// the `TransmitHandle` for it.
4769///
4770/// The `src_idx` is the guest-specified index within `instance` and `ty` is the
4771/// expected type of future/stream.
4772fn lift_index_to_transmit(
4773    instance: Pin<&mut ComponentInstance>,
4774    counter: &mut HandleCounter,
4775    concurrent_state: &mut ConcurrentState,
4776    ty: TransmitIndex,
4777    src_idx: u32,
4778) -> Result<TableId<TransmitHandle>> {
4779    let handle_table = instance.table_for_transmit(ty);
4780    let (rep, is_done) = match ty {
4781        TransmitIndex::Future(idx) => handle_table.future_remove_readable(counter, idx, src_idx)?,
4782        TransmitIndex::Stream(idx) => handle_table.stream_remove_readable(counter, idx, src_idx)?,
4783    };
4784    let desc = match ty {
4785        TransmitIndex::Future(_) => "future",
4786        TransmitIndex::Stream(_) => "stream",
4787    };
4788    if is_done {
4789        bail!("cannot lift {desc} after being notified that the writable end dropped");
4790    }
4791    let id = TableId::<TransmitHandle>::new(rep);
4792    let future = concurrent_state.get_mut(id)?;
4793    if future.common.set.is_some() {
4794        bail!("cannot lift {desc} while it's in a waitable set");
4795    }
4796    future.common.handle = None;
4797
4798    let state = future.state;
4799    if concurrent_state.get_mut(state)?.done {
4800        match ty {
4801            TransmitIndex::Future(_) => bail!("cannot lift {desc} after previous read succeeded"),
4802            TransmitIndex::Stream(_) => bail!(Trap::LiftDroppedStream),
4803        };
4804    }
4805
4806    Ok(id)
4807}
4808
4809/// Performs the opertion of lowering a future or stream `TransmitHandle` into
4810/// an instance.
4811fn lower_transmit_to_index(
4812    instance: Pin<&mut ComponentInstance>,
4813    counter: &mut HandleCounter,
4814    concurrent_state: &mut ConcurrentState,
4815    ty: TransmitIndex,
4816    id: TableId<TransmitHandle>,
4817) -> Result<u32> {
4818    let state = concurrent_state.get_mut(id)?.state;
4819    debug_assert_eq!(concurrent_state.get_mut(state)?.read_handle, id);
4820    let handle_table = instance.table_for_transmit(ty);
4821    let handle = match ty {
4822        TransmitIndex::Future(idx) => handle_table.future_insert_read(counter, idx, id.rep()),
4823        TransmitIndex::Stream(idx) => handle_table.stream_insert_read(counter, idx, id.rep()),
4824    }?;
4825    concurrent_state.get_mut(id)?.common.handle = Some(handle);
4826    Ok(handle)
4827}
4828
4829impl ComponentInstance {
4830    fn table_for_transmit(self: Pin<&mut Self>, ty: TransmitIndex) -> &mut HandleTable {
4831        let (states, types) = self.instance_states();
4832        let runtime_instance = match ty {
4833            TransmitIndex::Stream(ty) => types[ty].instance,
4834            TransmitIndex::Future(ty) => types[ty].instance,
4835        };
4836        states[runtime_instance].handle_table()
4837    }
4838
4839    fn table_for_error_context(
4840        self: Pin<&mut Self>,
4841        ty: TypeComponentLocalErrorContextTableIndex,
4842    ) -> &mut HandleTable {
4843        let (states, types) = self.instance_states();
4844        let runtime_instance = types[ty].instance;
4845        states[runtime_instance].handle_table()
4846    }
4847
4848    fn get_mut_by_index(
4849        self: Pin<&mut Self>,
4850        ty: TransmitIndex,
4851        index: u32,
4852    ) -> Result<(u32, &mut TransmitLocalState)> {
4853        get_mut_by_index_from(self.table_for_transmit(ty), ty, index)
4854    }
4855}
4856
4857impl ConcurrentState {
4858    fn send_write_result(
4859        &mut self,
4860        ty: TransmitIndex,
4861        id: TableId<TransmitState>,
4862        handle: u32,
4863        code: ReturnCode,
4864    ) -> Result<()> {
4865        let write_handle = self.get_mut(id)?.write_handle.rep();
4866        self.set_event(
4867            write_handle,
4868            match ty {
4869                TransmitIndex::Future(ty) => Event::FutureWrite {
4870                    code,
4871                    pending: Some((ty, handle)),
4872                },
4873                TransmitIndex::Stream(ty) => Event::StreamWrite {
4874                    code,
4875                    pending: Some((ty, handle)),
4876                },
4877            },
4878        )
4879    }
4880
4881    fn send_read_result(
4882        &mut self,
4883        ty: TransmitIndex,
4884        id: TableId<TransmitState>,
4885        handle: u32,
4886        code: ReturnCode,
4887    ) -> Result<()> {
4888        let read_handle = self.get_mut(id)?.read_handle.rep();
4889        self.set_event(
4890            read_handle,
4891            match ty {
4892                TransmitIndex::Future(ty) => Event::FutureRead {
4893                    code,
4894                    pending: Some((ty, handle)),
4895                },
4896                TransmitIndex::Stream(ty) => Event::StreamRead {
4897                    code,
4898                    pending: Some((ty, handle)),
4899                },
4900            },
4901        )
4902    }
4903
4904    fn take_event(&mut self, waitable: u32) -> Result<Option<Event>> {
4905        Waitable::Transmit(TableId::<TransmitHandle>::new(waitable)).take_event(self)
4906    }
4907
4908    fn set_event(&mut self, waitable: u32, event: Event) -> Result<()> {
4909        Waitable::Transmit(TableId::<TransmitHandle>::new(waitable)).set_event(self, Some(event))
4910    }
4911
4912    /// Set or update the event for the specified waitable.
4913    ///
4914    /// If there is already an event set for this waitable, we assert that it is
4915    /// of the same variant as the new one and reuse the `ReturnCode` count and
4916    /// the `pending` field if applicable.
4917    // TODO: This is a bit awkward due to how
4918    // `Event::{Stream,Future}{Write,Read}` and
4919    // `ReturnCode::{Completed,Dropped,Cancelled}` are currently represented.
4920    // Consider updating those representations in a way that allows this
4921    // function to be simplified.
4922    fn update_event(&mut self, waitable: u32, event: Event) -> Result<()> {
4923        let waitable = Waitable::Transmit(TableId::<TransmitHandle>::new(waitable));
4924
4925        fn update_code(old: ReturnCode, new: ReturnCode) -> Result<ReturnCode> {
4926            let (ReturnCode::Completed(count)
4927            | ReturnCode::Dropped(count)
4928            | ReturnCode::Cancelled(count)) = old
4929            else {
4930                bail_bug!("unexpected old return code")
4931            };
4932
4933            Ok(match new {
4934                ReturnCode::Dropped(ItemCount::ZERO) => ReturnCode::Dropped(count),
4935                ReturnCode::Cancelled(ItemCount::ZERO) => ReturnCode::Cancelled(count),
4936                _ => bail_bug!("unexpected new return code"),
4937            })
4938        }
4939
4940        let event = match (waitable.take_event(self)?, event) {
4941            (None, _) => event,
4942            (Some(old @ Event::FutureWrite { .. }), Event::FutureWrite { .. }) => old,
4943            (Some(old @ Event::FutureRead { .. }), Event::FutureRead { .. }) => old,
4944            (
4945                Some(Event::StreamWrite {
4946                    code: old_code,
4947                    pending: old_pending,
4948                }),
4949                Event::StreamWrite { code, pending },
4950            ) => Event::StreamWrite {
4951                code: update_code(old_code, code)?,
4952                pending: old_pending.or(pending),
4953            },
4954            (
4955                Some(Event::StreamRead {
4956                    code: old_code,
4957                    pending: old_pending,
4958                }),
4959                Event::StreamRead { code, pending },
4960            ) => Event::StreamRead {
4961                code: update_code(old_code, code)?,
4962                pending: old_pending.or(pending),
4963            },
4964            _ => bail_bug!("unexpected event combination"),
4965        };
4966
4967        waitable.set_event(self, Some(event))
4968    }
4969
4970    /// Allocate a new future or stream, including the `TransmitState` and the
4971    /// `TransmitHandle`s corresponding to the read and write ends.
4972    fn new_transmit(
4973        &mut self,
4974        origin: TransmitOrigin,
4975    ) -> Result<(TableId<TransmitHandle>, TableId<TransmitHandle>)> {
4976        // All three entries must fit before inserting any of them so a full
4977        // table does not leave an inaccessible state or handle behind.
4978        self.table().ensure_capacity(3)?;
4979        let state_id = self.push(TransmitState::new(origin))?;
4980
4981        let write = self.push(TransmitHandle::new(state_id))?;
4982        let read = self.push(TransmitHandle::new(state_id))?;
4983
4984        let state = self.get_mut(state_id)?;
4985        state.write_handle = write;
4986        state.read_handle = read;
4987
4988        log::trace!("new transmit: state {state_id:?}; write {write:?}; read {read:?}",);
4989
4990        Ok((write, read))
4991    }
4992
4993    /// Delete the specified future or stream, including the read and write ends.
4994    fn delete_transmit(&mut self, state_id: TableId<TransmitState>) -> Result<()> {
4995        let state = self.delete(state_id)?;
4996        self.delete(state.write_handle)?;
4997        self.delete(state.read_handle)?;
4998
4999        log::trace!(
5000            "delete transmit: state {state_id:?}; write {:?}; read {:?}",
5001            state.write_handle,
5002            state.read_handle,
5003        );
5004
5005        Ok(())
5006    }
5007}
5008
5009pub(crate) struct ResourcePair {
5010    pub(crate) write: u32,
5011    pub(crate) read: u32,
5012}
5013
5014impl Waitable {
5015    /// Handle the imminent delivery of the specified event, e.g. by updating
5016    /// the state of the stream or future.
5017    pub(super) fn on_delivery(
5018        &self,
5019        store: &mut StoreOpaque,
5020        instance: Instance,
5021        event: Event,
5022    ) -> Result<()> {
5023        if let Event::FutureRead {
5024            code: ReturnCode::Dropped(_),
5025            ..
5026        }
5027        | Event::FutureWrite {
5028            code: ReturnCode::Dropped(_),
5029            ..
5030        }
5031        | Event::StreamRead {
5032            code: ReturnCode::Dropped(_),
5033            ..
5034        }
5035        | Event::StreamWrite {
5036            code: ReturnCode::Dropped(_),
5037            ..
5038        } = event
5039        {
5040            let Waitable::Transmit(transmit_handle) = self else {
5041                bail_bug!("unexpected `{event:?}` for `{self:?}`");
5042            };
5043            let state = store.concurrent_state_mut()?;
5044            let transmit_id = state.get_mut(*transmit_handle)?.state;
5045            state.get_mut(transmit_id)?.done = true;
5046        }
5047
5048        let instance = instance.id().get_mut(store);
5049        let (rep, state, code) = match event {
5050            Event::FutureRead {
5051                pending: Some((ty, handle)),
5052                code,
5053            }
5054            | Event::FutureWrite {
5055                pending: Some((ty, handle)),
5056                code,
5057            } => {
5058                let runtime_instance = instance.component().types()[ty].instance;
5059                let (rep, state) = instance.instance_states().0[runtime_instance]
5060                    .handle_table()
5061                    .future_rep(ty, handle)?;
5062                (rep, state, code)
5063            }
5064            Event::StreamRead {
5065                pending: Some((ty, handle)),
5066                code,
5067            }
5068            | Event::StreamWrite {
5069                pending: Some((ty, handle)),
5070                code,
5071            } => {
5072                let runtime_instance = instance.component().types()[ty].instance;
5073                let (rep, state) = instance.instance_states().0[runtime_instance]
5074                    .handle_table()
5075                    .stream_rep(ty, handle)?;
5076                (rep, state, code)
5077            }
5078            _ => return Ok(()),
5079        };
5080        if rep != self.rep() {
5081            bail_bug!("unexpected rep mismatch");
5082        }
5083        if !matches!(
5084            *state,
5085            TransmitLocalState::Busy | TransmitLocalState::Cancelling
5086        ) {
5087            bail_bug!("expected state to be busy or cancelling");
5088        }
5089        let done = matches!(code, ReturnCode::Dropped(_));
5090        *state = match event {
5091            Event::FutureRead { .. } | Event::StreamRead { .. } => {
5092                TransmitLocalState::Read { done }
5093            }
5094            Event::FutureWrite { .. } | Event::StreamWrite { .. } => {
5095                TransmitLocalState::Write { done }
5096            }
5097            _ => bail_bug!("unexpected event for stream"),
5098        };
5099
5100        let transmit_handle = TableId::<TransmitHandle>::new(rep);
5101        let state = store.concurrent_state_mut()?;
5102        let transmit_id = state.get_mut(transmit_handle)?.state;
5103        let transmit = state.get_mut(transmit_id)?;
5104
5105        match event {
5106            Event::StreamRead { .. } => {
5107                transmit.read = ReadState::Open;
5108            }
5109            Event::StreamWrite { .. } => transmit.write = WriteState::Open,
5110            _ => {}
5111        }
5112        Ok(())
5113    }
5114}
5115
5116/// Determine whether an intra-component read/write is allowed for the specified
5117/// `stream` or `future` payload type according to the component model
5118/// specification.
5119fn allow_intra_component_read_write(ty: Option<&InterfaceType>) -> bool {
5120    matches!(
5121        ty,
5122        None | Some(
5123            InterfaceType::S8
5124                | InterfaceType::U8
5125                | InterfaceType::S16
5126                | InterfaceType::U16
5127                | InterfaceType::S32
5128                | InterfaceType::U32
5129                | InterfaceType::S64
5130                | InterfaceType::U64
5131                | InterfaceType::Float32
5132                | InterfaceType::Float64
5133        )
5134    )
5135}
5136
5137/// Helper structure to manage moving a `T` in/out of an interior `Mutex` which
5138/// contains an
5139/// `Option<T>`
5140struct LockedState<T> {
5141    inner: TryMutex<Option<T>>,
5142}
5143
5144impl<T> LockedState<T> {
5145    /// Creates a new initial state with `value` stored.
5146    fn new(value: T) -> Self {
5147        Self {
5148            inner: TryMutex::new(Some(value)),
5149        }
5150    }
5151
5152    /// Attempts to lock the inner mutex and return its guard.
5153    ///
5154    /// # Errors
5155    ///
5156    /// Fails if this lock is either poisoned or if it's currently locked.
5157    /// As-used in this file there should never actually be contention on this
5158    /// lock nor recursive access so failing to acquire the lock is a fatal
5159    /// error that gets propagated upwards.
5160    fn try_lock(&self) -> Result<TryMutexGuard<'_, Option<T>>> {
5161        match self.inner.try_lock() {
5162            Some(lock) => Ok(lock),
5163            None => bail_bug!("should not have contention on state lock"),
5164        }
5165    }
5166
5167    /// Takes the inner `T` out of this state, returning it as a guard which
5168    /// will put it back when finished.
5169    ///
5170    /// # Errors
5171    ///
5172    /// Returns an error if the state `T` isn't present.
5173    fn take(&self) -> Result<LockedStateGuard<'_, T>> {
5174        let result = self.try_lock()?.take();
5175        match result {
5176            Some(result) => Ok(LockedStateGuard {
5177                value: ManuallyDrop::new(result),
5178                state: self,
5179            }),
5180            None => bail_bug!("lock value unexpectedly missing"),
5181        }
5182    }
5183
5184    /// Performs the operation `f` on the inner state `&mut T`.
5185    ///
5186    /// This will acquire the internal lock and invoke `f`, so `f` should not
5187    /// expect to be able to recursively acquire this lock.
5188    ///
5189    /// # Errors
5190    ///
5191    /// Returns an error if the state `T` isn't present.
5192    fn with<R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R> {
5193        let mut inner = self.try_lock()?;
5194        match &mut *inner {
5195            Some(state) => Ok(f(state)),
5196            None => bail_bug!("lock value unexpectedly missing"),
5197        }
5198    }
5199}
5200
5201/// Helper structure returned from [`LockedState::take`] which will put the
5202/// state specified by `value` back into the original lock once this is dropped.
5203struct LockedStateGuard<'a, T> {
5204    value: ManuallyDrop<T>,
5205    state: &'a LockedState<T>,
5206}
5207
5208impl<T> Deref for LockedStateGuard<'_, T> {
5209    type Target = T;
5210
5211    fn deref(&self) -> &T {
5212        &self.value
5213    }
5214}
5215
5216impl<T> DerefMut for LockedStateGuard<'_, T> {
5217    fn deref_mut(&mut self) -> &mut T {
5218        &mut self.value
5219    }
5220}
5221
5222impl<T> Drop for LockedStateGuard<'_, T> {
5223    fn drop(&mut self) {
5224        // SAFETY: `ManuallyDrop::take` requires that after invoked the
5225        // original value is not read. This is the `Drop` for this type which
5226        // means we have exclusive ownership and it is not read further in the
5227        // destructor, satisfying this requirement.
5228        let value = unsafe { ManuallyDrop::take(&mut self.value) };
5229
5230        // If this fails due to contention that's a bug, but we're not in a
5231        // position to panic due to this being a destructor nor return an error,
5232        // so defer the bug to showing up later.
5233        if let Ok(mut lock) = self.state.try_lock() {
5234            *lock = Some(value);
5235        }
5236    }
5237}
5238
5239#[cfg(test)]
5240mod tests {
5241    use super::*;
5242    use crate::{Engine, Store};
5243    use core::future::pending;
5244    use core::pin::pin;
5245    use std::sync::LazyLock;
5246
5247    static ENGINE: LazyLock<Engine> = LazyLock::new(Engine::default);
5248
5249    fn poll_future_producer<T>(rx: Pin<&mut T>, finish: bool) -> Poll<Result<Option<T::Item>>>
5250    where
5251        T: FutureProducer<()>,
5252    {
5253        rx.poll_produce(
5254            &mut Context::from_waker(Waker::noop()),
5255            Store::new(&ENGINE, ()).as_context_mut(),
5256            finish,
5257        )
5258    }
5259
5260    #[test]
5261    fn future_producer() {
5262        let mut fut = pin!(async { crate::error::Ok(()) });
5263        assert!(matches!(
5264            poll_future_producer(fut.as_mut(), false),
5265            Poll::Ready(Ok(Some(()))),
5266        ));
5267
5268        let mut fut = pin!(async { crate::error::Ok(()) });
5269        assert!(matches!(
5270            poll_future_producer(fut.as_mut(), true),
5271            Poll::Ready(Ok(Some(()))),
5272        ));
5273
5274        let mut fut = pin!(pending::<Result<()>>());
5275        assert!(matches!(
5276            poll_future_producer(fut.as_mut(), false),
5277            Poll::Pending,
5278        ));
5279        assert!(matches!(
5280            poll_future_producer(fut.as_mut(), true),
5281            Poll::Ready(Ok(None)),
5282        ));
5283
5284        let (tx, rx) = oneshot::channel();
5285        let mut rx = pin!(rx);
5286        assert!(matches!(
5287            poll_future_producer(rx.as_mut(), false),
5288            Poll::Pending,
5289        ));
5290        assert!(matches!(
5291            poll_future_producer(rx.as_mut(), true),
5292            Poll::Ready(Ok(None)),
5293        ));
5294        tx.send(()).unwrap();
5295        assert!(matches!(
5296            poll_future_producer(rx.as_mut(), true),
5297            Poll::Ready(Ok(Some(()))),
5298        ));
5299
5300        let (tx, rx) = oneshot::channel();
5301        let mut rx = pin!(rx);
5302        tx.send(()).unwrap();
5303        assert!(matches!(
5304            poll_future_producer(rx.as_mut(), false),
5305            Poll::Ready(Ok(Some(()))),
5306        ));
5307
5308        let (tx, rx) = oneshot::channel::<()>();
5309        let mut rx = pin!(rx);
5310        drop(tx);
5311        assert!(matches!(
5312            poll_future_producer(rx.as_mut(), false),
5313            Poll::Ready(Err(..)),
5314        ));
5315
5316        let (tx, rx) = oneshot::channel::<()>();
5317        let mut rx = pin!(rx);
5318        drop(tx);
5319        assert!(matches!(
5320            poll_future_producer(rx.as_mut(), true),
5321            Poll::Ready(Err(..)),
5322        ));
5323    }
5324}