Skip to main content

spin_factor_wasi/
wasi_2026_03_15.rs

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}