@@ -263,12 +263,16 @@ impl<'a, T, B> Destination<'a, T, B> {
263263 /// This will return `Some(_)` if the reader is a guest; it will return
264264 /// `None` if the reader is the host.
265265 ///
266- /// Note that, if this returns `None(0)`, the producer must still attempt to
267- /// produce at least one item if the value of `finish` passed to
268- /// `StreamProducer::poll_produce` is false. In that case, the reader is
269- /// effectively asking when the producer will be able to produce items
270- /// without blocking (or reach a terminal state such as end-of-stream),
271- /// meaning the next non-zero read must complete without blocking.
266+ /// Note that this can return `Some(0)`. This means that the guest is
267+ /// attempting to perform a zero-length read which typically means that it's
268+ /// trying to wait for this stream to be ready-to-read but is not actually
269+ /// ready to receive the items yet. The host in this case is allowed to
270+ /// either block waiting for readiness or immediately complete the
271+ /// operation. The guest is expected to handle both cases. Some more
272+ /// discussion about this case can be found in the discussion of ["Stream
273+ /// Readiness" in the component-model repo][docs].
274+ ///
275+ /// [docs]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Concurrency.md#stream-readiness
272276 pub fn remaining ( & self , mut store : impl AsContextMut ) -> Option < usize > {
273277 let transmit = store
274278 . as_context_mut ( )
@@ -437,6 +441,21 @@ pub trait StreamProducer<D>: Send + 'static {
437441 ///
438442 /// This will be called whenever the reader starts a read.
439443 ///
444+ /// # Arguments
445+ ///
446+ /// * `self` - a `Pin`'d version of self to perform Rust-level
447+ /// future-related operations on.
448+ /// * `cx` - a Rust-related [`Context`] which is passed to other
449+ /// future-related operations or used to acquire a waker.
450+ /// * `store` - the Wasmtime store that this operation is happening within.
451+ /// Used, for example, to consult the state `D` associated with the store.
452+ /// * `destination` - the location that items are to be written to.
453+ /// * `finish` - a flag indicating whether the host should strive to
454+ /// immediately complete/cancel any pending operation. See below for more
455+ /// details.
456+ ///
457+ /// # Behavior
458+ ///
440459 /// If the implementation is able to produce one or more items immediately,
441460 /// it should write them to `destination` and return either
442461 /// `Poll::Ready(Ok(StreamResult::Completed))` if it expects to produce more
@@ -449,59 +468,109 @@ pub trait StreamProducer<D>: Send + 'static {
449468 /// anything to `destination`. Later, it should alert the waker when either
450469 /// the items arrive, the stream has ended, or an error occurs.
451470 ///
452- /// If the implementation is unable to produce any items immediately, but
453- /// expects to do so later, and `finish` is _true_, it should, if possible,
454- /// return `Poll::Ready(Ok(StreamResult::Cancelled))` immediately without
455- /// writing anything to `destination`. However, that might not be possible
456- /// if an earlier call to `poll_produce` kicked off an asynchronous
457- /// operation which needs to be completed (and possibly interrupted)
458- /// gracefully, in which case the implementation may return `Poll::Pending`
459- /// and later alert the waker as described above. In other words, when
460- /// `finish` is true, the implementation should prioritize returning a
461- /// result to the reader (even if no items can be produced) rather than wait
462- /// indefinitely for at least one item to arrive.
463- ///
464- /// In all of the above cases, the implementation may alternatively choose
465- /// to return `Err(_)` to indicate an unrecoverable error. This will cause
466- /// the guest (if any) to trap and render the component instance (if any)
467- /// unusable. The implementation should report errors that _are_
468- /// recoverable by other means (e.g. by writing to a `future`) and return
469- /// `Poll::Ready(Ok(StreamResult::Dropped))`.
470- ///
471- /// Note that the implementation should never return `Poll::Pending` after
472- /// writing one or more items to `destination`; if it does, the caller will
473- /// trap as if `Err(_)` was returned. Conversely, it should only return
474- /// `Poll::Ready(Ok(StreamResult::Cancelled))` without writing any items to
475- /// `destination` if called with `finish` set to true. If it does so when
476- /// `finish` is false, the caller will trap. Additionally, it should only
477- /// return `Poll::Ready(Ok(StreamResult::Completed))` after writing at least
478- /// one item to `destination` if it has capacity to accept that item;
479- /// otherwise, the caller will trap.
480- ///
481471 /// If more items are written to `destination` than the reader has immediate
482472 /// capacity to accept, they will be retained in memory by the caller and
483473 /// used to satisfy future reads, in which case `poll_produce` will only be
484474 /// called again once all those items have been delivered.
485475 ///
486- /// If this function is called with zero capacity
487- /// (i.e. `Destination::remaining` returns `Some(0)`), the implementation
488- /// should either:
476+ /// # Zero-length reads
477+ ///
478+ /// This function may be called with a zero-length capacity buffer
479+ /// (i.e. `Destination::remaining` returns `Some(0)`). This indicates that
480+ /// the guest wants to wait to see if an item is ready without actually
481+ /// reading the item. For example think of a UNIX `poll` function run on a
482+ /// TCP stream, seeing if it's readable without actually reading it.
483+ ///
484+ /// In this situation the host is allowed to either return immediately or
485+ /// wait for readiness. Note that waiting for readiness is not always
486+ /// possible. For example it's impossible to test if a Rust-native `Future`
487+ /// is ready without actually reading the item. Stream-specific
488+ /// optimizations, such as testing if a TCP stream is readable, may be
489+ /// possible however.
490+ ///
491+ /// For a zero-length read, the host is allowed to:
489492 ///
490493 /// - Return `Poll::Ready(Ok(StreamResult::Completed))` without writing
491- /// anything if it expects to be able to produce items immediately
492- /// (i.e. without first returning `Poll::Pending`) the next time
493- /// `poll_produce` is called with non-zero capacity _or_ if that cannot be
494- /// reliably determined.
494+ /// anything if it expects to be able to produce items immediately (i.e.
495+ /// without first returning `Poll::Pending`) the next time `poll_produce`
496+ /// is called with non-zero capacity. This is the best-case scenario of
497+ /// fulfilling the guest's desire -- items aren't read/buffered but the
498+ /// host is saying it's ready when the guest is.
499+ ///
500+ /// - Return `Poll::Ready(Ok(StreamResult::Completed))` without actually
501+ /// testing for readiness. The guest doesn't know this yet, but the guest
502+ /// will realize that zero-length reads won't work on this stream when a
503+ /// subsequent nonzero read attempt is made which returns `Poll::Pending`
504+ /// here.
495505 ///
496- /// - Return `Poll::Pending` if the next call to `poll_produce` with
497- /// non-zero capacity is likely to also return `Poll::Pending`.
506+ /// - Return `Poll::Pending` if the host has performed necessary async work
507+ /// to wait for this stream to be readable without actually reading
508+ /// anything. This is also a best-case scenario where the host is letting
509+ /// the guest know that nothing is ready yet. Later the zero-length read
510+ /// will complete and then the guest will attempt a nonzero-length read to
511+ /// actually read some bytes.
498512 ///
499513 /// - Return `Poll::Ready(Ok(StreamResult::Completed))` after calling
500- /// `Destination::set_buffer` with one more more items. Note, however, that
501- /// this creates the hazard that the items will never be received by the
502- /// guest if it decides not to do another non-zero-length read before
503- /// closing the stream. Moreover, if `Self::Item` is e.g. a `Resource<_>`,
504- /// they may end up leaking in that scenario.
514+ /// `Destination::set_buffer` with one more more items. Note, however,
515+ /// that this creates the hazard that the items will never be received by
516+ /// the guest if it decides not to do another non-zero-length read before
517+ /// closing the stream. Moreover, if `Self::Item` is e.g. a
518+ /// `Resource<_>`, they may end up leaking in that scenario. It is not
519+ /// recommended to do this and it's better to return
520+ /// `StreamResult::Completed` without buffering anything instead.
521+ ///
522+ /// For more discussion on zero-length reads see the [documentation in the
523+ /// component-model repo itself][docs].
524+ ///
525+ /// [docs]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Concurrency.md#stream-readiness
526+ ///
527+ /// # Return
528+ ///
529+ /// This function can return a number of possible cases from this function:
530+ ///
531+ /// * `Poll::Pending` - this operation cannot complete at this time. The
532+ /// Rust-level `Future::poll` contract applies here where a waker should
533+ /// be stored from the `cx` argument and be arranged to receive a
534+ /// notification when this implementation can make progress. For example
535+ /// if you call `Future::poll` on a sub-future, that's enough. If items
536+ /// were written to `destination` then a trap in the guest will be raised.
537+ ///
538+ /// Note that implementations should strive to avoid this return value
539+ /// when `finish` is `true`. In such a situation the guest is attempting
540+ /// to, for example, cancel a previous operation. By returning
541+ /// `Poll::Pending` the guest will be blocked during the cancellation
542+ /// request. If `finish` is `true` then `StreamResult::Cancelled` is
543+ /// favored to indicate that no items were read. If a short read happened,
544+ /// however, it's ok to return `StreamResult::Completed` indicating some
545+ /// items were read.
546+ ///
547+ /// * `Poll::Ok(StreamResult::Completed)` - items, if applicable, were
548+ /// written to the `destination`.
549+ ///
550+ /// * `Poll::Ok(StreamResult::Cancelled)` - used when `finish` is `true` and
551+ /// the implementation was able to successfully cancel any async work that
552+ /// a previous read kicked off, if any. The host should not buffer values
553+ /// received after returning `Cancelled` because the guest will not be
554+ /// aware of these values and the guest could close the stream after
555+ /// cancelling a read. Hosts should only return `Cancelled` when there are
556+ /// no more async operations in flight for a previous read.
557+ ///
558+ /// If items were written to `destination` then a trap in the guest will
559+ /// be raised. If `finish` is `false` then this return value will raise a
560+ /// trap in the guest.
561+ ///
562+ /// * `Poll::Ok(StreamResult::Dropped)` - end-of-stream marker, indicating
563+ /// that this producer should not be polled again. Note that items may
564+ /// still be written to `destination`.
565+ ///
566+ /// # Errors
567+ ///
568+ /// The implementation may alternatively choose to return `Err(_)` to
569+ /// indicate an unrecoverable error. This will cause the guest (if any) to
570+ /// trap and render the component instance (if any) unusable. The
571+ /// implementation should report errors that _are_ recoverable by other
572+ /// means (e.g. by writing to a `future`) and return
573+ /// `Poll::Ready(Ok(StreamResult::Dropped))`.
505574 fn poll_produce < ' a > (
506575 self : Pin < & mut Self > ,
507576 cx : & mut Context < ' _ > ,
0 commit comments