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