1use super::{convert, wasi_2023_10_18::convert_result};
2use crate::sockets::{SpinSockets, SpinSocketsView};
3use futures::{
4 Stream as _,
5 channel::{mpsc, oneshot},
6};
7use pin_project_lite::pin_project;
8use spin_factors::anyhow;
9use std::pin::Pin;
10use std::task::{Context, Poll};
11use wasmtime::component::{
12 Access, Accessor, Destination, FutureConsumer, FutureProducer, FutureReader, HasData, Lift,
13 Linker, Lower, Resource, Source, StreamConsumer, StreamProducer, StreamReader, StreamResult,
14};
15use wasmtime::error::Context as _;
16use wasmtime::{AsContextMut, StoreContextMut};
17use wasmtime_wasi::cli::{WasiCli, WasiCliCtxView};
18use wasmtime_wasi::clocks::{WasiClocks, WasiClocksCtxView};
19use wasmtime_wasi::filesystem::{WasiFilesystem, WasiFilesystemCtxView};
20use wasmtime_wasi::p3::bindings as latest;
21use wasmtime_wasi::random::{WasiRandom, WasiRandomCtx};
22use wasmtime_wasi::sockets::{WasiSockets, WasiSocketsCtxView};
23
24mod bindings {
25 use super::latest;
26
27 wasmtime::component::bindgen!({
28 path: "../../wit",
29 world: "wasi:cli/command@0.3.0-rc-2026-03-15",
30 imports: {
31 "wasi:cli/stdin": store | trappable,
32 "wasi:cli/stdout": store | trappable,
33 "wasi:cli/stderr": store | trappable,
34 "wasi:filesystem/types.[method]descriptor.read-via-stream": store | trappable,
35 "wasi:filesystem/types.[method]descriptor.write-via-stream": store | trappable,
36 "wasi:filesystem/types.[method]descriptor.append-via-stream": store | trappable,
37 "wasi:filesystem/types.[method]descriptor.read-directory": store | trappable,
38 "wasi:sockets/types.[method]tcp-socket.bind": async | trappable,
39 "wasi:sockets/types.[method]tcp-socket.listen": async | store | trappable,
40 "wasi:sockets/types.[method]tcp-socket.send": store | trappable,
41 "wasi:sockets/types.[method]tcp-socket.receive": store | trappable,
42 "wasi:sockets/types.[method]udp-socket.bind": async | trappable,
43 "wasi:sockets/types.[method]udp-socket.connect": async | trappable,
44 default: trappable,
45 },
46 exports: { default: async | store },
47 with: {
48 "wasi:cli/terminal-input.terminal-input": latest::cli::terminal_input::TerminalInput,
49 "wasi:cli/terminal-output.terminal-output": latest::cli::terminal_output::TerminalOutput,
50 "wasi:filesystem/types.descriptor": latest::filesystem::types::Descriptor,
51 "wasi:sockets/types.tcp-socket": latest::sockets::types::TcpSocket,
52 "wasi:sockets/types.udp-socket": latest::sockets::types::UdpSocket,
53 },
54 });
55}
56
57mod wasi {
58 pub use super::bindings::wasi::{
59 cli0_3_0_rc_2026_03_15 as cli, clocks0_3_0_rc_2026_03_15 as clocks,
60 filesystem0_3_0_rc_2026_03_15 as filesystem, random0_3_0_rc_2026_03_15 as random,
61 sockets0_3_0_rc_2026_03_15 as sockets,
62 };
63}
64
65pub fn add_to_linker<T>(
66 linker: &mut Linker<T>,
67 random_closure: fn(&mut T) -> &mut WasiRandomCtx,
68 clocks_closure: fn(&mut T) -> WasiClocksCtxView<'_>,
69 cli_closure: fn(&mut T) -> WasiCliCtxView<'_>,
70 filesystem_closure: fn(&mut T) -> WasiFilesystemCtxView<'_>,
71 sockets_closure: fn(&mut T) -> SpinSocketsView<'_, T>,
72 wasi_sockets_closure: fn(&mut T) -> WasiSocketsCtxView<'_>,
73) -> anyhow::Result<()>
74where
75 T: Send + 'static,
76{
77 wasi::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
78 wasi::clocks::system_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
79 wasi::filesystem::types::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
80 wasi::filesystem::preopens::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
81 wasi::random::random::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
82 wasi::random::insecure::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
83 wasi::random::insecure_seed::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
84 wasi::cli::exit::add_to_linker::<_, WasiCli>(
85 linker,
86 &wasi::cli::exit::LinkOptions::default(),
87 cli_closure,
88 )?;
89 wasi::cli::environment::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
90 wasi::cli::stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
91 wasi::cli::stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
92 wasi::cli::stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
93 wasi::cli::terminal_input::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
94 wasi::cli::terminal_output::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
95 wasi::cli::terminal_stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
96 wasi::cli::terminal_stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
97 wasi::cli::terminal_stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
98 wasi::sockets::types::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
99 wasi::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, wasi_sockets_closure)?;
100 Ok(())
101}
102
103impl wasi::clocks::types::Host for WasiClocksCtxView<'_> {}
104
105impl wasi::clocks::system_clock::Host for WasiClocksCtxView<'_> {
106 fn now(&mut self) -> wasmtime::Result<wasi::clocks::system_clock::Instant> {
107 latest::clocks::system_clock::Host::now(self).map(|v| v.into())
108 }
109
110 fn get_resolution(&mut self) -> wasmtime::Result<wasi::clocks::types::Duration> {
111 latest::clocks::system_clock::Host::get_resolution(self)
112 }
113}
114
115impl<T> wasi::clocks::monotonic_clock::HostWithStore<T> for WasiClocks {
116 async fn wait_until(
117 store: &Accessor<T, Self>,
118 when: wasi::clocks::monotonic_clock::Mark,
119 ) -> wasmtime::Result<()> {
120 latest::clocks::monotonic_clock::HostWithStore::wait_until(store, when).await
121 }
122
123 async fn wait_for(
124 store: &Accessor<T, Self>,
125 duration: wasi::clocks::types::Duration,
126 ) -> wasmtime::Result<()> {
127 latest::clocks::monotonic_clock::HostWithStore::wait_for(store, duration).await
128 }
129}
130
131impl wasi::clocks::monotonic_clock::Host for WasiClocksCtxView<'_> {
132 fn now(&mut self) -> wasmtime::Result<wasi::clocks::monotonic_clock::Mark> {
133 latest::clocks::monotonic_clock::Host::now(self)
134 }
135
136 fn get_resolution(&mut self) -> wasmtime::Result<wasi::clocks::types::Duration> {
137 latest::clocks::monotonic_clock::Host::get_resolution(self)
138 }
139}
140
141impl wasi::filesystem::types::Host for WasiFilesystemCtxView<'_> {}
142
143impl<T> wasi::filesystem::types::HostDescriptorWithStore<T> for WasiFilesystem {
144 fn read_via_stream(
145 mut store: Access<'_, T, Self>,
146 fd: Resource<wasi::filesystem::types::Descriptor>,
147 offset: wasi::filesystem::types::Filesize,
148 ) -> wasmtime::Result<(
149 StreamReader<u8>,
150 FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>,
151 )> {
152 latest::filesystem::types::HostDescriptorWithStore::read_via_stream(
153 reborrow(&mut store),
154 fd,
155 offset,
156 )
157 .and_then(|(stream, future)| {
158 Ok((stream, future.try_map(store, |v| v.map_err(|v| v.into()))?))
159 })
160 }
161
162 fn write_via_stream(
163 mut store: Access<'_, T, Self>,
164 fd: Resource<wasi::filesystem::types::Descriptor>,
165 data: StreamReader<u8>,
166 offset: wasi::filesystem::types::Filesize,
167 ) -> wasmtime::Result<FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>> {
168 latest::filesystem::types::HostDescriptorWithStore::write_via_stream(
169 reborrow(&mut store),
170 fd,
171 data,
172 offset,
173 )
174 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
175 }
176
177 fn append_via_stream(
178 mut store: Access<'_, T, Self>,
179 fd: Resource<wasi::filesystem::types::Descriptor>,
180 data: StreamReader<u8>,
181 ) -> wasmtime::Result<FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>> {
182 latest::filesystem::types::HostDescriptorWithStore::append_via_stream(
183 reborrow(&mut store),
184 fd,
185 data,
186 )
187 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
188 }
189
190 async fn advise(
191 store: &Accessor<T, Self>,
192 fd: Resource<wasi::filesystem::types::Descriptor>,
193 offset: wasi::filesystem::types::Filesize,
194 length: wasi::filesystem::types::Filesize,
195 advice: wasi::filesystem::types::Advice,
196 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
197 convert_result(
198 latest::filesystem::types::HostDescriptorWithStore::advise(
199 store,
200 fd,
201 offset,
202 length,
203 advice.into(),
204 )
205 .await,
206 )
207 }
208
209 async fn sync_data(
210 store: &Accessor<T, Self>,
211 fd: Resource<wasi::filesystem::types::Descriptor>,
212 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
213 convert_result(
214 latest::filesystem::types::HostDescriptorWithStore::sync_data(store, fd).await,
215 )
216 }
217
218 async fn get_flags(
219 store: &Accessor<T, Self>,
220 fd: Resource<wasi::filesystem::types::Descriptor>,
221 ) -> wasmtime::Result<
222 Result<wasi::filesystem::types::DescriptorFlags, wasi::filesystem::types::ErrorCode>,
223 > {
224 convert_result(
225 latest::filesystem::types::HostDescriptorWithStore::get_flags(store, fd).await,
226 )
227 }
228
229 async fn get_type(
230 store: &Accessor<T, Self>,
231 fd: Resource<wasi::filesystem::types::Descriptor>,
232 ) -> wasmtime::Result<
233 Result<wasi::filesystem::types::DescriptorType, wasi::filesystem::types::ErrorCode>,
234 > {
235 convert_result(
236 latest::filesystem::types::HostDescriptorWithStore::get_type(store, fd).await,
237 )
238 }
239
240 async fn set_size(
241 store: &Accessor<T, Self>,
242 fd: Resource<wasi::filesystem::types::Descriptor>,
243 size: wasi::filesystem::types::Filesize,
244 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
245 convert_result(
246 latest::filesystem::types::HostDescriptorWithStore::set_size(store, fd, size).await,
247 )
248 }
249
250 async fn set_times(
251 store: &Accessor<T, Self>,
252 fd: Resource<wasi::filesystem::types::Descriptor>,
253 data_access_timestamp: wasi::filesystem::types::NewTimestamp,
254 data_modification_timestamp: wasi::filesystem::types::NewTimestamp,
255 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
256 convert_result(
257 latest::filesystem::types::HostDescriptorWithStore::set_times(
258 store,
259 fd,
260 data_access_timestamp.into(),
261 data_modification_timestamp.into(),
262 )
263 .await,
264 )
265 }
266
267 fn read_directory(
268 mut store: Access<'_, T, Self>,
269 fd: Resource<wasi::filesystem::types::Descriptor>,
270 ) -> wasmtime::Result<(
271 StreamReader<wasi::filesystem::types::DirectoryEntry>,
272 FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>,
273 )> {
274 latest::filesystem::types::HostDescriptorWithStore::read_directory(reborrow(&mut store), fd)
275 .and_then(|(stream, future)| {
276 Ok((
277 stream.try_map(reborrow(&mut store), |v| v.into())?,
278 future.try_map(store, |v| v.map_err(|v| v.into()))?,
279 ))
280 })
281 }
282
283 async fn sync(
284 store: &Accessor<T, Self>,
285 fd: Resource<wasi::filesystem::types::Descriptor>,
286 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
287 convert_result(latest::filesystem::types::HostDescriptorWithStore::sync(store, fd).await)
288 }
289
290 async fn create_directory_at(
291 store: &Accessor<T, Self>,
292 fd: Resource<wasi::filesystem::types::Descriptor>,
293 path: String,
294 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
295 convert_result(
296 latest::filesystem::types::HostDescriptorWithStore::create_directory_at(
297 store, fd, path,
298 )
299 .await,
300 )
301 }
302
303 async fn stat(
304 store: &Accessor<T, Self>,
305 fd: Resource<wasi::filesystem::types::Descriptor>,
306 ) -> wasmtime::Result<
307 Result<wasi::filesystem::types::DescriptorStat, wasi::filesystem::types::ErrorCode>,
308 > {
309 convert_result(latest::filesystem::types::HostDescriptorWithStore::stat(store, fd).await)
310 }
311
312 async fn stat_at(
313 store: &Accessor<T, Self>,
314 fd: Resource<wasi::filesystem::types::Descriptor>,
315 path_flags: wasi::filesystem::types::PathFlags,
316 path: String,
317 ) -> wasmtime::Result<
318 Result<wasi::filesystem::types::DescriptorStat, wasi::filesystem::types::ErrorCode>,
319 > {
320 convert_result(
321 latest::filesystem::types::HostDescriptorWithStore::stat_at(
322 store,
323 fd,
324 path_flags.into(),
325 path,
326 )
327 .await,
328 )
329 }
330
331 async fn set_times_at(
332 store: &Accessor<T, Self>,
333 fd: Resource<wasi::filesystem::types::Descriptor>,
334 path_flags: wasi::filesystem::types::PathFlags,
335 path: String,
336 data_access_timestamp: wasi::filesystem::types::NewTimestamp,
337 data_modification_timestamp: wasi::filesystem::types::NewTimestamp,
338 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
339 convert_result(
340 latest::filesystem::types::HostDescriptorWithStore::set_times_at(
341 store,
342 fd,
343 path_flags.into(),
344 path,
345 data_access_timestamp.into(),
346 data_modification_timestamp.into(),
347 )
348 .await,
349 )
350 }
351
352 async fn link_at(
353 store: &Accessor<T, Self>,
354 fd: Resource<wasi::filesystem::types::Descriptor>,
355 old_path_flags: wasi::filesystem::types::PathFlags,
356 old_path: String,
357 new_fd: Resource<wasi::filesystem::types::Descriptor>,
358 new_path: String,
359 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
360 convert_result(
361 latest::filesystem::types::HostDescriptorWithStore::link_at(
362 store,
363 fd,
364 old_path_flags.into(),
365 old_path,
366 new_fd,
367 new_path,
368 )
369 .await,
370 )
371 }
372
373 async fn open_at(
374 store: &Accessor<T, Self>,
375 fd: Resource<wasi::filesystem::types::Descriptor>,
376 path_flags: wasi::filesystem::types::PathFlags,
377 path: String,
378 open_flags: wasi::filesystem::types::OpenFlags,
379 flags: wasi::filesystem::types::DescriptorFlags,
380 ) -> wasmtime::Result<
381 Result<Resource<wasi::filesystem::types::Descriptor>, wasi::filesystem::types::ErrorCode>,
382 > {
383 convert_result(
384 latest::filesystem::types::HostDescriptorWithStore::open_at(
385 store,
386 fd,
387 path_flags.into(),
388 path,
389 open_flags.into(),
390 flags.into(),
391 )
392 .await,
393 )
394 }
395
396 async fn readlink_at(
397 store: &Accessor<T, Self>,
398 fd: Resource<wasi::filesystem::types::Descriptor>,
399 path: String,
400 ) -> wasmtime::Result<Result<String, wasi::filesystem::types::ErrorCode>> {
401 convert_result(
402 latest::filesystem::types::HostDescriptorWithStore::readlink_at(store, fd, path).await,
403 )
404 }
405
406 async fn remove_directory_at(
407 store: &Accessor<T, Self>,
408 fd: Resource<wasi::filesystem::types::Descriptor>,
409 path: String,
410 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
411 convert_result(
412 latest::filesystem::types::HostDescriptorWithStore::remove_directory_at(
413 store, fd, path,
414 )
415 .await,
416 )
417 }
418
419 async fn rename_at(
420 store: &Accessor<T, Self>,
421 fd: Resource<wasi::filesystem::types::Descriptor>,
422 old_path: String,
423 new_fd: Resource<wasi::filesystem::types::Descriptor>,
424 new_path: String,
425 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
426 convert_result(
427 latest::filesystem::types::HostDescriptorWithStore::rename_at(
428 store, fd, old_path, new_fd, new_path,
429 )
430 .await,
431 )
432 }
433
434 async fn symlink_at(
435 store: &Accessor<T, Self>,
436 fd: Resource<wasi::filesystem::types::Descriptor>,
437 old_path: String,
438 new_path: String,
439 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
440 convert_result(
441 latest::filesystem::types::HostDescriptorWithStore::symlink_at(
442 store, fd, old_path, new_path,
443 )
444 .await,
445 )
446 }
447
448 async fn unlink_file_at(
449 store: &Accessor<T, Self>,
450 fd: Resource<wasi::filesystem::types::Descriptor>,
451 path: String,
452 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
453 convert_result(
454 latest::filesystem::types::HostDescriptorWithStore::unlink_file_at(store, fd, path)
455 .await,
456 )
457 }
458
459 async fn is_same_object(
460 store: &Accessor<T, Self>,
461 fd: Resource<wasi::filesystem::types::Descriptor>,
462 other: Resource<wasi::filesystem::types::Descriptor>,
463 ) -> wasmtime::Result<bool> {
464 latest::filesystem::types::HostDescriptorWithStore::is_same_object(store, fd, other).await
465 }
466
467 async fn metadata_hash(
468 store: &Accessor<T, Self>,
469 fd: Resource<wasi::filesystem::types::Descriptor>,
470 ) -> wasmtime::Result<
471 Result<wasi::filesystem::types::MetadataHashValue, wasi::filesystem::types::ErrorCode>,
472 > {
473 convert_result(
474 latest::filesystem::types::HostDescriptorWithStore::metadata_hash(store, fd).await,
475 )
476 }
477
478 async fn metadata_hash_at(
479 store: &Accessor<T, Self>,
480 fd: Resource<wasi::filesystem::types::Descriptor>,
481 path_flags: wasi::filesystem::types::PathFlags,
482 path: String,
483 ) -> wasmtime::Result<
484 Result<wasi::filesystem::types::MetadataHashValue, wasi::filesystem::types::ErrorCode>,
485 > {
486 convert_result(
487 latest::filesystem::types::HostDescriptorWithStore::metadata_hash_at(
488 store,
489 fd,
490 path_flags.into(),
491 path,
492 )
493 .await,
494 )
495 }
496}
497
498impl wasi::filesystem::types::HostDescriptor for WasiFilesystemCtxView<'_> {
499 fn drop(&mut self, fd: Resource<wasi::filesystem::types::Descriptor>) -> wasmtime::Result<()> {
500 latest::filesystem::types::HostDescriptor::drop(self, fd)
501 }
502}
503
504impl wasi::filesystem::preopens::Host for WasiFilesystemCtxView<'_> {
505 fn get_directories(
506 &mut self,
507 ) -> wasmtime::Result<Vec<(Resource<wasi::filesystem::types::Descriptor>, String)>> {
508 latest::filesystem::preopens::Host::get_directories(self)
509 }
510}
511
512impl wasi::random::random::Host for WasiRandomCtx {
513 fn get_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
514 latest::random::random::Host::get_random_bytes(self, len)
515 }
516
517 fn get_random_u64(&mut self) -> wasmtime::Result<u64> {
518 latest::random::random::Host::get_random_u64(self)
519 }
520}
521
522impl wasi::random::insecure::Host for WasiRandomCtx {
523 fn get_insecure_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
524 latest::random::insecure::Host::get_insecure_random_bytes(self, len)
525 }
526
527 fn get_insecure_random_u64(&mut self) -> wasmtime::Result<u64> {
528 latest::random::insecure::Host::get_insecure_random_u64(self)
529 }
530}
531
532impl wasi::random::insecure_seed::Host for WasiRandomCtx {
533 fn get_insecure_seed(&mut self) -> wasmtime::Result<(u64, u64)> {
534 latest::random::insecure_seed::Host::get_insecure_seed(self)
535 }
536}
537
538impl wasi::cli::terminal_input::Host for WasiCliCtxView<'_> {}
539impl wasi::cli::terminal_output::Host for WasiCliCtxView<'_> {}
540
541impl wasi::cli::terminal_input::HostTerminalInput for WasiCliCtxView<'_> {
542 fn drop(
543 &mut self,
544 rep: Resource<wasi::cli::terminal_input::TerminalInput>,
545 ) -> wasmtime::Result<()> {
546 latest::cli::terminal_input::HostTerminalInput::drop(self, rep)
547 }
548}
549
550impl wasi::cli::terminal_output::HostTerminalOutput for WasiCliCtxView<'_> {
551 fn drop(
552 &mut self,
553 rep: Resource<wasi::cli::terminal_output::TerminalOutput>,
554 ) -> wasmtime::Result<()> {
555 latest::cli::terminal_output::HostTerminalOutput::drop(self, rep)
556 }
557}
558
559impl wasi::cli::terminal_stdin::Host for WasiCliCtxView<'_> {
560 fn get_terminal_stdin(
561 &mut self,
562 ) -> wasmtime::Result<Option<Resource<wasi::cli::terminal_input::TerminalInput>>> {
563 latest::cli::terminal_stdin::Host::get_terminal_stdin(self)
564 }
565}
566
567impl wasi::cli::terminal_stdout::Host for WasiCliCtxView<'_> {
568 fn get_terminal_stdout(
569 &mut self,
570 ) -> wasmtime::Result<Option<Resource<wasi::cli::terminal_output::TerminalOutput>>> {
571 latest::cli::terminal_stdout::Host::get_terminal_stdout(self)
572 }
573}
574
575impl wasi::cli::terminal_stderr::Host for WasiCliCtxView<'_> {
576 fn get_terminal_stderr(
577 &mut self,
578 ) -> wasmtime::Result<Option<Resource<wasi::cli::terminal_output::TerminalOutput>>> {
579 latest::cli::terminal_stderr::Host::get_terminal_stderr(self)
580 }
581}
582
583impl<T> wasi::cli::stdin::HostWithStore<T> for WasiCli {
584 fn read_via_stream(
585 mut store: Access<T, Self>,
586 ) -> wasmtime::Result<(
587 StreamReader<u8>,
588 FutureReader<Result<(), wasi::cli::types::ErrorCode>>,
589 )> {
590 latest::cli::stdin::HostWithStore::read_via_stream(reborrow(&mut store)).and_then(
591 |(stream, future)| Ok((stream, future.try_map(store, |v| v.map_err(|v| v.into()))?)),
592 )
593 }
594}
595
596impl wasi::cli::stdin::Host for WasiCliCtxView<'_> {}
597
598impl<T> wasi::cli::stdout::HostWithStore<T> for WasiCli {
599 fn write_via_stream(
600 mut store: Access<'_, T, Self>,
601 data: StreamReader<u8>,
602 ) -> wasmtime::Result<FutureReader<Result<(), wasi::cli::types::ErrorCode>>> {
603 latest::cli::stdout::HostWithStore::write_via_stream(reborrow(&mut store), data)
604 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
605 }
606}
607
608impl wasi::cli::stdout::Host for WasiCliCtxView<'_> {}
609
610impl<T> wasi::cli::stderr::HostWithStore<T> for WasiCli {
611 fn write_via_stream(
612 mut store: Access<'_, T, Self>,
613 data: StreamReader<u8>,
614 ) -> wasmtime::Result<FutureReader<Result<(), wasi::cli::types::ErrorCode>>> {
615 latest::cli::stderr::HostWithStore::write_via_stream(reborrow(&mut store), data)
616 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
617 }
618}
619
620impl wasi::cli::stderr::Host for WasiCliCtxView<'_> {}
621
622impl wasi::cli::environment::Host for WasiCliCtxView<'_> {
623 fn get_environment(&mut self) -> wasmtime::Result<Vec<(String, String)>> {
624 latest::cli::environment::Host::get_environment(self)
625 }
626
627 fn get_arguments(&mut self) -> wasmtime::Result<Vec<String>> {
628 latest::cli::environment::Host::get_arguments(self)
629 }
630
631 fn get_initial_cwd(&mut self) -> wasmtime::Result<Option<String>> {
632 latest::cli::environment::Host::get_initial_cwd(self)
633 }
634}
635
636impl wasi::cli::exit::Host for WasiCliCtxView<'_> {
637 fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> {
638 latest::cli::exit::Host::exit(self, status)
639 }
640
641 fn exit_with_code(&mut self, status_code: u8) -> wasmtime::Result<()> {
642 latest::cli::exit::Host::exit_with_code(self, status_code)
643 }
644}
645
646impl<T> wasi::sockets::types::Host for SpinSocketsView<'_, T> {}
647
648impl<T: 'static> wasi::sockets::types::HostUdpSocketWithStore<T> for SpinSockets<T> {
649 async fn send(
650 store: &Accessor<T, Self>,
651 socket: Resource<wasi::sockets::types::UdpSocket>,
652 data: Vec<u8>,
653 remote_address: Option<wasi::sockets::types::IpSocketAddress>,
654 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
655 convert_result(
656 latest::sockets::types::HostUdpSocketWithStore::send(
657 store,
658 socket,
659 data,
660 remote_address.map(|v| v.into()),
661 )
662 .await,
663 )
664 }
665
666 async fn receive(
667 store: &Accessor<T, Self>,
668 socket: Resource<wasi::sockets::types::UdpSocket>,
669 ) -> wasmtime::Result<
670 Result<(Vec<u8>, wasi::sockets::types::IpSocketAddress), wasi::sockets::types::ErrorCode>,
671 > {
672 convert_result(
673 latest::sockets::types::HostUdpSocketWithStore::receive(store, socket)
674 .await
675 .map(|(a, b)| (a, b.into())),
676 )
677 }
678}
679
680impl<T> wasi::sockets::types::HostUdpSocket for SpinSocketsView<'_, T> {
681 async fn bind(
682 &mut self,
683 socket: Resource<wasi::sockets::types::UdpSocket>,
684 local_address: wasi::sockets::types::IpSocketAddress,
685 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
686 convert_result(
687 latest::sockets::types::HostUdpSocket::bind(self, socket, local_address.into()).await,
688 )
689 }
690
691 async fn connect(
692 &mut self,
693 socket: Resource<wasi::sockets::types::UdpSocket>,
694 remote_address: wasi::sockets::types::IpSocketAddress,
695 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
696 convert_result(
697 latest::sockets::types::HostUdpSocket::connect(self, socket, remote_address.into())
698 .await,
699 )
700 }
701
702 fn create(
703 &mut self,
704 address_family: wasi::sockets::types::IpAddressFamily,
705 ) -> wasmtime::Result<
706 Result<Resource<wasi::sockets::types::UdpSocket>, wasi::sockets::types::ErrorCode>,
707 > {
708 convert_result(latest::sockets::types::HostUdpSocket::create(
709 self,
710 address_family.into(),
711 ))
712 }
713
714 fn disconnect(
715 &mut self,
716 socket: Resource<wasi::sockets::types::UdpSocket>,
717 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
718 convert_result(latest::sockets::types::HostUdpSocket::disconnect(
719 self, socket,
720 ))
721 }
722
723 fn get_local_address(
724 &mut self,
725 socket: Resource<wasi::sockets::types::UdpSocket>,
726 ) -> wasmtime::Result<
727 Result<wasi::sockets::types::IpSocketAddress, wasi::sockets::types::ErrorCode>,
728 > {
729 convert_result(latest::sockets::types::HostUdpSocket::get_local_address(
730 self, socket,
731 ))
732 }
733
734 fn get_remote_address(
735 &mut self,
736 socket: Resource<wasi::sockets::types::UdpSocket>,
737 ) -> wasmtime::Result<
738 Result<wasi::sockets::types::IpSocketAddress, wasi::sockets::types::ErrorCode>,
739 > {
740 convert_result(latest::sockets::types::HostUdpSocket::get_remote_address(
741 self, socket,
742 ))
743 }
744
745 fn get_address_family(
746 &mut self,
747 socket: Resource<wasi::sockets::types::UdpSocket>,
748 ) -> wasmtime::Result<wasi::sockets::types::IpAddressFamily> {
749 latest::sockets::types::HostUdpSocket::get_address_family(self, socket).map(|v| v.into())
750 }
751
752 fn get_unicast_hop_limit(
753 &mut self,
754 socket: Resource<wasi::sockets::types::UdpSocket>,
755 ) -> wasmtime::Result<Result<u8, wasi::sockets::types::ErrorCode>> {
756 convert_result(latest::sockets::types::HostUdpSocket::get_unicast_hop_limit(self, socket))
757 }
758
759 fn set_unicast_hop_limit(
760 &mut self,
761 socket: Resource<wasi::sockets::types::UdpSocket>,
762 value: u8,
763 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
764 convert_result(
765 latest::sockets::types::HostUdpSocket::set_unicast_hop_limit(self, socket, value),
766 )
767 }
768
769 fn get_receive_buffer_size(
770 &mut self,
771 socket: Resource<wasi::sockets::types::UdpSocket>,
772 ) -> wasmtime::Result<Result<u64, wasi::sockets::types::ErrorCode>> {
773 convert_result(latest::sockets::types::HostUdpSocket::get_receive_buffer_size(self, socket))
774 }
775
776 fn set_receive_buffer_size(
777 &mut self,
778 socket: Resource<wasi::sockets::types::UdpSocket>,
779 value: u64,
780 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
781 convert_result(
782 latest::sockets::types::HostUdpSocket::set_receive_buffer_size(self, socket, value),
783 )
784 }
785
786 fn get_send_buffer_size(
787 &mut self,
788 socket: Resource<wasi::sockets::types::UdpSocket>,
789 ) -> wasmtime::Result<Result<u64, wasi::sockets::types::ErrorCode>> {
790 convert_result(latest::sockets::types::HostUdpSocket::get_send_buffer_size(
791 self, socket,
792 ))
793 }
794
795 fn set_send_buffer_size(
796 &mut self,
797 socket: Resource<wasi::sockets::types::UdpSocket>,
798 value: u64,
799 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
800 convert_result(latest::sockets::types::HostUdpSocket::set_send_buffer_size(
801 self, socket, value,
802 ))
803 }
804
805 fn drop(&mut self, sock: Resource<wasi::sockets::types::UdpSocket>) -> wasmtime::Result<()> {
806 latest::sockets::types::HostUdpSocket::drop(self, sock)
807 }
808}
809
810impl<T: Send + 'static> wasi::sockets::types::HostTcpSocketWithStore<T> for SpinSockets<T> {
811 async fn connect(
812 store: &Accessor<T, Self>,
813 socket: Resource<wasi::sockets::types::TcpSocket>,
814 remote_address: wasi::sockets::types::IpSocketAddress,
815 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
816 convert_result(
817 latest::sockets::types::HostTcpSocketWithStore::connect(
818 store,
819 socket,
820 remote_address.into(),
821 )
822 .await,
823 )
824 }
825
826 async fn listen(
827 store: Access<'_, T, Self>,
828 socket: Resource<wasi::sockets::types::TcpSocket>,
829 ) -> wasmtime::Result<
830 Result<
831 StreamReader<Resource<wasi::sockets::types::TcpSocket>>,
832 wasi::sockets::types::ErrorCode,
833 >,
834 > {
835 convert_result(latest::sockets::types::HostTcpSocketWithStore::listen(store, socket).await)
836 }
837
838 fn send(
839 mut store: Access<'_, T, Self>,
840 socket: Resource<wasi::sockets::types::TcpSocket>,
841 data: StreamReader<u8>,
842 ) -> wasmtime::Result<FutureReader<Result<(), wasi::sockets::types::ErrorCode>>> {
843 latest::sockets::types::HostTcpSocketWithStore::send(reborrow(&mut store), socket, data)
844 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
845 }
846
847 fn receive(
848 mut store: Access<'_, T, Self>,
849 socket: Resource<wasi::sockets::types::TcpSocket>,
850 ) -> wasmtime::Result<(
851 StreamReader<u8>,
852 FutureReader<Result<(), wasi::sockets::types::ErrorCode>>,
853 )> {
854 latest::sockets::types::HostTcpSocketWithStore::receive(reborrow(&mut store), socket)
855 .and_then(|(stream, future)| {
856 Ok((stream, future.try_map(store, |v| v.map_err(|v| v.into()))?))
857 })
858 }
859}
860
861impl<T> wasi::sockets::types::HostTcpSocket for SpinSocketsView<'_, T> {
862 async fn bind(
863 &mut self,
864 socket: Resource<wasi::sockets::types::TcpSocket>,
865 local_address: wasi::sockets::types::IpSocketAddress,
866 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
867 convert_result(
868 latest::sockets::types::HostTcpSocket::bind(self, socket, local_address.into()).await,
869 )
870 }
871
872 fn create(
873 &mut self,
874 address_family: wasi::sockets::types::IpAddressFamily,
875 ) -> wasmtime::Result<
876 Result<Resource<wasi::sockets::types::TcpSocket>, wasi::sockets::types::ErrorCode>,
877 > {
878 convert_result(latest::sockets::types::HostTcpSocket::create(
879 self,
880 address_family.into(),
881 ))
882 }
883
884 fn get_local_address(
885 &mut self,
886 socket: Resource<wasi::sockets::types::TcpSocket>,
887 ) -> wasmtime::Result<
888 Result<wasi::sockets::types::IpSocketAddress, wasi::sockets::types::ErrorCode>,
889 > {
890 convert_result(latest::sockets::types::HostTcpSocket::get_local_address(
891 self, socket,
892 ))
893 }
894
895 fn get_remote_address(
896 &mut self,
897 socket: Resource<wasi::sockets::types::TcpSocket>,
898 ) -> wasmtime::Result<
899 Result<wasi::sockets::types::IpSocketAddress, wasi::sockets::types::ErrorCode>,
900 > {
901 convert_result(latest::sockets::types::HostTcpSocket::get_remote_address(
902 self, socket,
903 ))
904 }
905
906 fn get_is_listening(
907 &mut self,
908 socket: Resource<wasi::sockets::types::TcpSocket>,
909 ) -> wasmtime::Result<bool> {
910 latest::sockets::types::HostTcpSocket::get_is_listening(self, socket)
911 }
912
913 fn get_address_family(
914 &mut self,
915 socket: Resource<wasi::sockets::types::TcpSocket>,
916 ) -> wasmtime::Result<wasi::sockets::types::IpAddressFamily> {
917 latest::sockets::types::HostTcpSocket::get_address_family(self, socket).map(|v| v.into())
918 }
919
920 fn set_listen_backlog_size(
921 &mut self,
922 socket: Resource<wasi::sockets::types::TcpSocket>,
923 value: u64,
924 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
925 convert_result(
926 latest::sockets::types::HostTcpSocket::set_listen_backlog_size(self, socket, value),
927 )
928 }
929
930 fn get_keep_alive_enabled(
931 &mut self,
932 socket: Resource<wasi::sockets::types::TcpSocket>,
933 ) -> wasmtime::Result<Result<bool, wasi::sockets::types::ErrorCode>> {
934 convert_result(latest::sockets::types::HostTcpSocket::get_keep_alive_enabled(self, socket))
935 }
936
937 fn set_keep_alive_enabled(
938 &mut self,
939 socket: Resource<wasi::sockets::types::TcpSocket>,
940 value: bool,
941 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
942 convert_result(
943 latest::sockets::types::HostTcpSocket::set_keep_alive_enabled(self, socket, value),
944 )
945 }
946
947 fn get_keep_alive_idle_time(
948 &mut self,
949 socket: Resource<wasi::sockets::types::TcpSocket>,
950 ) -> wasmtime::Result<Result<wasi::sockets::types::Duration, wasi::sockets::types::ErrorCode>>
951 {
952 convert_result(
953 latest::sockets::types::HostTcpSocket::get_keep_alive_idle_time(self, socket),
954 )
955 }
956
957 fn set_keep_alive_idle_time(
958 &mut self,
959 socket: Resource<wasi::sockets::types::TcpSocket>,
960 value: wasi::sockets::types::Duration,
961 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
962 convert_result(
963 latest::sockets::types::HostTcpSocket::set_keep_alive_idle_time(self, socket, value),
964 )
965 }
966
967 fn get_keep_alive_interval(
968 &mut self,
969 socket: Resource<wasi::sockets::types::TcpSocket>,
970 ) -> wasmtime::Result<Result<wasi::sockets::types::Duration, wasi::sockets::types::ErrorCode>>
971 {
972 convert_result(latest::sockets::types::HostTcpSocket::get_keep_alive_interval(self, socket))
973 }
974
975 fn set_keep_alive_interval(
976 &mut self,
977 socket: Resource<wasi::sockets::types::TcpSocket>,
978 value: wasi::sockets::types::Duration,
979 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
980 convert_result(
981 latest::sockets::types::HostTcpSocket::set_keep_alive_interval(self, socket, value),
982 )
983 }
984
985 fn get_keep_alive_count(
986 &mut self,
987 socket: Resource<wasi::sockets::types::TcpSocket>,
988 ) -> wasmtime::Result<Result<u32, wasi::sockets::types::ErrorCode>> {
989 convert_result(latest::sockets::types::HostTcpSocket::get_keep_alive_count(
990 self, socket,
991 ))
992 }
993
994 fn set_keep_alive_count(
995 &mut self,
996 socket: Resource<wasi::sockets::types::TcpSocket>,
997 value: u32,
998 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
999 convert_result(latest::sockets::types::HostTcpSocket::set_keep_alive_count(
1000 self, socket, value,
1001 ))
1002 }
1003
1004 fn get_hop_limit(
1005 &mut self,
1006 socket: Resource<wasi::sockets::types::TcpSocket>,
1007 ) -> wasmtime::Result<Result<u8, wasi::sockets::types::ErrorCode>> {
1008 convert_result(latest::sockets::types::HostTcpSocket::get_hop_limit(
1009 self, socket,
1010 ))
1011 }
1012
1013 fn set_hop_limit(
1014 &mut self,
1015 socket: Resource<wasi::sockets::types::TcpSocket>,
1016 value: u8,
1017 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
1018 convert_result(latest::sockets::types::HostTcpSocket::set_hop_limit(
1019 self, socket, value,
1020 ))
1021 }
1022
1023 fn get_receive_buffer_size(
1024 &mut self,
1025 socket: Resource<wasi::sockets::types::TcpSocket>,
1026 ) -> wasmtime::Result<Result<u64, wasi::sockets::types::ErrorCode>> {
1027 convert_result(latest::sockets::types::HostTcpSocket::get_receive_buffer_size(self, socket))
1028 }
1029
1030 fn set_receive_buffer_size(
1031 &mut self,
1032 socket: Resource<wasi::sockets::types::TcpSocket>,
1033 value: u64,
1034 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
1035 convert_result(
1036 latest::sockets::types::HostTcpSocket::set_receive_buffer_size(self, socket, value),
1037 )
1038 }
1039
1040 fn get_send_buffer_size(
1041 &mut self,
1042 socket: Resource<wasi::sockets::types::TcpSocket>,
1043 ) -> wasmtime::Result<Result<u64, wasi::sockets::types::ErrorCode>> {
1044 convert_result(latest::sockets::types::HostTcpSocket::get_send_buffer_size(
1045 self, socket,
1046 ))
1047 }
1048
1049 fn set_send_buffer_size(
1050 &mut self,
1051 socket: Resource<wasi::sockets::types::TcpSocket>,
1052 value: u64,
1053 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
1054 convert_result(latest::sockets::types::HostTcpSocket::set_send_buffer_size(
1055 self, socket, value,
1056 ))
1057 }
1058
1059 fn drop(&mut self, sock: Resource<wasi::sockets::types::TcpSocket>) -> wasmtime::Result<()> {
1060 latest::sockets::types::HostTcpSocket::drop(self, sock)
1061 }
1062}
1063
1064impl<T> wasi::sockets::ip_name_lookup::HostWithStore<T> for WasiSockets {
1065 async fn resolve_addresses(
1066 store: &Accessor<T, Self>,
1067 name: String,
1068 ) -> wasmtime::Result<
1069 Result<Vec<wasi::sockets::types::IpAddress>, wasi::sockets::ip_name_lookup::ErrorCode>,
1070 > {
1071 latest::sockets::ip_name_lookup::HostWithStore::resolve_addresses(store, name)
1072 .await
1073 .map(|v| {
1074 v.map(|v| v.into_iter().map(|v| v.into()).collect())
1075 .map_err(|e| e.into())
1076 })
1077 }
1078}
1079
1080impl wasi::sockets::ip_name_lookup::Host for WasiSocketsCtxView<'_> {}
1081
1082convert! {
1083 struct latest::clocks::system_clock::Instant [<=>] wasi::clocks::system_clock::Instant {
1084 seconds,
1085 nanoseconds,
1086 }
1087
1088 enum latest::cli::types::ErrorCode => wasi::cli::types::ErrorCode {
1089 Io,
1090 IllegalByteSequence,
1091 Pipe,
1092 }
1093
1094 enum latest::filesystem::types::ErrorCode => wasi::filesystem::types::ErrorCode {
1095 Access,
1096 Already,
1097 BadDescriptor,
1098 Busy,
1099 Deadlock,
1100 Quota,
1101 Exist,
1102 FileTooLarge,
1103 IllegalByteSequence,
1104 InProgress,
1105 Interrupted,
1106 Invalid,
1107 Io,
1108 IsDirectory,
1109 Loop,
1110 TooManyLinks,
1111 MessageSize,
1112 NameTooLong,
1113 NoDevice,
1114 NoEntry,
1115 NoLock,
1116 InsufficientMemory,
1117 InsufficientSpace,
1118 NotDirectory,
1119 NotEmpty,
1120 NotRecoverable,
1121 Unsupported,
1122 NoTty,
1123 NoSuchDevice,
1124 Overflow,
1125 NotPermitted,
1126 Pipe,
1127 ReadOnly,
1128 InvalidSeek,
1129 TextFileBusy,
1130 CrossDevice,
1131 Other(v),
1132 }
1133
1134 enum wasi::filesystem::types::Advice => latest::filesystem::types::Advice {
1135 Normal,
1136 Sequential,
1137 Random,
1138 WillNeed,
1139 DontNeed,
1140 NoReuse,
1141 }
1142
1143 flags wasi::filesystem::types::DescriptorFlags [<=>] latest::filesystem::types::DescriptorFlags {
1144 READ,
1145 WRITE,
1146 FILE_INTEGRITY_SYNC,
1147 DATA_INTEGRITY_SYNC,
1148 REQUESTED_WRITE_SYNC,
1149 MUTATE_DIRECTORY,
1150 }
1151
1152 enum wasi::filesystem::types::DescriptorType [<=>] latest::filesystem::types::DescriptorType {
1153 BlockDevice,
1154 CharacterDevice,
1155 Directory,
1156 Fifo,
1157 SymbolicLink,
1158 RegularFile,
1159 Socket,
1160 Other(v),
1161 }
1162
1163 enum wasi::filesystem::types::NewTimestamp => latest::filesystem::types::NewTimestamp {
1164 NoChange,
1165 Now,
1166 Timestamp(e),
1167 }
1168
1169 flags wasi::filesystem::types::PathFlags => latest::filesystem::types::PathFlags {
1170 SYMLINK_FOLLOW,
1171 }
1172
1173 flags wasi::filesystem::types::OpenFlags => latest::filesystem::types::OpenFlags {
1174 CREATE,
1175 DIRECTORY,
1176 EXCLUSIVE,
1177 TRUNCATE,
1178 }
1179
1180 struct latest::filesystem::types::MetadataHashValue => wasi::filesystem::types::MetadataHashValue {
1181 lower,
1182 upper,
1183 }
1184
1185 struct latest::filesystem::types::DirectoryEntry => wasi::filesystem::types::DirectoryEntry {
1186 type_,
1187 name,
1188 }
1189
1190 enum latest::sockets::types::ErrorCode => wasi::sockets::types::ErrorCode {
1191 AccessDenied,
1192 NotSupported,
1193 InvalidArgument,
1194 OutOfMemory,
1195 Timeout,
1196 InvalidState,
1197 AddressNotBindable,
1198 AddressInUse,
1199 RemoteUnreachable,
1200 ConnectionRefused,
1201 ConnectionBroken,
1202 ConnectionReset,
1203 ConnectionAborted,
1204 DatagramTooLarge,
1205 Other(v),
1206 }
1207
1208 enum latest::sockets::types::IpAddress [<=>] wasi::sockets::types::IpAddress {
1209 Ipv4(e),
1210 Ipv6(e),
1211 }
1212
1213 enum latest::sockets::types::IpSocketAddress [<=>] wasi::sockets::types::IpSocketAddress {
1214 Ipv4(e),
1215 Ipv6(e),
1216 }
1217
1218 struct latest::sockets::types::Ipv4SocketAddress [<=>] wasi::sockets::types::Ipv4SocketAddress {
1219 port,
1220 address,
1221 }
1222
1223 struct latest::sockets::types::Ipv6SocketAddress [<=>] wasi::sockets::types::Ipv6SocketAddress {
1224 port,
1225 flow_info,
1226 scope_id,
1227 address,
1228 }
1229
1230 enum latest::sockets::types::IpAddressFamily [<=>] wasi::sockets::types::IpAddressFamily {
1231 Ipv4,
1232 Ipv6,
1233 }
1234
1235 enum latest::sockets::ip_name_lookup::ErrorCode => wasi::sockets::ip_name_lookup::ErrorCode {
1236 AccessDenied,
1237 InvalidArgument,
1238 NameUnresolvable,
1239 TemporaryResolverFailure,
1240 PermanentResolverFailure,
1241 Other(v),
1242 }
1243}
1244
1245impl From<latest::filesystem::types::DescriptorStat> for wasi::filesystem::types::DescriptorStat {
1246 fn from(
1247 e: latest::filesystem::types::DescriptorStat,
1248 ) -> wasi::filesystem::types::DescriptorStat {
1249 wasi::filesystem::types::DescriptorStat {
1250 type_: e.type_.into(),
1251 link_count: e.link_count,
1252 size: e.size,
1253 data_access_timestamp: e.data_access_timestamp.map(|e| e.into()),
1254 data_modification_timestamp: e.data_modification_timestamp.map(|e| e.into()),
1255 status_change_timestamp: e.status_change_timestamp.map(|e| e.into()),
1256 }
1257 }
1258}
1259
1260pub trait FutureReaderExt<T> {
1261 fn try_map<U: Lower + Lift + 'static>(
1262 self,
1263 store: impl AsContextMut,
1264 fun: impl FnOnce(T) -> U + Send + 'static,
1265 ) -> wasmtime::Result<FutureReader<U>>;
1266}
1267
1268impl<T: Lift + Send + 'static> FutureReaderExt<T> for FutureReader<T> {
1269 fn try_map<U: Lower + Lift + 'static>(
1270 self,
1271 mut store: impl AsContextMut,
1272 fun: impl FnOnce(T) -> U + Send + 'static,
1273 ) -> wasmtime::Result<FutureReader<U>> {
1274 pin_project! {
1275 struct Producer<T, F> {
1276 #[pin]
1277 rx: oneshot::Receiver<T>,
1278 fun: Option<F>,
1279 }
1280 }
1281
1282 impl<D, T: Send + 'static, U, F: FnOnce(T) -> U + Send + 'static> FutureProducer<D>
1283 for Producer<T, F>
1284 {
1285 type Item = U;
1286
1287 fn poll_produce(
1288 self: Pin<&mut Self>,
1289 cx: &mut Context<'_>,
1290 _store: StoreContextMut<D>,
1291 finish: bool,
1292 ) -> Poll<wasmtime::Result<Option<Self::Item>>> {
1293 let me = self.project();
1294
1295 match me.rx.poll(cx) {
1296 Poll::Pending if finish => Poll::Ready(Ok(None)),
1297 Poll::Pending => Poll::Pending,
1298 Poll::Ready(result) => {
1299 Poll::Ready(result.map_err(wasmtime::Error::from).and_then(|value| {
1300 Ok(Some((me
1301 .fun
1302 .take()
1303 .context("oneshot channel yielded more than one value")?)(
1304 value,
1305 )))
1306 }))
1307 }
1308 }
1309 }
1310 }
1311
1312 struct Consumer<T> {
1313 tx: Option<oneshot::Sender<T>>,
1314 }
1315
1316 impl<D, T: Lift + Send + 'static> FutureConsumer<D> for Consumer<T> {
1317 type Item = T;
1318
1319 fn poll_consume(
1320 mut self: Pin<&mut Self>,
1321 _cx: &mut Context<'_>,
1322 store: StoreContextMut<D>,
1323 mut source: Source<'_, Self::Item>,
1324 _finish: bool,
1325 ) -> Poll<wasmtime::Result<()>> {
1326 let mut result = None;
1327 source
1328 .read(store, &mut result)
1329 .context("failed to read result")?;
1330 let result = result.context("result value missing")?;
1331 let tx = self.tx.take().context("polled after returning `Ready`")?;
1332 _ = tx.send(result);
1333 Poll::Ready(Ok(()))
1334 }
1335 }
1336
1337 let (tx, rx) = oneshot::channel();
1338 let mapped = FutureReader::new(store.as_context_mut(), Producer { rx, fun: Some(fun) })?;
1339 self.pipe(store, Consumer { tx: Some(tx) })?;
1340 Ok(mapped)
1341 }
1342}
1343
1344pub trait StreamReaderExt<T> {
1345 fn try_map<U: Lower + Lift + Send + Sync + 'static>(
1346 self,
1347 store: impl AsContextMut,
1348 fun: impl Fn(T) -> U + Send + 'static,
1349 ) -> wasmtime::Result<StreamReader<U>>;
1350}
1351
1352impl<T: Lift + Send + 'static> StreamReaderExt<T> for StreamReader<T> {
1353 fn try_map<U: Lower + Lift + Send + Sync + 'static>(
1354 self,
1355 mut store: impl AsContextMut,
1356 fun: impl Fn(T) -> U + Send + 'static,
1357 ) -> wasmtime::Result<StreamReader<U>> {
1358 pin_project! {
1359 struct Producer<T, F> {
1360 #[pin]
1361 rx: mpsc::Receiver<T>,
1362 fun: F,
1363 }
1364 }
1365
1366 impl<D, T: Send + 'static, U: Send + Sync + 'static, F: Fn(T) -> U + Send + 'static>
1367 StreamProducer<D> for Producer<T, F>
1368 {
1369 type Item = U;
1370 type Buffer = Option<U>;
1371
1372 fn poll_produce<'a>(
1373 self: Pin<&mut Self>,
1374 cx: &mut Context<'_>,
1375 _store: StoreContextMut<'a, D>,
1376 mut destination: Destination<'a, Self::Item, Self::Buffer>,
1377 finish: bool,
1378 ) -> Poll<wasmtime::Result<StreamResult>> {
1379 let me = self.project();
1380
1381 match me.rx.poll_next(cx) {
1382 Poll::Pending if finish => Poll::Ready(Ok(StreamResult::Cancelled)),
1383 Poll::Pending => Poll::Pending,
1384 Poll::Ready(Some(result)) => {
1385 destination.set_buffer(Some((me.fun)(result)));
1386 Poll::Ready(Ok(StreamResult::Completed))
1387 }
1388 Poll::Ready(None) => Poll::Ready(Ok(StreamResult::Dropped)),
1389 }
1390 }
1391 }
1392
1393 struct Consumer<T> {
1394 tx: mpsc::Sender<T>,
1395 }
1396
1397 impl<D, T: Lift + Send + 'static> StreamConsumer<D> for Consumer<T> {
1398 type Item = T;
1399
1400 fn poll_consume(
1401 mut self: Pin<&mut Self>,
1402 cx: &mut Context<'_>,
1403 store: StoreContextMut<D>,
1404 mut source: Source<'_, Self::Item>,
1405 finish: bool,
1406 ) -> Poll<wasmtime::Result<StreamResult>> {
1407 match self.tx.poll_ready(cx) {
1408 Poll::Pending if finish => Poll::Ready(Ok(StreamResult::Cancelled)),
1409 Poll::Pending => Poll::Pending,
1410 Poll::Ready(Ok(())) => {
1411 let mut result = None;
1412 source
1413 .read(store, &mut result)
1414 .context("failed to read result")?;
1415 let result = result.context("result value missing")?;
1416 self.tx.start_send(result)?;
1417 Poll::Ready(Ok(StreamResult::Completed))
1418 }
1419 Poll::Ready(Err(error)) if error.is_disconnected() => {
1420 Poll::Ready(Ok(StreamResult::Dropped))
1421 }
1422 Poll::Ready(Err(error)) => Poll::Ready(Err(error.into())),
1423 }
1424 }
1425 }
1426
1427 let (tx, rx) = mpsc::channel(1);
1428 let mapped = StreamReader::new(store.as_context_mut(), Producer { rx, fun })?;
1429 self.pipe(store, Consumer { tx })?;
1430 Ok(mapped)
1431 }
1432}
1433
1434pub fn reborrow<'a, T: 'static, D: HasData + ?Sized>(
1435 access: &'a mut Access<'_, T, D>,
1436) -> Access<'a, T, D> {
1437 let getter = access.getter();
1438 Access::new(access.as_context_mut(), getter)
1439}