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#[derive(Copy, Clone, Debug)]
51pub enum TransmitKind {
52 Stream,
53 Future,
54}
55
56#[derive(Copy, Clone, Debug, PartialEq)]
58pub enum ReturnCode {
59 Blocked,
60 Completed(ItemCount),
61 Dropped(ItemCount),
62 Cancelled(ItemCount),
63}
64
65impl ReturnCode {
66 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 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#[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 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 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 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 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 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#[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 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
229fn 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 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 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 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#[derive(Debug, PartialEq, Eq, PartialOrd)]
329pub(super) struct ErrorContextState {
330 pub(crate) debug_msg: String,
332}
333
334#[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
356pub 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 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 pub fn take_buffer(&mut self) -> B
381 where
382 B: Default,
383 {
384 mem::take(self.buffer)
385 }
386
387 pub fn set_buffer(&mut self, buffer: B) {
397 *self.buffer = buffer;
398 }
399
400 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 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
464pub 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 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 pub fn mark_written(&mut self, count: usize) {
538 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 *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 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#[derive(Copy, Clone, Debug)]
584pub enum StreamResult {
585 Completed,
588 Cancelled,
593 Dropped,
596}
597
598pub trait StreamProducer<D>: Send + 'static {
600 type Item;
602
603 type Buffer: WriteBuffer<Self::Item> + Default;
605
606 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 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
870pub 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 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 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 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 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
977pub 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 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 pub fn mark_read(&mut self, count: usize) {
1047 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 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
1087pub trait StreamConsumer<D>: Send + 'static {
1089 type Item;
1091
1092 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
1187pub trait FutureProducer<D>: Send + 'static {
1189 type Item;
1191
1192 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
1231pub trait FutureConsumer<D>: Send + 'static {
1233 type Item;
1235
1236 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
1256pub struct FutureReader<T> {
1263 idx: HostResourceIndex,
1264 _phantom: PhantomData<T>,
1265}
1266
1267impl<T> FutureReader<T> {
1268 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 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 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 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 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 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 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 pub fn close(&mut self, mut store: impl AsContextMut) -> Result<()> {
1419 future_close(store.as_context_mut().0, self.idx)
1420 }
1421
1422 pub fn close_with(&mut self, accessor: impl AsAccessor) -> Result<()> {
1424 accessor.as_accessor().with(|access| self.close(access))
1425 }
1426
1427 pub fn guard<A>(self, accessor: A) -> GuardedFutureReader<T, A>
1433 where
1434 A: AsAccessor,
1435 {
1436 GuardedFutureReader::new(accessor, self)
1437 }
1438
1439 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 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
1479pub(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
1497fn 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
1530pub(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
1548unsafe 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
1566unsafe 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
1591unsafe 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
1612pub struct GuardedFutureReader<T, A>
1620where
1621 A: AsAccessor,
1622{
1623 reader: Option<FutureReader<T>>,
1627 accessor: A,
1628}
1629
1630impl<T, A> GuardedFutureReader<T, A>
1631where
1632 A: AsAccessor,
1633{
1634 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 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 let result = reader.close_with(&self.accessor);
1681 debug_assert!(result.is_ok());
1682 }
1683 }
1684}
1685
1686pub struct StreamReader<T> {
1693 idx: HostResourceIndex,
1694 _phantom: PhantomData<T>,
1695}
1696
1697impl<T> StreamReader<T> {
1698 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 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 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 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 pub fn close(&mut self, mut store: impl AsContextMut) -> Result<()> {
1810 stream_close(store.as_context_mut().0, self.idx)
1811 }
1812
1813 pub fn close_with(&mut self, accessor: impl AsAccessor) -> Result<()> {
1815 accessor.as_accessor().with(|access| self.close(access))
1816 }
1817
1818 pub fn guard<A>(self, accessor: A) -> GuardedStreamReader<T, A>
1824 where
1825 A: AsAccessor,
1826 {
1827 GuardedStreamReader::new(accessor, self)
1828 }
1829
1830 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 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
1870pub(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
1888pub(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
1906unsafe 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
1924unsafe 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
1949unsafe 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
1970pub struct GuardedStreamReader<T, A>
1978where
1979 A: AsAccessor,
1980{
1981 reader: Option<StreamReader<T>>,
1985 accessor: A,
1986}
1987
1988impl<T, A> GuardedStreamReader<T, A>
1989where
1990 A: AsAccessor,
1991{
1992 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 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 let result = reader.close_with(&self.accessor);
2036 debug_assert!(result.is_ok());
2037 }
2038 }
2039}
2040
2041pub struct ErrorContext {
2043 rep: u32,
2044}
2045
2046impl ErrorContext {
2047 pub(crate) fn new(rep: u32) -> Self {
2048 Self { rep }
2049 }
2050
2051 pub fn into_val(self) -> Val {
2053 Val::ErrorContext(ErrorContextAny(self.rep))
2054 }
2055
2056 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}
2097unsafe 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
2112unsafe 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
2141unsafe 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
2162pub(super) struct TransmitHandle {
2164 pub(super) common: WaitableCommon,
2165 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
2184struct TransmitState {
2186 write_handle: TableId<TransmitHandle>,
2188 read_handle: TableId<TransmitHandle>,
2190 write: WriteState,
2192 read: ReadState,
2194 done: bool,
2196 pub(super) origin: TransmitOrigin,
2200}
2201
2202#[derive(Copy, Clone)]
2203pub(super) enum TransmitOrigin {
2204 Host {
2205 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
2246enum WriteState {
2248 Open,
2250 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 HostReady {
2263 produce: PollStream,
2264 try_into: TryInto,
2265 guest_offset: ItemCount,
2266 cancel: bool,
2267 cancel_waker: Option<Waker>,
2268 },
2269 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
2284enum ReadState {
2286 Open,
2288 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 HostReady {
2302 consume: PollStream,
2303 guest_offset: ItemCount,
2304 cancel: bool,
2305 cancel_waker: Option<Waker>,
2306 },
2307 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 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 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 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 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 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 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 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 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 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 match mem::replace(&mut transmit.read, new_state) {
2580 ReadState::GuestReady { ty, handle, .. } => {
2584 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 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 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 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 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 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 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 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 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 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 Err(oneshot::Canceled) => {
3168 bail!("stream write cancelled before it could complete")
3169 }
3170 }
3171 } else {
3172 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
3251fn 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 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 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 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 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 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 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 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 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 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 if count == 0 {
3595 return Ok(());
3596 }
3597 let abi = types.canonical_abi(&payload);
3598 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let _ = state
4441 .global_error_context_ref_counts
4442 .insert(global_ref_count_idx, GlobalErrorContextRefCount(1));
4443
4444 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
4767fn 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
4809fn 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 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 fn new_transmit(
4973 &mut self,
4974 origin: TransmitOrigin,
4975 ) -> Result<(TableId<TransmitHandle>, TableId<TransmitHandle>)> {
4976 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 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 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
5116fn 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
5137struct LockedState<T> {
5141 inner: TryMutex<Option<T>>,
5142}
5143
5144impl<T> LockedState<T> {
5145 fn new(value: T) -> Self {
5147 Self {
5148 inner: TryMutex::new(Some(value)),
5149 }
5150 }
5151
5152 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 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 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
5201struct 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 let value = unsafe { ManuallyDrop::take(&mut self.value) };
5229
5230 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}