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.[static]udp-socket.create": async | trappable,
43 "wasi:sockets/types.[method]udp-socket.bind": async | trappable,
44 "wasi:sockets/types.[method]udp-socket.connect": async | trappable,
45 default: trappable,
46 },
47 exports: { default: async | store },
48 with: {
49 "wasi:cli/terminal-input.terminal-input": latest::cli::terminal_input::TerminalInput,
50 "wasi:cli/terminal-output.terminal-output": latest::cli::terminal_output::TerminalOutput,
51 "wasi:filesystem/types.descriptor": latest::filesystem::types::Descriptor,
52 "wasi:sockets/types.tcp-socket": latest::sockets::types::TcpSocket,
53 "wasi:sockets/types.udp-socket": latest::sockets::types::UdpSocket,
54 },
55 });
56}
57
58mod wasi {
59 pub use super::bindings::wasi::{
60 cli0_3_0_rc_2026_03_15 as cli, clocks0_3_0_rc_2026_03_15 as clocks,
61 filesystem0_3_0_rc_2026_03_15 as filesystem, random0_3_0_rc_2026_03_15 as random,
62 sockets0_3_0_rc_2026_03_15 as sockets,
63 };
64}
65
66pub fn add_to_linker<T>(
67 linker: &mut Linker<T>,
68 random_closure: fn(&mut T) -> &mut WasiRandomCtx,
69 clocks_closure: fn(&mut T) -> WasiClocksCtxView<'_>,
70 cli_closure: fn(&mut T) -> WasiCliCtxView<'_>,
71 filesystem_closure: fn(&mut T) -> WasiFilesystemCtxView<'_>,
72 sockets_closure: fn(&mut T) -> SpinSocketsView<'_, T>,
73 wasi_sockets_closure: fn(&mut T) -> WasiSocketsCtxView<'_>,
74) -> anyhow::Result<()>
75where
76 T: Send + 'static,
77{
78 wasi::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
79 wasi::clocks::system_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
80 wasi::filesystem::types::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
81 wasi::filesystem::preopens::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
82 wasi::random::random::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
83 wasi::random::insecure::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
84 wasi::random::insecure_seed::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
85 wasi::cli::exit::add_to_linker::<_, WasiCli>(
86 linker,
87 &wasi::cli::exit::LinkOptions::default(),
88 cli_closure,
89 )?;
90 wasi::cli::environment::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
91 wasi::cli::stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
92 wasi::cli::stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
93 wasi::cli::stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
94 wasi::cli::terminal_input::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
95 wasi::cli::terminal_output::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
96 wasi::cli::terminal_stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
97 wasi::cli::terminal_stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
98 wasi::cli::terminal_stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
99 wasi::sockets::types::add_to_linker::<_, SpinSockets<T>>(linker, sockets_closure)?;
100 wasi::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, wasi_sockets_closure)?;
101 Ok(())
102}
103
104impl wasi::clocks::types::Host for WasiClocksCtxView<'_> {}
105
106impl wasi::clocks::system_clock::Host for WasiClocksCtxView<'_> {
107 fn now(&mut self) -> wasmtime::Result<wasi::clocks::system_clock::Instant> {
108 latest::clocks::system_clock::Host::now(self).map(|v| v.into())
109 }
110
111 fn get_resolution(&mut self) -> wasmtime::Result<wasi::clocks::types::Duration> {
112 latest::clocks::system_clock::Host::get_resolution(self)
113 }
114}
115
116impl<T> wasi::clocks::monotonic_clock::HostWithStore<T> for WasiClocks {
117 async fn wait_until(
118 store: &Accessor<T, Self>,
119 when: wasi::clocks::monotonic_clock::Mark,
120 ) -> wasmtime::Result<()> {
121 latest::clocks::monotonic_clock::HostWithStore::wait_until(store, when).await
122 }
123
124 async fn wait_for(
125 store: &Accessor<T, Self>,
126 duration: wasi::clocks::types::Duration,
127 ) -> wasmtime::Result<()> {
128 latest::clocks::monotonic_clock::HostWithStore::wait_for(store, duration).await
129 }
130}
131
132impl wasi::clocks::monotonic_clock::Host for WasiClocksCtxView<'_> {
133 fn now(&mut self) -> wasmtime::Result<wasi::clocks::monotonic_clock::Mark> {
134 latest::clocks::monotonic_clock::Host::now(self)
135 }
136
137 fn get_resolution(&mut self) -> wasmtime::Result<wasi::clocks::types::Duration> {
138 latest::clocks::monotonic_clock::Host::get_resolution(self)
139 }
140}
141
142impl wasi::filesystem::types::Host for WasiFilesystemCtxView<'_> {}
143
144impl<T> wasi::filesystem::types::HostDescriptorWithStore<T> for WasiFilesystem {
145 fn read_via_stream(
146 mut store: Access<'_, T, Self>,
147 fd: Resource<wasi::filesystem::types::Descriptor>,
148 offset: wasi::filesystem::types::Filesize,
149 ) -> wasmtime::Result<(
150 StreamReader<u8>,
151 FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>,
152 )> {
153 latest::filesystem::types::HostDescriptorWithStore::read_via_stream(
154 reborrow(&mut store),
155 fd,
156 offset,
157 )
158 .and_then(|(stream, future)| {
159 Ok((stream, future.try_map(store, |v| v.map_err(|v| v.into()))?))
160 })
161 }
162
163 fn write_via_stream(
164 mut store: Access<'_, T, Self>,
165 fd: Resource<wasi::filesystem::types::Descriptor>,
166 data: StreamReader<u8>,
167 offset: wasi::filesystem::types::Filesize,
168 ) -> wasmtime::Result<FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>> {
169 latest::filesystem::types::HostDescriptorWithStore::write_via_stream(
170 reborrow(&mut store),
171 fd,
172 data,
173 offset,
174 )
175 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
176 }
177
178 fn append_via_stream(
179 mut store: Access<'_, T, Self>,
180 fd: Resource<wasi::filesystem::types::Descriptor>,
181 data: StreamReader<u8>,
182 ) -> wasmtime::Result<FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>> {
183 latest::filesystem::types::HostDescriptorWithStore::append_via_stream(
184 reborrow(&mut store),
185 fd,
186 data,
187 )
188 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
189 }
190
191 async fn advise(
192 store: &Accessor<T, Self>,
193 fd: Resource<wasi::filesystem::types::Descriptor>,
194 offset: wasi::filesystem::types::Filesize,
195 length: wasi::filesystem::types::Filesize,
196 advice: wasi::filesystem::types::Advice,
197 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
198 convert_result(
199 latest::filesystem::types::HostDescriptorWithStore::advise(
200 store,
201 fd,
202 offset,
203 length,
204 advice.into(),
205 )
206 .await,
207 )
208 }
209
210 async fn sync_data(
211 store: &Accessor<T, Self>,
212 fd: Resource<wasi::filesystem::types::Descriptor>,
213 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
214 convert_result(
215 latest::filesystem::types::HostDescriptorWithStore::sync_data(store, fd).await,
216 )
217 }
218
219 async fn get_flags(
220 store: &Accessor<T, Self>,
221 fd: Resource<wasi::filesystem::types::Descriptor>,
222 ) -> wasmtime::Result<
223 Result<wasi::filesystem::types::DescriptorFlags, wasi::filesystem::types::ErrorCode>,
224 > {
225 convert_result(
226 latest::filesystem::types::HostDescriptorWithStore::get_flags(store, fd).await,
227 )
228 }
229
230 async fn get_type(
231 store: &Accessor<T, Self>,
232 fd: Resource<wasi::filesystem::types::Descriptor>,
233 ) -> wasmtime::Result<
234 Result<wasi::filesystem::types::DescriptorType, wasi::filesystem::types::ErrorCode>,
235 > {
236 convert_result(
237 latest::filesystem::types::HostDescriptorWithStore::get_type(store, fd).await,
238 )
239 }
240
241 async fn set_size(
242 store: &Accessor<T, Self>,
243 fd: Resource<wasi::filesystem::types::Descriptor>,
244 size: wasi::filesystem::types::Filesize,
245 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
246 convert_result(
247 latest::filesystem::types::HostDescriptorWithStore::set_size(store, fd, size).await,
248 )
249 }
250
251 async fn set_times(
252 store: &Accessor<T, Self>,
253 fd: Resource<wasi::filesystem::types::Descriptor>,
254 data_access_timestamp: wasi::filesystem::types::NewTimestamp,
255 data_modification_timestamp: wasi::filesystem::types::NewTimestamp,
256 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
257 convert_result(
258 latest::filesystem::types::HostDescriptorWithStore::set_times(
259 store,
260 fd,
261 data_access_timestamp.into(),
262 data_modification_timestamp.into(),
263 )
264 .await,
265 )
266 }
267
268 fn read_directory(
269 mut store: Access<'_, T, Self>,
270 fd: Resource<wasi::filesystem::types::Descriptor>,
271 ) -> wasmtime::Result<(
272 StreamReader<wasi::filesystem::types::DirectoryEntry>,
273 FutureReader<Result<(), wasi::filesystem::types::ErrorCode>>,
274 )> {
275 latest::filesystem::types::HostDescriptorWithStore::read_directory(reborrow(&mut store), fd)
276 .and_then(|(stream, future)| {
277 Ok((
278 stream.try_map(reborrow(&mut store), |v| v.into())?,
279 future.try_map(store, |v| v.map_err(|v| v.into()))?,
280 ))
281 })
282 }
283
284 async fn sync(
285 store: &Accessor<T, Self>,
286 fd: Resource<wasi::filesystem::types::Descriptor>,
287 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
288 convert_result(latest::filesystem::types::HostDescriptorWithStore::sync(store, fd).await)
289 }
290
291 async fn create_directory_at(
292 store: &Accessor<T, Self>,
293 fd: Resource<wasi::filesystem::types::Descriptor>,
294 path: String,
295 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
296 convert_result(
297 latest::filesystem::types::HostDescriptorWithStore::create_directory_at(
298 store, fd, path,
299 )
300 .await,
301 )
302 }
303
304 async fn stat(
305 store: &Accessor<T, Self>,
306 fd: Resource<wasi::filesystem::types::Descriptor>,
307 ) -> wasmtime::Result<
308 Result<wasi::filesystem::types::DescriptorStat, wasi::filesystem::types::ErrorCode>,
309 > {
310 convert_result(latest::filesystem::types::HostDescriptorWithStore::stat(store, fd).await)
311 }
312
313 async fn stat_at(
314 store: &Accessor<T, Self>,
315 fd: Resource<wasi::filesystem::types::Descriptor>,
316 path_flags: wasi::filesystem::types::PathFlags,
317 path: String,
318 ) -> wasmtime::Result<
319 Result<wasi::filesystem::types::DescriptorStat, wasi::filesystem::types::ErrorCode>,
320 > {
321 convert_result(
322 latest::filesystem::types::HostDescriptorWithStore::stat_at(
323 store,
324 fd,
325 path_flags.into(),
326 path,
327 )
328 .await,
329 )
330 }
331
332 async fn set_times_at(
333 store: &Accessor<T, Self>,
334 fd: Resource<wasi::filesystem::types::Descriptor>,
335 path_flags: wasi::filesystem::types::PathFlags,
336 path: String,
337 data_access_timestamp: wasi::filesystem::types::NewTimestamp,
338 data_modification_timestamp: wasi::filesystem::types::NewTimestamp,
339 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
340 convert_result(
341 latest::filesystem::types::HostDescriptorWithStore::set_times_at(
342 store,
343 fd,
344 path_flags.into(),
345 path,
346 data_access_timestamp.into(),
347 data_modification_timestamp.into(),
348 )
349 .await,
350 )
351 }
352
353 async fn link_at(
354 store: &Accessor<T, Self>,
355 fd: Resource<wasi::filesystem::types::Descriptor>,
356 old_path_flags: wasi::filesystem::types::PathFlags,
357 old_path: String,
358 new_fd: Resource<wasi::filesystem::types::Descriptor>,
359 new_path: String,
360 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
361 convert_result(
362 latest::filesystem::types::HostDescriptorWithStore::link_at(
363 store,
364 fd,
365 old_path_flags.into(),
366 old_path,
367 new_fd,
368 new_path,
369 )
370 .await,
371 )
372 }
373
374 async fn open_at(
375 store: &Accessor<T, Self>,
376 fd: Resource<wasi::filesystem::types::Descriptor>,
377 path_flags: wasi::filesystem::types::PathFlags,
378 path: String,
379 open_flags: wasi::filesystem::types::OpenFlags,
380 flags: wasi::filesystem::types::DescriptorFlags,
381 ) -> wasmtime::Result<
382 Result<Resource<wasi::filesystem::types::Descriptor>, wasi::filesystem::types::ErrorCode>,
383 > {
384 convert_result(
385 latest::filesystem::types::HostDescriptorWithStore::open_at(
386 store,
387 fd,
388 path_flags.into(),
389 path,
390 open_flags.into(),
391 flags.into(),
392 )
393 .await,
394 )
395 }
396
397 async fn readlink_at(
398 store: &Accessor<T, Self>,
399 fd: Resource<wasi::filesystem::types::Descriptor>,
400 path: String,
401 ) -> wasmtime::Result<Result<String, wasi::filesystem::types::ErrorCode>> {
402 convert_result(
403 latest::filesystem::types::HostDescriptorWithStore::readlink_at(store, fd, path).await,
404 )
405 }
406
407 async fn remove_directory_at(
408 store: &Accessor<T, Self>,
409 fd: Resource<wasi::filesystem::types::Descriptor>,
410 path: String,
411 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
412 convert_result(
413 latest::filesystem::types::HostDescriptorWithStore::remove_directory_at(
414 store, fd, path,
415 )
416 .await,
417 )
418 }
419
420 async fn rename_at(
421 store: &Accessor<T, Self>,
422 fd: Resource<wasi::filesystem::types::Descriptor>,
423 old_path: String,
424 new_fd: Resource<wasi::filesystem::types::Descriptor>,
425 new_path: String,
426 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
427 convert_result(
428 latest::filesystem::types::HostDescriptorWithStore::rename_at(
429 store, fd, old_path, new_fd, new_path,
430 )
431 .await,
432 )
433 }
434
435 async fn symlink_at(
436 store: &Accessor<T, Self>,
437 fd: Resource<wasi::filesystem::types::Descriptor>,
438 old_path: String,
439 new_path: String,
440 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
441 convert_result(
442 latest::filesystem::types::HostDescriptorWithStore::symlink_at(
443 store, fd, old_path, new_path,
444 )
445 .await,
446 )
447 }
448
449 async fn unlink_file_at(
450 store: &Accessor<T, Self>,
451 fd: Resource<wasi::filesystem::types::Descriptor>,
452 path: String,
453 ) -> wasmtime::Result<Result<(), wasi::filesystem::types::ErrorCode>> {
454 convert_result(
455 latest::filesystem::types::HostDescriptorWithStore::unlink_file_at(store, fd, path)
456 .await,
457 )
458 }
459
460 async fn is_same_object(
461 store: &Accessor<T, Self>,
462 fd: Resource<wasi::filesystem::types::Descriptor>,
463 other: Resource<wasi::filesystem::types::Descriptor>,
464 ) -> wasmtime::Result<bool> {
465 latest::filesystem::types::HostDescriptorWithStore::is_same_object(store, fd, other).await
466 }
467
468 async fn metadata_hash(
469 store: &Accessor<T, Self>,
470 fd: Resource<wasi::filesystem::types::Descriptor>,
471 ) -> wasmtime::Result<
472 Result<wasi::filesystem::types::MetadataHashValue, wasi::filesystem::types::ErrorCode>,
473 > {
474 convert_result(
475 latest::filesystem::types::HostDescriptorWithStore::metadata_hash(store, fd).await,
476 )
477 }
478
479 async fn metadata_hash_at(
480 store: &Accessor<T, Self>,
481 fd: Resource<wasi::filesystem::types::Descriptor>,
482 path_flags: wasi::filesystem::types::PathFlags,
483 path: String,
484 ) -> wasmtime::Result<
485 Result<wasi::filesystem::types::MetadataHashValue, wasi::filesystem::types::ErrorCode>,
486 > {
487 convert_result(
488 latest::filesystem::types::HostDescriptorWithStore::metadata_hash_at(
489 store,
490 fd,
491 path_flags.into(),
492 path,
493 )
494 .await,
495 )
496 }
497}
498
499impl wasi::filesystem::types::HostDescriptor for WasiFilesystemCtxView<'_> {
500 fn drop(&mut self, fd: Resource<wasi::filesystem::types::Descriptor>) -> wasmtime::Result<()> {
501 latest::filesystem::types::HostDescriptor::drop(self, fd)
502 }
503}
504
505impl wasi::filesystem::preopens::Host for WasiFilesystemCtxView<'_> {
506 fn get_directories(
507 &mut self,
508 ) -> wasmtime::Result<Vec<(Resource<wasi::filesystem::types::Descriptor>, String)>> {
509 latest::filesystem::preopens::Host::get_directories(self)
510 }
511}
512
513impl wasi::random::random::Host for WasiRandomCtx {
514 fn get_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
515 latest::random::random::Host::get_random_bytes(self, len)
516 }
517
518 fn get_random_u64(&mut self) -> wasmtime::Result<u64> {
519 latest::random::random::Host::get_random_u64(self)
520 }
521}
522
523impl wasi::random::insecure::Host for WasiRandomCtx {
524 fn get_insecure_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
525 latest::random::insecure::Host::get_insecure_random_bytes(self, len)
526 }
527
528 fn get_insecure_random_u64(&mut self) -> wasmtime::Result<u64> {
529 latest::random::insecure::Host::get_insecure_random_u64(self)
530 }
531}
532
533impl wasi::random::insecure_seed::Host for WasiRandomCtx {
534 fn get_insecure_seed(&mut self) -> wasmtime::Result<(u64, u64)> {
535 latest::random::insecure_seed::Host::get_insecure_seed(self)
536 }
537}
538
539impl wasi::cli::terminal_input::Host for WasiCliCtxView<'_> {}
540impl wasi::cli::terminal_output::Host for WasiCliCtxView<'_> {}
541
542impl wasi::cli::terminal_input::HostTerminalInput for WasiCliCtxView<'_> {
543 fn drop(
544 &mut self,
545 rep: Resource<wasi::cli::terminal_input::TerminalInput>,
546 ) -> wasmtime::Result<()> {
547 latest::cli::terminal_input::HostTerminalInput::drop(self, rep)
548 }
549}
550
551impl wasi::cli::terminal_output::HostTerminalOutput for WasiCliCtxView<'_> {
552 fn drop(
553 &mut self,
554 rep: Resource<wasi::cli::terminal_output::TerminalOutput>,
555 ) -> wasmtime::Result<()> {
556 latest::cli::terminal_output::HostTerminalOutput::drop(self, rep)
557 }
558}
559
560impl wasi::cli::terminal_stdin::Host for WasiCliCtxView<'_> {
561 fn get_terminal_stdin(
562 &mut self,
563 ) -> wasmtime::Result<Option<Resource<wasi::cli::terminal_input::TerminalInput>>> {
564 latest::cli::terminal_stdin::Host::get_terminal_stdin(self)
565 }
566}
567
568impl wasi::cli::terminal_stdout::Host for WasiCliCtxView<'_> {
569 fn get_terminal_stdout(
570 &mut self,
571 ) -> wasmtime::Result<Option<Resource<wasi::cli::terminal_output::TerminalOutput>>> {
572 latest::cli::terminal_stdout::Host::get_terminal_stdout(self)
573 }
574}
575
576impl wasi::cli::terminal_stderr::Host for WasiCliCtxView<'_> {
577 fn get_terminal_stderr(
578 &mut self,
579 ) -> wasmtime::Result<Option<Resource<wasi::cli::terminal_output::TerminalOutput>>> {
580 latest::cli::terminal_stderr::Host::get_terminal_stderr(self)
581 }
582}
583
584impl<T> wasi::cli::stdin::HostWithStore<T> for WasiCli {
585 fn read_via_stream(
586 mut store: Access<T, Self>,
587 ) -> wasmtime::Result<(
588 StreamReader<u8>,
589 FutureReader<Result<(), wasi::cli::types::ErrorCode>>,
590 )> {
591 latest::cli::stdin::HostWithStore::read_via_stream(reborrow(&mut store)).and_then(
592 |(stream, future)| Ok((stream, future.try_map(store, |v| v.map_err(|v| v.into()))?)),
593 )
594 }
595}
596
597impl wasi::cli::stdin::Host for WasiCliCtxView<'_> {}
598
599impl<T> wasi::cli::stdout::HostWithStore<T> for WasiCli {
600 fn write_via_stream(
601 mut store: Access<'_, T, Self>,
602 data: StreamReader<u8>,
603 ) -> wasmtime::Result<FutureReader<Result<(), wasi::cli::types::ErrorCode>>> {
604 latest::cli::stdout::HostWithStore::write_via_stream(reborrow(&mut store), data)
605 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
606 }
607}
608
609impl wasi::cli::stdout::Host for WasiCliCtxView<'_> {}
610
611impl<T> wasi::cli::stderr::HostWithStore<T> for WasiCli {
612 fn write_via_stream(
613 mut store: Access<'_, T, Self>,
614 data: StreamReader<u8>,
615 ) -> wasmtime::Result<FutureReader<Result<(), wasi::cli::types::ErrorCode>>> {
616 latest::cli::stderr::HostWithStore::write_via_stream(reborrow(&mut store), data)
617 .and_then(|v| v.try_map(store, |v| v.map_err(|v| v.into())))
618 }
619}
620
621impl wasi::cli::stderr::Host for WasiCliCtxView<'_> {}
622
623impl wasi::cli::environment::Host for WasiCliCtxView<'_> {
624 fn get_environment(&mut self) -> wasmtime::Result<Vec<(String, String)>> {
625 latest::cli::environment::Host::get_environment(self)
626 }
627
628 fn get_arguments(&mut self) -> wasmtime::Result<Vec<String>> {
629 latest::cli::environment::Host::get_arguments(self)
630 }
631
632 fn get_initial_cwd(&mut self) -> wasmtime::Result<Option<String>> {
633 latest::cli::environment::Host::get_initial_cwd(self)
634 }
635}
636
637impl wasi::cli::exit::Host for WasiCliCtxView<'_> {
638 fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> {
639 latest::cli::exit::Host::exit(self, status)
640 }
641
642 fn exit_with_code(&mut self, status_code: u8) -> wasmtime::Result<()> {
643 latest::cli::exit::Host::exit_with_code(self, status_code)
644 }
645}
646
647impl<T> wasi::sockets::types::Host for SpinSocketsView<'_, T> {}
648
649impl<T: 'static> wasi::sockets::types::HostUdpSocketWithStore<T> for SpinSockets<T> {
650 async fn send(
651 store: &Accessor<T, Self>,
652 socket: Resource<wasi::sockets::types::UdpSocket>,
653 data: Vec<u8>,
654 remote_address: Option<wasi::sockets::types::IpSocketAddress>,
655 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
656 convert_result(
657 latest::sockets::types::HostUdpSocketWithStore::send(
658 store,
659 socket,
660 data,
661 remote_address.map(|v| v.into()),
662 )
663 .await,
664 )
665 }
666
667 async fn receive(
668 store: &Accessor<T, Self>,
669 socket: Resource<wasi::sockets::types::UdpSocket>,
670 ) -> wasmtime::Result<
671 Result<(Vec<u8>, wasi::sockets::types::IpSocketAddress), wasi::sockets::types::ErrorCode>,
672 > {
673 convert_result(
674 latest::sockets::types::HostUdpSocketWithStore::receive(store, socket)
675 .await
676 .map(|(a, b)| (a, b.into())),
677 )
678 }
679}
680
681impl<T> wasi::sockets::types::HostUdpSocket for SpinSocketsView<'_, T> {
682 async fn bind(
683 &mut self,
684 socket: Resource<wasi::sockets::types::UdpSocket>,
685 local_address: wasi::sockets::types::IpSocketAddress,
686 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
687 convert_result(
688 latest::sockets::types::HostUdpSocket::bind(self, socket, local_address.into()).await,
689 )
690 }
691
692 async fn connect(
693 &mut self,
694 socket: Resource<wasi::sockets::types::UdpSocket>,
695 remote_address: wasi::sockets::types::IpSocketAddress,
696 ) -> wasmtime::Result<Result<(), wasi::sockets::types::ErrorCode>> {
697 convert_result(
698 latest::sockets::types::HostUdpSocket::connect(self, socket, remote_address.into())
699 .await,
700 )
701 }
702
703 async fn create(
704 &mut self,
705 address_family: wasi::sockets::types::IpAddressFamily,
706 ) -> wasmtime::Result<
707 Result<Resource<wasi::sockets::types::UdpSocket>, wasi::sockets::types::ErrorCode>,
708 > {
709 convert_result(
710 latest::sockets::types::HostUdpSocket::create(self, address_family.into()).await,
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}