wasmtime/runtime/component/concurrent/
future_stream_any.rs1use crate::component::concurrent::futures_and_streams::{self, TransmitOrigin};
4use crate::component::func::{LiftContext, LowerContext, desc};
5use crate::component::matching::InstanceType;
6use crate::component::resources::HostResourceIndex;
7use crate::component::types::{FutureType, StreamType};
8use crate::component::{
9 ComponentInstanceId, ComponentType, FutureReader, Lift, Lower, StreamReader,
10};
11use crate::store::StoreOpaque;
12use crate::{AsContextMut, Result, bail};
13use core::any::TypeId;
14use core::mem::MaybeUninit;
15use wasmtime_environ::component::{
16 CanonicalAbiInfo, InterfaceType, TypeFutureTableIndex, TypeStreamTableIndex,
17};
18
19#[derive(Debug, Clone, PartialEq)]
50pub struct FutureAny {
51 idx: HostResourceIndex,
52 ty: PayloadType<FutureType>,
53}
54
55impl FutureAny {
56 pub fn try_into_future_reader<T>(self) -> Result<FutureReader<T>>
64 where
65 T: ComponentType + 'static,
66 {
67 self.ty
68 .typecheck_host::<T>(FutureType::equivalent_payload_host::<T>)?;
69 Ok(FutureReader::new_(self.idx))
70 }
71
72 pub fn try_from_future_reader<T>(
80 mut store: impl AsContextMut,
81 reader: FutureReader<T>,
82 ) -> Result<Self>
83 where
84 T: ComponentType + 'static,
85 {
86 let store = store.as_context_mut();
87 let ty = match store.0.transmit_origin(reader.idx())? {
88 TransmitOrigin::Host { .. } => PayloadType::new_host::<T>(),
89 TransmitOrigin::GuestFuture(id, ty) => PayloadType::new_guest_future(store.0, id, ty),
90 TransmitOrigin::GuestStream(..) => bail!("not a future"),
91 };
92 Ok(FutureAny {
93 idx: reader.idx(),
94 ty,
95 })
96 }
97
98 fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
99 let idx = futures_and_streams::lift_index_to_future(cx, ty, index)?;
100 let InterfaceType::Future(ty) = ty else {
101 unreachable!()
102 };
103 let ty = cx.types[ty].ty;
104 Ok(FutureAny {
105 idx,
106 ty: PayloadType::Guest(FutureType::from(ty, &cx.instance_type())),
112 })
113 }
114
115 pub fn close(&mut self, mut store: impl AsContextMut) -> Result<()> {
126 futures_and_streams::future_close(store.as_context_mut().0, self.idx)
127 }
128}
129
130unsafe impl ComponentType for FutureAny {
131 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
132
133 type Lower = <u32 as ComponentType>::Lower;
134
135 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
136 match ty {
137 InterfaceType::Future(_) => Ok(()),
138 other => bail!("expected `future`, found `{}`", desc(other)),
139 }
140 }
141}
142
143unsafe impl Lower for FutureAny {
144 fn linear_lower_to_flat<T>(
145 &self,
146 cx: &mut LowerContext<'_, T>,
147 ty: InterfaceType,
148 dst: &mut MaybeUninit<Self::Lower>,
149 ) -> Result<()> {
150 futures_and_streams::lower_future_to_index(self.idx, cx, ty)?.linear_lower_to_flat(
151 cx,
152 InterfaceType::U32,
153 dst,
154 )
155 }
156
157 fn linear_lower_to_memory<T>(
158 &self,
159 cx: &mut LowerContext<'_, T>,
160 ty: InterfaceType,
161 offset: usize,
162 ) -> Result<()> {
163 futures_and_streams::lower_future_to_index(self.idx, cx, ty)?.linear_lower_to_memory(
164 cx,
165 InterfaceType::U32,
166 offset,
167 )
168 }
169}
170
171unsafe impl Lift for FutureAny {
172 fn linear_lift_from_flat(
173 cx: &mut LiftContext<'_>,
174 ty: InterfaceType,
175 src: &Self::Lower,
176 ) -> Result<Self> {
177 let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
178 Self::lift_from_index(cx, ty, index)
179 }
180
181 fn linear_lift_from_memory(
182 cx: &mut LiftContext<'_>,
183 ty: InterfaceType,
184 bytes: &[u8],
185 ) -> Result<Self> {
186 let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
187 Self::lift_from_index(cx, ty, index)
188 }
189}
190
191#[derive(Debug, Clone, PartialEq)]
222pub struct StreamAny {
223 idx: HostResourceIndex,
224 ty: PayloadType<StreamType>,
225}
226
227impl StreamAny {
228 pub fn try_into_stream_reader<T>(self) -> Result<StreamReader<T>>
236 where
237 T: ComponentType + 'static,
238 {
239 self.ty
240 .typecheck_host::<T>(StreamType::equivalent_payload_host::<T>)?;
241 Ok(StreamReader::new_(self.idx))
242 }
243
244 pub fn try_from_stream_reader<T>(
252 mut store: impl AsContextMut,
253 reader: StreamReader<T>,
254 ) -> Result<Self>
255 where
256 T: ComponentType + 'static,
257 {
258 let store = store.as_context_mut();
259 let ty = match store.0.transmit_origin(reader.idx())? {
260 TransmitOrigin::Host { .. } => PayloadType::new_host::<T>(),
261 TransmitOrigin::GuestStream(id, ty) => PayloadType::new_guest_stream(store.0, id, ty),
262 TransmitOrigin::GuestFuture(..) => bail!("not a stream"),
263 };
264 Ok(StreamAny {
265 idx: reader.idx(),
266 ty,
267 })
268 }
269
270 fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
271 let idx = futures_and_streams::lift_index_to_stream(cx, ty, index)?;
272 let InterfaceType::Stream(ty) = ty else {
273 unreachable!()
274 };
275 let ty = cx.types[ty].ty;
276 Ok(StreamAny {
277 idx,
278 ty: PayloadType::Guest(StreamType::from(ty, &cx.instance_type())),
282 })
283 }
284
285 pub fn close(&mut self, mut store: impl AsContextMut) -> Result<()> {
296 futures_and_streams::stream_close(store.as_context_mut().0, self.idx)
297 }
298}
299
300unsafe impl ComponentType for StreamAny {
301 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
302
303 type Lower = <u32 as ComponentType>::Lower;
304
305 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
306 match ty {
307 InterfaceType::Stream(_) => Ok(()),
308 other => bail!("expected `stream`, found `{}`", desc(other)),
309 }
310 }
311}
312
313unsafe impl Lower for StreamAny {
314 fn linear_lower_to_flat<T>(
315 &self,
316 cx: &mut LowerContext<'_, T>,
317 ty: InterfaceType,
318 dst: &mut MaybeUninit<Self::Lower>,
319 ) -> Result<()> {
320 futures_and_streams::lower_stream_to_index(self.idx, cx, ty)?.linear_lower_to_flat(
321 cx,
322 InterfaceType::U32,
323 dst,
324 )
325 }
326
327 fn linear_lower_to_memory<T>(
328 &self,
329 cx: &mut LowerContext<'_, T>,
330 ty: InterfaceType,
331 offset: usize,
332 ) -> Result<()> {
333 futures_and_streams::lower_stream_to_index(self.idx, cx, ty)?.linear_lower_to_memory(
334 cx,
335 InterfaceType::U32,
336 offset,
337 )
338 }
339}
340
341unsafe impl Lift for StreamAny {
342 fn linear_lift_from_flat(
343 cx: &mut LiftContext<'_>,
344 ty: InterfaceType,
345 src: &Self::Lower,
346 ) -> Result<Self> {
347 let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
348 Self::lift_from_index(cx, ty, index)
349 }
350
351 fn linear_lift_from_memory(
352 cx: &mut LiftContext<'_>,
353 ty: InterfaceType,
354 bytes: &[u8],
355 ) -> Result<Self> {
356 let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
357 Self::lift_from_index(cx, ty, index)
358 }
359}
360
361#[derive(Debug, Clone, PartialEq)]
362enum PayloadType<T> {
363 Guest(T),
364 Host(TypeId),
365}
366
367impl PayloadType<FutureType> {
368 fn new_guest_future(
369 store: &StoreOpaque,
370 id: ComponentInstanceId,
371 ty: TypeFutureTableIndex,
372 ) -> Self {
373 let types = InstanceType::new(&store.component_instance(id));
374 let ty = types.types[ty].ty;
375 PayloadType::Guest(FutureType::from(ty, &types))
376 }
377}
378
379impl PayloadType<StreamType> {
380 fn new_guest_stream(
381 store: &StoreOpaque,
382 id: ComponentInstanceId,
383 ty: TypeStreamTableIndex,
384 ) -> Self {
385 let types = InstanceType::new(&store.component_instance(id));
386 let ty = types.types[ty].ty;
387 PayloadType::Guest(StreamType::from(ty, &types))
388 }
389}
390
391impl<T> PayloadType<T> {
392 fn new_host<P>() -> Self
393 where
394 P: ComponentType + 'static,
395 {
396 PayloadType::Host(TypeId::of::<P>())
397 }
398
399 fn typecheck_host<P>(&self, equivalent: fn(&T) -> Result<()>) -> Result<()>
400 where
401 P: ComponentType + 'static,
402 {
403 match self {
404 Self::Guest(ty) => equivalent(ty),
405 Self::Host(id) => {
406 if *id == TypeId::of::<P>() {
407 Ok(())
408 } else {
409 bail!("future payload types differ")
410 }
411 }
412 }
413 }
414}