spin_factor_wasi/
wasi_2023_10_18.rs

1use spin_factors::anyhow::{self, Result};
2use std::mem;
3use wasmtime::component::{Linker, Resource, ResourceTable};
4use wasmtime_wasi::cli::{WasiCli, WasiCliCtxView};
5use wasmtime_wasi::clocks::{WasiClocks, WasiClocksCtxView};
6use wasmtime_wasi::filesystem::{WasiFilesystem, WasiFilesystemCtxView};
7use wasmtime_wasi::p2::DynPollable;
8use wasmtime_wasi::random::{WasiRandom, WasiRandomCtx};
9use wasmtime_wasi::sockets::{WasiSockets, WasiSocketsCtxView};
10use wasmtime_wasi::TrappableError;
11
12mod latest {
13    pub use wasmtime_wasi::p2::bindings::*;
14}
15
16mod bindings {
17    use super::latest;
18    pub use super::UdpSocket;
19
20    wasmtime::component::bindgen!({
21        path: "../../wit",
22        world: "wasi:cli/reactor@0.2.0-rc-2023-10-18",
23        imports: {
24            "wasi:io/streams/[drop]output-stream": async | trappable,
25            "wasi:io/streams/[drop]input-stream": async | trappable,
26            "wasi:filesystem/types/[method]descriptor.access-at": async | trappable,
27            "wasi:filesystem/types/[method]descriptor.advise": async | trappable,
28            "wasi:filesystem/types/[method]descriptor.change-directory-permissions-at": async | trappable,
29            "wasi:filesystem/types/[method]descriptor.change-file-permissions-at": async | trappable,
30            "wasi:filesystem/types/[method]descriptor.create-directory-at": async | trappable,
31            "wasi:filesystem/types/[method]descriptor.get-flags": async | trappable,
32            "wasi:filesystem/types/[method]descriptor.get-type": async | trappable,
33            "wasi:filesystem/types/[method]descriptor.is-same-object": async | trappable,
34            "wasi:filesystem/types/[method]descriptor.link-at": async | trappable,
35            "wasi:filesystem/types/[method]descriptor.lock-exclusive": async | trappable,
36            "wasi:filesystem/types/[method]descriptor.lock-shared": async | trappable,
37            "wasi:filesystem/types/[method]descriptor.metadata-hash": async | trappable,
38            "wasi:filesystem/types/[method]descriptor.metadata-hash-at": async | trappable,
39            "wasi:filesystem/types/[method]descriptor.open-at": async | trappable,
40            "wasi:filesystem/types/[method]descriptor.read": async | trappable,
41            "wasi:filesystem/types/[method]descriptor.read-directory": async | trappable,
42            "wasi:filesystem/types/[method]descriptor.readlink-at": async | trappable,
43            "wasi:filesystem/types/[method]descriptor.remove-directory-at": async | trappable,
44            "wasi:filesystem/types/[method]descriptor.rename-at": async | trappable,
45            "wasi:filesystem/types/[method]descriptor.set-size": async | trappable,
46            "wasi:filesystem/types/[method]descriptor.set-times": async | trappable,
47            "wasi:filesystem/types/[method]descriptor.set-times-at": async | trappable,
48            "wasi:filesystem/types/[method]descriptor.stat": async | trappable,
49            "wasi:filesystem/types/[method]descriptor.stat-at": async | trappable,
50            "wasi:filesystem/types/[method]descriptor.symlink-at": async | trappable,
51            "wasi:filesystem/types/[method]descriptor.sync": async | trappable,
52            "wasi:filesystem/types/[method]descriptor.sync-data": async | trappable,
53            "wasi:filesystem/types/[method]descriptor.try-lock-exclusive": async | trappable,
54            "wasi:filesystem/types/[method]descriptor.try-lock-shared": async | trappable,
55            "wasi:filesystem/types/[method]descriptor.unlink-file-at": async | trappable,
56            "wasi:filesystem/types/[method]descriptor.unlock": async | trappable,
57            "wasi:filesystem/types/[method]descriptor.write": async | trappable,
58            "wasi:filesystem/types/[method]directory-entry-stream.read-directory-entry": async | trappable,
59            "wasi:io/streams/[method]input-stream.blocking-read": async | trappable,
60            "wasi:io/streams/[method]input-stream.blocking-skip": async | trappable,
61            "wasi:io/streams/[method]output-stream.forward": async | trappable,
62            "wasi:io/streams/[method]output-stream.blocking-splice": async | trappable,
63            "wasi:io/streams/[method]output-stream.blocking-flush": async | trappable,
64            "wasi:io/streams/[method]output-stream.blocking-write-and-flush": async | trappable,
65            "wasi:io/streams/[method]output-stream.blocking-write-zeroes-and-flush": async | trappable,
66            "wasi:io/poll/poll-list": async | trappable,
67            "wasi:io/poll/poll-one": async | trappable,
68
69            "wasi:sockets/tcp/[method]tcp-socket.start-bind": async | trappable,
70            "wasi:sockets/tcp/[method]tcp-socket.start-connect": async | trappable,
71            "wasi:sockets/udp/[method]udp-socket.finish-connect": async | trappable,
72            "wasi:sockets/udp/[method]udp-socket.receive": async | trappable,
73            "wasi:sockets/udp/[method]udp-socket.send": async | trappable,
74            "wasi:sockets/udp/[method]udp-socket.start-bind": async | trappable,
75            default: trappable,
76        },
77        with: {
78            "wasi:io/poll/pollable": latest::io::poll::Pollable,
79            "wasi:io/streams/input-stream": latest::io::streams::InputStream,
80            "wasi:io/streams/output-stream": latest::io::streams::OutputStream,
81            "wasi:io/streams/error": latest::io::streams::Error,
82            "wasi:filesystem/types/directory-entry-stream": latest::filesystem::types::DirectoryEntryStream,
83            "wasi:filesystem/types/descriptor": latest::filesystem::types::Descriptor,
84            "wasi:cli/terminal-input/terminal-input": latest::cli::terminal_input::TerminalInput,
85            "wasi:cli/terminal-output/terminal-output": latest::cli::terminal_output::TerminalOutput,
86            "wasi:sockets/tcp/tcp-socket": latest::sockets::tcp::TcpSocket,
87            "wasi:sockets/udp/udp-socket": UdpSocket,
88            "wasi:sockets/network/network": latest::sockets::network::Network,
89            "wasi:sockets/ip-name-lookup/resolve-address-stream": latest::sockets::ip_name_lookup::ResolveAddressStream,
90        },
91    });
92}
93
94mod wasi {
95    pub use super::bindings::wasi::{
96        cli0_2_0_rc_2023_10_18 as cli, clocks0_2_0_rc_2023_10_18 as clocks,
97        filesystem0_2_0_rc_2023_10_18 as filesystem, io0_2_0_rc_2023_10_18 as io,
98        random0_2_0_rc_2023_10_18 as random, sockets0_2_0_rc_2023_10_18 as sockets,
99    };
100}
101
102use wasi::cli::terminal_input::TerminalInput;
103use wasi::cli::terminal_output::TerminalOutput;
104use wasi::clocks::monotonic_clock::Instant;
105use wasi::clocks::wall_clock::Datetime;
106use wasi::filesystem::types::{
107    AccessType, Advice, Descriptor, DescriptorFlags, DescriptorStat, DescriptorType,
108    DirectoryEntry, DirectoryEntryStream, Error, ErrorCode as FsErrorCode, Filesize,
109    MetadataHashValue, Modes, NewTimestamp, OpenFlags, PathFlags,
110};
111use wasi::io::streams::{InputStream, OutputStream, StreamError};
112use wasi::sockets::ip_name_lookup::{IpAddress, ResolveAddressStream};
113use wasi::sockets::network::{Ipv4SocketAddress, Ipv6SocketAddress};
114use wasi::sockets::tcp::{
115    ErrorCode as SocketErrorCode, IpAddressFamily, IpSocketAddress, Network, ShutdownType,
116    TcpSocket,
117};
118use wasi::sockets::udp::Datagram;
119
120use crate::HasIo;
121
122pub fn add_to_linker<T>(
123    linker: &mut Linker<T>,
124    io_closure: fn(&mut T) -> &mut ResourceTable,
125    random_closure: fn(&mut T) -> &mut WasiRandomCtx,
126    clocks_closure: fn(&mut T) -> WasiClocksCtxView<'_>,
127    cli_closure: fn(&mut T) -> WasiCliCtxView<'_>,
128    filesystem_closure: fn(&mut T) -> WasiFilesystemCtxView<'_>,
129    sockets_closure: fn(&mut T) -> WasiSocketsCtxView<'_>,
130) -> Result<()>
131where
132    T: Send + 'static,
133{
134    wasi::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
135    wasi::clocks::wall_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?;
136    wasi::filesystem::types::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
137    wasi::filesystem::preopens::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?;
138    wasi::io::poll::add_to_linker::<_, HasIo>(linker, io_closure)?;
139    wasi::io::streams::add_to_linker::<_, HasIo>(linker, io_closure)?;
140    wasi::random::random::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
141    wasi::random::insecure::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
142    wasi::random::insecure_seed::add_to_linker::<_, WasiRandom>(linker, random_closure)?;
143    wasi::cli::exit::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
144    wasi::cli::environment::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
145    wasi::cli::stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
146    wasi::cli::stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
147    wasi::cli::stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
148    wasi::cli::terminal_input::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
149    wasi::cli::terminal_output::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
150    wasi::cli::terminal_stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
151    wasi::cli::terminal_stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
152    wasi::cli::terminal_stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?;
153    wasi::sockets::tcp::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
154    wasi::sockets::tcp_create_socket::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
155    wasi::sockets::udp::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
156    wasi::sockets::udp_create_socket::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
157    wasi::sockets::instance_network::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
158    wasi::sockets::network::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
159    wasi::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?;
160    Ok(())
161}
162
163impl wasi::clocks::monotonic_clock::Host for WasiClocksCtxView<'_> {
164    fn now(&mut self) -> wasmtime::Result<Instant> {
165        latest::clocks::monotonic_clock::Host::now(self)
166    }
167
168    fn resolution(&mut self) -> wasmtime::Result<Instant> {
169        latest::clocks::monotonic_clock::Host::resolution(self)
170    }
171
172    fn subscribe(
173        &mut self,
174        when: Instant,
175        absolute: bool,
176    ) -> wasmtime::Result<Resource<DynPollable>> {
177        if absolute {
178            latest::clocks::monotonic_clock::Host::subscribe_instant(self, when)
179        } else {
180            latest::clocks::monotonic_clock::Host::subscribe_duration(self, when)
181        }
182    }
183}
184
185impl wasi::clocks::wall_clock::Host for WasiClocksCtxView<'_> {
186    fn now(&mut self) -> wasmtime::Result<Datetime> {
187        Ok(latest::clocks::wall_clock::Host::now(self)?.into())
188    }
189
190    fn resolution(&mut self) -> wasmtime::Result<Datetime> {
191        Ok(latest::clocks::wall_clock::Host::resolution(self)?.into())
192    }
193}
194
195impl wasi::filesystem::types::Host for WasiFilesystemCtxView<'_> {
196    fn filesystem_error_code(
197        &mut self,
198        err: Resource<wasi::filesystem::types::Error>,
199    ) -> wasmtime::Result<Option<FsErrorCode>> {
200        Ok(latest::filesystem::types::Host::filesystem_error_code(self, err)?.map(|e| e.into()))
201    }
202}
203
204impl wasi::filesystem::types::HostDescriptor for WasiFilesystemCtxView<'_> {
205    fn read_via_stream(
206        &mut self,
207        self_: Resource<Descriptor>,
208        offset: Filesize,
209    ) -> wasmtime::Result<Result<Resource<InputStream>, FsErrorCode>> {
210        convert_result(latest::filesystem::types::HostDescriptor::read_via_stream(
211            self, self_, offset,
212        ))
213    }
214
215    fn write_via_stream(
216        &mut self,
217        self_: Resource<Descriptor>,
218        offset: Filesize,
219    ) -> wasmtime::Result<Result<Resource<OutputStream>, FsErrorCode>> {
220        convert_result(latest::filesystem::types::HostDescriptor::write_via_stream(
221            self, self_, offset,
222        ))
223    }
224
225    fn append_via_stream(
226        &mut self,
227        self_: Resource<Descriptor>,
228    ) -> wasmtime::Result<Result<Resource<OutputStream>, FsErrorCode>> {
229        convert_result(latest::filesystem::types::HostDescriptor::append_via_stream(self, self_))
230    }
231
232    async fn advise(
233        &mut self,
234        self_: Resource<Descriptor>,
235        offset: Filesize,
236        length: Filesize,
237        advice: Advice,
238    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
239        convert_result(
240            latest::filesystem::types::HostDescriptor::advise(
241                self,
242                self_,
243                offset,
244                length,
245                advice.into(),
246            )
247            .await,
248        )
249    }
250
251    async fn sync_data(
252        &mut self,
253        self_: Resource<Descriptor>,
254    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
255        convert_result(latest::filesystem::types::HostDescriptor::sync_data(self, self_).await)
256    }
257
258    async fn get_flags(
259        &mut self,
260        self_: Resource<Descriptor>,
261    ) -> wasmtime::Result<Result<DescriptorFlags, FsErrorCode>> {
262        convert_result(latest::filesystem::types::HostDescriptor::get_flags(self, self_).await)
263    }
264
265    async fn get_type(
266        &mut self,
267        self_: Resource<Descriptor>,
268    ) -> wasmtime::Result<Result<DescriptorType, FsErrorCode>> {
269        convert_result(latest::filesystem::types::HostDescriptor::get_type(self, self_).await)
270    }
271
272    async fn set_size(
273        &mut self,
274        self_: Resource<Descriptor>,
275        size: Filesize,
276    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
277        convert_result(latest::filesystem::types::HostDescriptor::set_size(self, self_, size).await)
278    }
279
280    async fn set_times(
281        &mut self,
282        self_: Resource<Descriptor>,
283        data_access_timestamp: NewTimestamp,
284        data_modification_timestamp: NewTimestamp,
285    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
286        convert_result(
287            latest::filesystem::types::HostDescriptor::set_times(
288                self,
289                self_,
290                data_access_timestamp.into(),
291                data_modification_timestamp.into(),
292            )
293            .await,
294        )
295    }
296
297    async fn read(
298        &mut self,
299        self_: Resource<Descriptor>,
300        length: Filesize,
301        offset: Filesize,
302    ) -> wasmtime::Result<Result<(Vec<u8>, bool), FsErrorCode>> {
303        convert_result(
304            latest::filesystem::types::HostDescriptor::read(self, self_, length, offset).await,
305        )
306    }
307
308    async fn write(
309        &mut self,
310        self_: Resource<Descriptor>,
311        buffer: Vec<u8>,
312        offset: Filesize,
313    ) -> wasmtime::Result<Result<Filesize, FsErrorCode>> {
314        convert_result(
315            latest::filesystem::types::HostDescriptor::write(self, self_, buffer, offset).await,
316        )
317    }
318
319    async fn read_directory(
320        &mut self,
321        self_: Resource<Descriptor>,
322    ) -> wasmtime::Result<Result<Resource<DirectoryEntryStream>, FsErrorCode>> {
323        convert_result(latest::filesystem::types::HostDescriptor::read_directory(self, self_).await)
324    }
325
326    async fn sync(
327        &mut self,
328        self_: Resource<Descriptor>,
329    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
330        convert_result(latest::filesystem::types::HostDescriptor::sync(self, self_).await)
331    }
332
333    async fn create_directory_at(
334        &mut self,
335        self_: Resource<Descriptor>,
336        path: String,
337    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
338        convert_result(
339            latest::filesystem::types::HostDescriptor::create_directory_at(self, self_, path).await,
340        )
341    }
342
343    async fn stat(
344        &mut self,
345        self_: Resource<Descriptor>,
346    ) -> wasmtime::Result<Result<DescriptorStat, FsErrorCode>> {
347        convert_result(latest::filesystem::types::HostDescriptor::stat(self, self_).await)
348    }
349
350    async fn stat_at(
351        &mut self,
352        self_: Resource<Descriptor>,
353        path_flags: PathFlags,
354        path: String,
355    ) -> wasmtime::Result<Result<DescriptorStat, FsErrorCode>> {
356        convert_result(
357            latest::filesystem::types::HostDescriptor::stat_at(
358                self,
359                self_,
360                path_flags.into(),
361                path,
362            )
363            .await,
364        )
365    }
366
367    async fn set_times_at(
368        &mut self,
369        self_: Resource<Descriptor>,
370        path_flags: PathFlags,
371        path: String,
372        data_access_timestamp: NewTimestamp,
373        data_modification_timestamp: NewTimestamp,
374    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
375        convert_result(
376            latest::filesystem::types::HostDescriptor::set_times_at(
377                self,
378                self_,
379                path_flags.into(),
380                path,
381                data_access_timestamp.into(),
382                data_modification_timestamp.into(),
383            )
384            .await,
385        )
386    }
387
388    async fn link_at(
389        &mut self,
390        self_: Resource<Descriptor>,
391        old_path_flags: PathFlags,
392        old_path: String,
393        new_descriptor: Resource<Descriptor>,
394        new_path: String,
395    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
396        convert_result(
397            latest::filesystem::types::HostDescriptor::link_at(
398                self,
399                self_,
400                old_path_flags.into(),
401                old_path,
402                new_descriptor,
403                new_path,
404            )
405            .await,
406        )
407    }
408
409    async fn open_at(
410        &mut self,
411        self_: Resource<Descriptor>,
412        path_flags: PathFlags,
413        path: String,
414        open_flags: OpenFlags,
415        flags: DescriptorFlags,
416        _modes: Modes,
417    ) -> wasmtime::Result<Result<Resource<Descriptor>, FsErrorCode>> {
418        convert_result(
419            latest::filesystem::types::HostDescriptor::open_at(
420                self,
421                self_,
422                path_flags.into(),
423                path,
424                open_flags.into(),
425                flags.into(),
426            )
427            .await,
428        )
429    }
430
431    async fn readlink_at(
432        &mut self,
433        self_: Resource<Descriptor>,
434        path: String,
435    ) -> wasmtime::Result<Result<String, FsErrorCode>> {
436        convert_result(
437            latest::filesystem::types::HostDescriptor::readlink_at(self, self_, path).await,
438        )
439    }
440
441    async fn remove_directory_at(
442        &mut self,
443        self_: Resource<Descriptor>,
444        path: String,
445    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
446        convert_result(
447            latest::filesystem::types::HostDescriptor::remove_directory_at(self, self_, path).await,
448        )
449    }
450
451    async fn rename_at(
452        &mut self,
453        self_: Resource<Descriptor>,
454        old_path: String,
455        new_descriptor: Resource<Descriptor>,
456        new_path: String,
457    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
458        convert_result(
459            latest::filesystem::types::HostDescriptor::rename_at(
460                self,
461                self_,
462                old_path,
463                new_descriptor,
464                new_path,
465            )
466            .await,
467        )
468    }
469
470    async fn symlink_at(
471        &mut self,
472        self_: Resource<Descriptor>,
473        old_path: String,
474        new_path: String,
475    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
476        convert_result(
477            latest::filesystem::types::HostDescriptor::symlink_at(self, self_, old_path, new_path)
478                .await,
479        )
480    }
481
482    async fn access_at(
483        &mut self,
484        _self_: Resource<Descriptor>,
485        _path_flags: PathFlags,
486        _path: String,
487        _type_: AccessType,
488    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
489        anyhow::bail!("access-at API is no longer supported in the latest snapshot")
490    }
491
492    async fn unlink_file_at(
493        &mut self,
494        self_: Resource<Descriptor>,
495        path: String,
496    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
497        convert_result(
498            latest::filesystem::types::HostDescriptor::unlink_file_at(self, self_, path).await,
499        )
500    }
501
502    async fn change_file_permissions_at(
503        &mut self,
504        _self_: Resource<Descriptor>,
505        _path_flags: PathFlags,
506        _path: String,
507        _modes: Modes,
508    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
509        anyhow::bail!(
510            "change-file-permissions-at API is no longer supported in the latest snapshot"
511        )
512    }
513
514    async fn change_directory_permissions_at(
515        &mut self,
516        _self_: Resource<Descriptor>,
517        _path_flags: PathFlags,
518        _path: String,
519        _modes: Modes,
520    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
521        anyhow::bail!(
522            "change-directory-permissions-at API is no longer supported in the latest snapshot"
523        )
524    }
525
526    async fn lock_shared(
527        &mut self,
528        _self_: Resource<Descriptor>,
529    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
530        anyhow::bail!("lock-shared API is no longer supported in the latest snapshot")
531    }
532
533    async fn lock_exclusive(
534        &mut self,
535        _self_: Resource<Descriptor>,
536    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
537        anyhow::bail!("lock-exclusive API is no longer supported in the latest snapshot")
538    }
539
540    async fn try_lock_shared(
541        &mut self,
542        _self_: Resource<Descriptor>,
543    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
544        anyhow::bail!("try-lock-shared API is no longer supported in the latest snapshot")
545    }
546
547    async fn try_lock_exclusive(
548        &mut self,
549        _self_: Resource<Descriptor>,
550    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
551        anyhow::bail!("try-lock-exclusive API is no longer supported in the latest snapshot")
552    }
553
554    async fn unlock(
555        &mut self,
556        _self_: Resource<Descriptor>,
557    ) -> wasmtime::Result<Result<(), FsErrorCode>> {
558        anyhow::bail!("unlock API is no longer supported in the latest snapshot")
559    }
560
561    async fn is_same_object(
562        &mut self,
563        self_: Resource<Descriptor>,
564        other: Resource<Descriptor>,
565    ) -> wasmtime::Result<bool> {
566        latest::filesystem::types::HostDescriptor::is_same_object(self, self_, other).await
567    }
568
569    async fn metadata_hash(
570        &mut self,
571        self_: Resource<Descriptor>,
572    ) -> wasmtime::Result<Result<MetadataHashValue, FsErrorCode>> {
573        convert_result(latest::filesystem::types::HostDescriptor::metadata_hash(self, self_).await)
574    }
575
576    async fn metadata_hash_at(
577        &mut self,
578        self_: Resource<Descriptor>,
579        path_flags: PathFlags,
580        path: String,
581    ) -> wasmtime::Result<Result<MetadataHashValue, FsErrorCode>> {
582        convert_result(
583            latest::filesystem::types::HostDescriptor::metadata_hash_at(
584                self,
585                self_,
586                path_flags.into(),
587                path,
588            )
589            .await,
590        )
591    }
592
593    fn drop(&mut self, rep: Resource<Descriptor>) -> wasmtime::Result<()> {
594        latest::filesystem::types::HostDescriptor::drop(self, rep)
595    }
596}
597
598impl wasi::filesystem::types::HostDirectoryEntryStream for WasiFilesystemCtxView<'_> {
599    async fn read_directory_entry(
600        &mut self,
601        self_: Resource<DirectoryEntryStream>,
602    ) -> wasmtime::Result<Result<Option<DirectoryEntry>, FsErrorCode>> {
603        convert_result(
604            latest::filesystem::types::HostDirectoryEntryStream::read_directory_entry(self, self_)
605                .await
606                .map(|e| e.map(DirectoryEntry::from)),
607        )
608    }
609
610    fn drop(&mut self, rep: Resource<DirectoryEntryStream>) -> wasmtime::Result<()> {
611        latest::filesystem::types::HostDirectoryEntryStream::drop(self, rep)
612    }
613}
614
615impl wasi::filesystem::preopens::Host for WasiFilesystemCtxView<'_> {
616    fn get_directories(&mut self) -> wasmtime::Result<Vec<(Resource<Descriptor>, String)>> {
617        latest::filesystem::preopens::Host::get_directories(self)
618    }
619}
620
621impl wasi::io::poll::Host for ResourceTable {
622    async fn poll_list(&mut self, list: Vec<Resource<DynPollable>>) -> wasmtime::Result<Vec<u32>> {
623        latest::io::poll::Host::poll(self, list).await
624    }
625
626    async fn poll_one(&mut self, rep: Resource<DynPollable>) -> wasmtime::Result<()> {
627        latest::io::poll::HostPollable::block(self, rep).await
628    }
629}
630
631impl wasi::io::poll::HostPollable for ResourceTable {
632    fn drop(&mut self, rep: Resource<DynPollable>) -> wasmtime::Result<()> {
633        latest::io::poll::HostPollable::drop(self, rep)
634    }
635}
636
637impl wasi::io::streams::Host for ResourceTable {}
638
639impl wasi::io::streams::HostError for ResourceTable {
640    fn to_debug_string(&mut self, self_: Resource<Error>) -> wasmtime::Result<String> {
641        latest::io::error::HostError::to_debug_string(self, self_)
642    }
643
644    fn drop(&mut self, rep: Resource<Error>) -> wasmtime::Result<()> {
645        latest::io::error::HostError::drop(self, rep)
646    }
647}
648
649impl wasi::io::streams::HostInputStream for ResourceTable {
650    fn read(
651        &mut self,
652        self_: Resource<InputStream>,
653        len: u64,
654    ) -> wasmtime::Result<Result<Vec<u8>, StreamError>> {
655        let result = latest::io::streams::HostInputStream::read(self, self_, len);
656        convert_stream_result(self, result)
657    }
658
659    async fn blocking_read(
660        &mut self,
661        self_: Resource<InputStream>,
662        len: u64,
663    ) -> wasmtime::Result<Result<Vec<u8>, StreamError>> {
664        let result = latest::io::streams::HostInputStream::blocking_read(self, self_, len).await;
665        convert_stream_result(self, result)
666    }
667
668    fn skip(
669        &mut self,
670        self_: Resource<InputStream>,
671        len: u64,
672    ) -> wasmtime::Result<Result<u64, StreamError>> {
673        let result = latest::io::streams::HostInputStream::skip(self, self_, len);
674        convert_stream_result(self, result)
675    }
676
677    async fn blocking_skip(
678        &mut self,
679        self_: Resource<InputStream>,
680        len: u64,
681    ) -> wasmtime::Result<Result<u64, StreamError>> {
682        let result = latest::io::streams::HostInputStream::blocking_skip(self, self_, len).await;
683        convert_stream_result(self, result)
684    }
685
686    fn subscribe(
687        &mut self,
688        self_: Resource<InputStream>,
689    ) -> wasmtime::Result<Resource<DynPollable>> {
690        latest::io::streams::HostInputStream::subscribe(self, self_)
691    }
692
693    async fn drop(&mut self, rep: Resource<InputStream>) -> wasmtime::Result<()> {
694        latest::io::streams::HostInputStream::drop(self, rep).await
695    }
696}
697
698impl wasi::io::streams::HostOutputStream for ResourceTable {
699    fn check_write(
700        &mut self,
701        self_: Resource<OutputStream>,
702    ) -> wasmtime::Result<Result<u64, StreamError>> {
703        let result = latest::io::streams::HostOutputStream::check_write(self, self_);
704        convert_stream_result(self, result)
705    }
706
707    fn write(
708        &mut self,
709        self_: Resource<OutputStream>,
710        contents: Vec<u8>,
711    ) -> wasmtime::Result<Result<(), StreamError>> {
712        let result = latest::io::streams::HostOutputStream::write(self, self_, contents);
713        convert_stream_result(self, result)
714    }
715
716    async fn blocking_write_and_flush(
717        &mut self,
718        self_: Resource<OutputStream>,
719        contents: Vec<u8>,
720    ) -> wasmtime::Result<Result<(), StreamError>> {
721        let result =
722            latest::io::streams::HostOutputStream::blocking_write_and_flush(self, self_, contents)
723                .await;
724        convert_stream_result(self, result)
725    }
726
727    fn flush(
728        &mut self,
729        self_: Resource<OutputStream>,
730    ) -> wasmtime::Result<Result<(), StreamError>> {
731        let result = latest::io::streams::HostOutputStream::flush(self, self_);
732        convert_stream_result(self, result)
733    }
734
735    async fn blocking_flush(
736        &mut self,
737        self_: Resource<OutputStream>,
738    ) -> wasmtime::Result<Result<(), StreamError>> {
739        let result = latest::io::streams::HostOutputStream::blocking_flush(self, self_).await;
740        convert_stream_result(self, result)
741    }
742
743    fn subscribe(
744        &mut self,
745        self_: Resource<OutputStream>,
746    ) -> wasmtime::Result<Resource<DynPollable>> {
747        latest::io::streams::HostOutputStream::subscribe(self, self_)
748    }
749
750    fn write_zeroes(
751        &mut self,
752        self_: Resource<OutputStream>,
753        len: u64,
754    ) -> wasmtime::Result<Result<(), StreamError>> {
755        let result = latest::io::streams::HostOutputStream::write_zeroes(self, self_, len);
756        convert_stream_result(self, result)
757    }
758
759    async fn blocking_write_zeroes_and_flush(
760        &mut self,
761        self_: Resource<OutputStream>,
762        len: u64,
763    ) -> wasmtime::Result<Result<(), StreamError>> {
764        let result = latest::io::streams::HostOutputStream::blocking_write_zeroes_and_flush(
765            self, self_, len,
766        )
767        .await;
768        convert_stream_result(self, result)
769    }
770
771    fn splice(
772        &mut self,
773        self_: Resource<OutputStream>,
774        src: Resource<InputStream>,
775        len: u64,
776    ) -> wasmtime::Result<Result<u64, StreamError>> {
777        let result = latest::io::streams::HostOutputStream::splice(self, self_, src, len);
778        convert_stream_result(self, result)
779    }
780
781    async fn blocking_splice(
782        &mut self,
783        self_: Resource<OutputStream>,
784        src: Resource<InputStream>,
785        len: u64,
786    ) -> wasmtime::Result<Result<u64, StreamError>> {
787        let result =
788            latest::io::streams::HostOutputStream::blocking_splice(self, self_, src, len).await;
789        convert_stream_result(self, result)
790    }
791
792    async fn forward(
793        &mut self,
794        _self_: Resource<OutputStream>,
795        _src: Resource<InputStream>,
796    ) -> wasmtime::Result<Result<u64, StreamError>> {
797        anyhow::bail!("forward API no longer supported")
798    }
799
800    async fn drop(&mut self, rep: Resource<OutputStream>) -> wasmtime::Result<()> {
801        latest::io::streams::HostOutputStream::drop(self, rep).await
802    }
803}
804
805impl wasi::random::random::Host for WasiRandomCtx {
806    fn get_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
807        latest::random::random::Host::get_random_bytes(self, len)
808    }
809
810    fn get_random_u64(&mut self) -> wasmtime::Result<u64> {
811        latest::random::random::Host::get_random_u64(self)
812    }
813}
814
815impl wasi::random::insecure::Host for WasiRandomCtx {
816    fn get_insecure_random_bytes(&mut self, len: u64) -> wasmtime::Result<Vec<u8>> {
817        latest::random::insecure::Host::get_insecure_random_bytes(self, len)
818    }
819
820    fn get_insecure_random_u64(&mut self) -> wasmtime::Result<u64> {
821        latest::random::insecure::Host::get_insecure_random_u64(self)
822    }
823}
824
825impl wasi::random::insecure_seed::Host for WasiRandomCtx {
826    fn insecure_seed(&mut self) -> wasmtime::Result<(u64, u64)> {
827        latest::random::insecure_seed::Host::insecure_seed(self)
828    }
829}
830
831impl wasi::cli::exit::Host for WasiCliCtxView<'_> {
832    fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> {
833        latest::cli::exit::Host::exit(self, status)
834    }
835}
836
837impl wasi::cli::environment::Host for WasiCliCtxView<'_> {
838    fn get_environment(&mut self) -> wasmtime::Result<Vec<(String, String)>> {
839        latest::cli::environment::Host::get_environment(self)
840    }
841
842    fn get_arguments(&mut self) -> wasmtime::Result<Vec<String>> {
843        latest::cli::environment::Host::get_arguments(self)
844    }
845
846    fn initial_cwd(&mut self) -> wasmtime::Result<Option<String>> {
847        latest::cli::environment::Host::initial_cwd(self)
848    }
849}
850
851impl wasi::cli::stdin::Host for WasiCliCtxView<'_> {
852    fn get_stdin(&mut self) -> wasmtime::Result<Resource<InputStream>> {
853        latest::cli::stdin::Host::get_stdin(self)
854    }
855}
856
857impl wasi::cli::stdout::Host for WasiCliCtxView<'_> {
858    fn get_stdout(&mut self) -> wasmtime::Result<Resource<OutputStream>> {
859        latest::cli::stdout::Host::get_stdout(self)
860    }
861}
862
863impl wasi::cli::stderr::Host for WasiCliCtxView<'_> {
864    fn get_stderr(&mut self) -> wasmtime::Result<Resource<OutputStream>> {
865        latest::cli::stderr::Host::get_stderr(self)
866    }
867}
868
869impl wasi::cli::terminal_stdin::Host for WasiCliCtxView<'_> {
870    fn get_terminal_stdin(&mut self) -> wasmtime::Result<Option<Resource<TerminalInput>>> {
871        latest::cli::terminal_stdin::Host::get_terminal_stdin(self)
872    }
873}
874
875impl wasi::cli::terminal_stdout::Host for WasiCliCtxView<'_> {
876    fn get_terminal_stdout(&mut self) -> wasmtime::Result<Option<Resource<TerminalOutput>>> {
877        latest::cli::terminal_stdout::Host::get_terminal_stdout(self)
878    }
879}
880
881impl wasi::cli::terminal_stderr::Host for WasiCliCtxView<'_> {
882    fn get_terminal_stderr(&mut self) -> wasmtime::Result<Option<Resource<TerminalOutput>>> {
883        latest::cli::terminal_stderr::Host::get_terminal_stderr(self)
884    }
885}
886
887impl wasi::cli::terminal_input::Host for WasiCliCtxView<'_> {}
888
889impl wasi::cli::terminal_input::HostTerminalInput for WasiCliCtxView<'_> {
890    fn drop(&mut self, rep: Resource<TerminalInput>) -> wasmtime::Result<()> {
891        latest::cli::terminal_input::HostTerminalInput::drop(self, rep)
892    }
893}
894
895impl wasi::cli::terminal_output::Host for WasiCliCtxView<'_> {}
896
897impl wasi::cli::terminal_output::HostTerminalOutput for WasiCliCtxView<'_> {
898    fn drop(&mut self, rep: Resource<TerminalOutput>) -> wasmtime::Result<()> {
899        latest::cli::terminal_output::HostTerminalOutput::drop(self, rep)
900    }
901}
902
903impl wasi::sockets::tcp::Host for WasiSocketsCtxView<'_> {}
904
905impl wasi::sockets::tcp::HostTcpSocket for WasiSocketsCtxView<'_> {
906    async fn start_bind(
907        &mut self,
908        self_: Resource<TcpSocket>,
909        network: Resource<Network>,
910        local_address: IpSocketAddress,
911    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
912        convert_result(
913            latest::sockets::tcp::HostTcpSocket::start_bind(
914                self,
915                self_,
916                network,
917                local_address.into(),
918            )
919            .await,
920        )
921    }
922
923    fn finish_bind(
924        &mut self,
925        self_: Resource<TcpSocket>,
926    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
927        convert_result(latest::sockets::tcp::HostTcpSocket::finish_bind(
928            self, self_,
929        ))
930    }
931
932    async fn start_connect(
933        &mut self,
934        self_: Resource<TcpSocket>,
935        network: Resource<Network>,
936        remote_address: IpSocketAddress,
937    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
938        convert_result(
939            latest::sockets::tcp::HostTcpSocket::start_connect(
940                self,
941                self_,
942                network,
943                remote_address.into(),
944            )
945            .await,
946        )
947    }
948
949    fn finish_connect(
950        &mut self,
951        self_: Resource<TcpSocket>,
952    ) -> wasmtime::Result<Result<(Resource<InputStream>, Resource<OutputStream>), SocketErrorCode>>
953    {
954        convert_result(latest::sockets::tcp::HostTcpSocket::finish_connect(
955            self, self_,
956        ))
957    }
958
959    fn start_listen(
960        &mut self,
961        self_: Resource<TcpSocket>,
962    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
963        convert_result(latest::sockets::tcp::HostTcpSocket::start_listen(
964            self, self_,
965        ))
966    }
967
968    fn finish_listen(
969        &mut self,
970        self_: Resource<TcpSocket>,
971    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
972        convert_result(latest::sockets::tcp::HostTcpSocket::finish_listen(
973            self, self_,
974        ))
975    }
976
977    fn accept(
978        &mut self,
979        self_: Resource<TcpSocket>,
980    ) -> wasmtime::Result<
981        Result<
982            (
983                Resource<TcpSocket>,
984                Resource<InputStream>,
985                Resource<OutputStream>,
986            ),
987            SocketErrorCode,
988        >,
989    > {
990        convert_result(latest::sockets::tcp::HostTcpSocket::accept(self, self_))
991    }
992
993    fn local_address(
994        &mut self,
995        self_: Resource<TcpSocket>,
996    ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
997        convert_result(latest::sockets::tcp::HostTcpSocket::local_address(
998            self, self_,
999        ))
1000    }
1001
1002    fn remote_address(
1003        &mut self,
1004        self_: Resource<TcpSocket>,
1005    ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1006        convert_result(latest::sockets::tcp::HostTcpSocket::remote_address(
1007            self, self_,
1008        ))
1009    }
1010
1011    fn address_family(&mut self, self_: Resource<TcpSocket>) -> wasmtime::Result<IpAddressFamily> {
1012        latest::sockets::tcp::HostTcpSocket::address_family(self, self_).map(|e| e.into())
1013    }
1014
1015    fn ipv6_only(
1016        &mut self,
1017        _self_: Resource<TcpSocket>,
1018    ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1019        anyhow::bail!("ipv6-only API no longer supported")
1020    }
1021
1022    fn set_ipv6_only(
1023        &mut self,
1024        _self_: Resource<TcpSocket>,
1025        _value: bool,
1026    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1027        anyhow::bail!("ipv6-only API no longer supported")
1028    }
1029
1030    fn set_listen_backlog_size(
1031        &mut self,
1032        self_: Resource<TcpSocket>,
1033        value: u64,
1034    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1035        convert_result(
1036            latest::sockets::tcp::HostTcpSocket::set_listen_backlog_size(self, self_, value),
1037        )
1038    }
1039
1040    fn keep_alive(
1041        &mut self,
1042        self_: Resource<TcpSocket>,
1043    ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1044        convert_result(latest::sockets::tcp::HostTcpSocket::keep_alive_enabled(
1045            self, self_,
1046        ))
1047    }
1048
1049    fn set_keep_alive(
1050        &mut self,
1051        self_: Resource<TcpSocket>,
1052        value: bool,
1053    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1054        convert_result(latest::sockets::tcp::HostTcpSocket::set_keep_alive_enabled(
1055            self, self_, value,
1056        ))
1057    }
1058
1059    fn no_delay(
1060        &mut self,
1061        _self_: Resource<TcpSocket>,
1062    ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1063        anyhow::bail!("no-delay API no longer supported")
1064    }
1065
1066    fn set_no_delay(
1067        &mut self,
1068        _self_: Resource<TcpSocket>,
1069        _value: bool,
1070    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1071        anyhow::bail!("set-no-delay API no longer supported")
1072    }
1073
1074    fn unicast_hop_limit(
1075        &mut self,
1076        self_: Resource<TcpSocket>,
1077    ) -> wasmtime::Result<Result<u8, SocketErrorCode>> {
1078        convert_result(latest::sockets::tcp::HostTcpSocket::hop_limit(self, self_))
1079    }
1080
1081    fn set_unicast_hop_limit(
1082        &mut self,
1083        self_: Resource<TcpSocket>,
1084        value: u8,
1085    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1086        convert_result(latest::sockets::tcp::HostTcpSocket::set_hop_limit(
1087            self, self_, value,
1088        ))
1089    }
1090
1091    fn receive_buffer_size(
1092        &mut self,
1093        self_: Resource<TcpSocket>,
1094    ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1095        convert_result(latest::sockets::tcp::HostTcpSocket::receive_buffer_size(
1096            self, self_,
1097        ))
1098    }
1099
1100    fn set_receive_buffer_size(
1101        &mut self,
1102        self_: Resource<TcpSocket>,
1103        value: u64,
1104    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1105        convert_result(
1106            latest::sockets::tcp::HostTcpSocket::set_receive_buffer_size(self, self_, value),
1107        )
1108    }
1109
1110    fn send_buffer_size(
1111        &mut self,
1112        self_: Resource<TcpSocket>,
1113    ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1114        convert_result(latest::sockets::tcp::HostTcpSocket::send_buffer_size(
1115            self, self_,
1116        ))
1117    }
1118
1119    fn set_send_buffer_size(
1120        &mut self,
1121        self_: Resource<TcpSocket>,
1122        value: u64,
1123    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1124        convert_result(latest::sockets::tcp::HostTcpSocket::set_send_buffer_size(
1125            self, self_, value,
1126        ))
1127    }
1128
1129    fn subscribe(&mut self, self_: Resource<TcpSocket>) -> wasmtime::Result<Resource<DynPollable>> {
1130        latest::sockets::tcp::HostTcpSocket::subscribe(self, self_)
1131    }
1132
1133    fn shutdown(
1134        &mut self,
1135        self_: Resource<TcpSocket>,
1136        shutdown_type: ShutdownType,
1137    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1138        convert_result(latest::sockets::tcp::HostTcpSocket::shutdown(
1139            self,
1140            self_,
1141            shutdown_type.into(),
1142        ))
1143    }
1144
1145    fn drop(&mut self, rep: Resource<TcpSocket>) -> wasmtime::Result<()> {
1146        latest::sockets::tcp::HostTcpSocket::drop(self, rep)
1147    }
1148}
1149
1150impl wasi::sockets::tcp_create_socket::Host for WasiSocketsCtxView<'_> {
1151    fn create_tcp_socket(
1152        &mut self,
1153        address_family: IpAddressFamily,
1154    ) -> wasmtime::Result<Result<Resource<TcpSocket>, SocketErrorCode>> {
1155        convert_result(latest::sockets::tcp_create_socket::Host::create_tcp_socket(
1156            self,
1157            address_family.into(),
1158        ))
1159    }
1160}
1161
1162impl wasi::sockets::udp::Host for WasiSocketsCtxView<'_> {}
1163
1164/// Between the snapshot of WASI that this file is implementing and the current
1165/// implementation of WASI UDP sockets were redesigned slightly to deal with
1166/// a different way of managing incoming and outgoing datagrams. This means
1167/// that this snapshot's `{start,finish}_connect`, `send`, and `receive`
1168/// methods are no longer natively implemented, so they're polyfilled by this
1169/// implementation.
1170pub enum UdpSocket {
1171    Initial(Resource<latest::sockets::udp::UdpSocket>),
1172    Connecting(Resource<latest::sockets::udp::UdpSocket>, IpSocketAddress),
1173    Connected {
1174        socket: Resource<latest::sockets::udp::UdpSocket>,
1175        incoming: Resource<latest::sockets::udp::IncomingDatagramStream>,
1176        outgoing: Resource<latest::sockets::udp::OutgoingDatagramStream>,
1177    },
1178    Dummy,
1179}
1180
1181impl UdpSocket {
1182    async fn finish_connect(
1183        table: &mut WasiSocketsCtxView<'_>,
1184        socket: &Resource<UdpSocket>,
1185        explicit: bool,
1186    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1187        let state = table.table.get_mut(socket)?;
1188        let (new_socket, addr) = match mem::replace(state, UdpSocket::Dummy) {
1189            // Implicit finishes will call `stream` for sockets in the initial
1190            // state.
1191            UdpSocket::Initial(socket) if !explicit => (socket, None),
1192            // Implicit finishes won't try to reconnect a socket.
1193            UdpSocket::Connected { .. } if !explicit => return Ok(Ok(())),
1194            // Only explicit finishes can transition from the `Connecting` state.
1195            UdpSocket::Connecting(socket, addr) if explicit => (socket, Some(addr)),
1196            _ => return Ok(Err(SocketErrorCode::ConcurrencyConflict)),
1197        };
1198        let borrow = Resource::new_borrow(new_socket.rep());
1199        let result = convert_result(
1200            latest::sockets::udp::HostUdpSocket::stream(table, borrow, addr.map(|a| a.into()))
1201                .await,
1202        )?;
1203        let (incoming, outgoing) = match result {
1204            Ok(pair) => pair,
1205            Err(e) => return Ok(Err(e)),
1206        };
1207        *table.table.get_mut(socket)? = UdpSocket::Connected {
1208            socket: new_socket,
1209            incoming,
1210            outgoing,
1211        };
1212        Ok(Ok(()))
1213    }
1214
1215    fn inner(&self) -> wasmtime::Result<Resource<latest::sockets::udp::UdpSocket>> {
1216        let r = match self {
1217            UdpSocket::Initial(r) => r,
1218            UdpSocket::Connecting(r, _) => r,
1219            UdpSocket::Connected { socket, .. } => socket,
1220            UdpSocket::Dummy => anyhow::bail!("invalid udp socket state"),
1221        };
1222        Ok(Resource::new_borrow(r.rep()))
1223    }
1224}
1225
1226impl wasi::sockets::udp::HostUdpSocket for WasiSocketsCtxView<'_> {
1227    async fn start_bind(
1228        &mut self,
1229        self_: Resource<UdpSocket>,
1230        network: Resource<Network>,
1231        local_address: IpSocketAddress,
1232    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1233        let socket = self.table.get(&self_)?.inner()?;
1234        convert_result(
1235            latest::sockets::udp::HostUdpSocket::start_bind(
1236                self,
1237                socket,
1238                network,
1239                local_address.into(),
1240            )
1241            .await,
1242        )
1243    }
1244
1245    fn finish_bind(
1246        &mut self,
1247        self_: Resource<UdpSocket>,
1248    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1249        let socket = self.table.get(&self_)?.inner()?;
1250        convert_result(latest::sockets::udp::HostUdpSocket::finish_bind(
1251            self, socket,
1252        ))
1253    }
1254
1255    fn start_connect(
1256        &mut self,
1257        self_: Resource<UdpSocket>,
1258        _network: Resource<Network>,
1259        remote_address: IpSocketAddress,
1260    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1261        let socket = self.table.get_mut(&self_)?;
1262        let (new_state, result) = match mem::replace(socket, UdpSocket::Dummy) {
1263            UdpSocket::Initial(socket) => (UdpSocket::Connecting(socket, remote_address), Ok(())),
1264            other => (other, Err(SocketErrorCode::ConcurrencyConflict)),
1265        };
1266        *socket = new_state;
1267        Ok(result)
1268    }
1269
1270    async fn finish_connect(
1271        &mut self,
1272        self_: Resource<UdpSocket>,
1273    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1274        UdpSocket::finish_connect(self, &self_, true).await
1275    }
1276
1277    async fn receive(
1278        &mut self,
1279        self_: Resource<UdpSocket>,
1280        max_results: u64,
1281    ) -> wasmtime::Result<Result<Vec<Datagram>, SocketErrorCode>> {
1282        // If the socket is in the `initial` state then complete the connect,
1283        // otherwise verify we're connected.
1284        if let Err(e) = UdpSocket::finish_connect(self, &self_, true).await? {
1285            return Ok(Err(e));
1286        }
1287
1288        // Use our connected state to acquire the `incoming-datagram-stream`
1289        // resource, then receive some datagrams.
1290        let incoming = match self.table.get(&self_)? {
1291            UdpSocket::Connected { incoming, .. } => Resource::new_borrow(incoming.rep()),
1292            _ => return Ok(Err(SocketErrorCode::ConcurrencyConflict)),
1293        };
1294        let result: Result<Vec<_>, _> = convert_result(
1295            latest::sockets::udp::HostIncomingDatagramStream::receive(self, incoming, max_results),
1296        )?;
1297        match result {
1298            Ok(datagrams) => Ok(Ok(datagrams
1299                .into_iter()
1300                .map(|datagram| datagram.into())
1301                .collect())),
1302            Err(e) => Ok(Err(e)),
1303        }
1304    }
1305
1306    async fn send(
1307        &mut self,
1308        self_: Resource<UdpSocket>,
1309        mut datagrams: Vec<Datagram>,
1310    ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1311        // If the socket is in the `initial` state then complete the connect,
1312        // otherwise verify we're connected.
1313        if let Err(e) = UdpSocket::finish_connect(self, &self_, true).await? {
1314            return Ok(Err(e));
1315        }
1316
1317        // Use our connected state to acquire the `outgoing-datagram-stream`
1318        // resource.
1319        let outgoing = match self.table.get(&self_)? {
1320            UdpSocket::Connected { outgoing, .. } => Resource::new_borrow(outgoing.rep()),
1321            _ => return Ok(Err(SocketErrorCode::ConcurrencyConflict)),
1322        };
1323
1324        // Acquire a sending permit for some datagrams, truncating our list to
1325        // that size if we have one.
1326        let outgoing2 = Resource::new_borrow(outgoing.rep());
1327        match convert_result(
1328            latest::sockets::udp::HostOutgoingDatagramStream::check_send(self, outgoing2),
1329        )? {
1330            Ok(n) => {
1331                if datagrams.len() as u64 > n {
1332                    datagrams.truncate(n as usize);
1333                }
1334            }
1335            Err(e) => return Ok(Err(e)),
1336        }
1337
1338        // Send off the datagrams.
1339        convert_result(
1340            latest::sockets::udp::HostOutgoingDatagramStream::send(
1341                self,
1342                outgoing,
1343                datagrams
1344                    .into_iter()
1345                    .map(|d| latest::sockets::udp::OutgoingDatagram {
1346                        data: d.data,
1347                        remote_address: Some(d.remote_address.into()),
1348                    })
1349                    .collect(),
1350            )
1351            .await,
1352        )
1353    }
1354
1355    fn local_address(
1356        &mut self,
1357        self_: Resource<UdpSocket>,
1358    ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1359        let socket = self.table.get(&self_)?.inner()?;
1360        convert_result(latest::sockets::udp::HostUdpSocket::local_address(
1361            self, socket,
1362        ))
1363    }
1364
1365    fn remote_address(
1366        &mut self,
1367        self_: Resource<UdpSocket>,
1368    ) -> wasmtime::Result<Result<IpSocketAddress, SocketErrorCode>> {
1369        let socket = self.table.get(&self_)?.inner()?;
1370        convert_result(latest::sockets::udp::HostUdpSocket::remote_address(
1371            self, socket,
1372        ))
1373    }
1374
1375    fn address_family(&mut self, self_: Resource<UdpSocket>) -> wasmtime::Result<IpAddressFamily> {
1376        let socket = self.table.get(&self_)?.inner()?;
1377        latest::sockets::udp::HostUdpSocket::address_family(self, socket).map(|e| e.into())
1378    }
1379
1380    fn ipv6_only(
1381        &mut self,
1382        _self_: Resource<UdpSocket>,
1383    ) -> wasmtime::Result<Result<bool, SocketErrorCode>> {
1384        anyhow::bail!("ipv6-only API no longer supported")
1385    }
1386
1387    fn set_ipv6_only(
1388        &mut self,
1389        _self_: Resource<UdpSocket>,
1390        _value: bool,
1391    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1392        anyhow::bail!("ipv6-only API no longer supported")
1393    }
1394
1395    fn unicast_hop_limit(
1396        &mut self,
1397        self_: Resource<UdpSocket>,
1398    ) -> wasmtime::Result<Result<u8, SocketErrorCode>> {
1399        let socket = self.table.get(&self_)?.inner()?;
1400        convert_result(latest::sockets::udp::HostUdpSocket::unicast_hop_limit(
1401            self, socket,
1402        ))
1403    }
1404
1405    fn set_unicast_hop_limit(
1406        &mut self,
1407        self_: Resource<UdpSocket>,
1408        value: u8,
1409    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1410        let socket = self.table.get(&self_)?.inner()?;
1411        convert_result(latest::sockets::udp::HostUdpSocket::set_unicast_hop_limit(
1412            self, socket, value,
1413        ))
1414    }
1415
1416    fn receive_buffer_size(
1417        &mut self,
1418        self_: Resource<UdpSocket>,
1419    ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1420        let socket = self.table.get(&self_)?.inner()?;
1421        convert_result(latest::sockets::udp::HostUdpSocket::receive_buffer_size(
1422            self, socket,
1423        ))
1424    }
1425
1426    fn set_receive_buffer_size(
1427        &mut self,
1428        self_: Resource<UdpSocket>,
1429        value: u64,
1430    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1431        let socket = self.table.get(&self_)?.inner()?;
1432        convert_result(
1433            latest::sockets::udp::HostUdpSocket::set_receive_buffer_size(self, socket, value),
1434        )
1435    }
1436
1437    fn send_buffer_size(
1438        &mut self,
1439        self_: Resource<UdpSocket>,
1440    ) -> wasmtime::Result<Result<u64, SocketErrorCode>> {
1441        let socket = self.table.get(&self_)?.inner()?;
1442        convert_result(latest::sockets::udp::HostUdpSocket::send_buffer_size(
1443            self, socket,
1444        ))
1445    }
1446
1447    fn set_send_buffer_size(
1448        &mut self,
1449        self_: Resource<UdpSocket>,
1450        value: u64,
1451    ) -> wasmtime::Result<Result<(), SocketErrorCode>> {
1452        let socket = self.table.get(&self_)?.inner()?;
1453        convert_result(latest::sockets::udp::HostUdpSocket::set_send_buffer_size(
1454            self, socket, value,
1455        ))
1456    }
1457
1458    fn subscribe(&mut self, self_: Resource<UdpSocket>) -> wasmtime::Result<Resource<DynPollable>> {
1459        let socket = self.table.get(&self_)?.inner()?;
1460        latest::sockets::udp::HostUdpSocket::subscribe(self, socket)
1461    }
1462
1463    fn drop(&mut self, rep: Resource<UdpSocket>) -> wasmtime::Result<()> {
1464        let me = self.table.delete(rep)?;
1465        let socket = match me {
1466            UdpSocket::Initial(s) => s,
1467            UdpSocket::Connecting(s, _) => s,
1468            UdpSocket::Connected {
1469                socket,
1470                incoming,
1471                outgoing,
1472            } => {
1473                latest::sockets::udp::HostIncomingDatagramStream::drop(self, incoming)?;
1474                latest::sockets::udp::HostOutgoingDatagramStream::drop(self, outgoing)?;
1475                socket
1476            }
1477            UdpSocket::Dummy => return Ok(()),
1478        };
1479        latest::sockets::udp::HostUdpSocket::drop(self, socket)
1480    }
1481}
1482
1483impl wasi::sockets::udp_create_socket::Host for WasiSocketsCtxView<'_> {
1484    fn create_udp_socket(
1485        &mut self,
1486        address_family: IpAddressFamily,
1487    ) -> wasmtime::Result<Result<Resource<UdpSocket>, SocketErrorCode>> {
1488        let result = convert_result(latest::sockets::udp_create_socket::Host::create_udp_socket(
1489            self,
1490            address_family.into(),
1491        ))?;
1492        let socket = match result {
1493            Ok(socket) => socket,
1494            Err(e) => return Ok(Err(e)),
1495        };
1496        let socket = self.table.push(UdpSocket::Initial(socket))?;
1497        Ok(Ok(socket))
1498    }
1499}
1500
1501impl wasi::sockets::instance_network::Host for WasiSocketsCtxView<'_> {
1502    fn instance_network(&mut self) -> wasmtime::Result<Resource<Network>> {
1503        latest::sockets::instance_network::Host::instance_network(self)
1504    }
1505}
1506
1507impl wasi::sockets::network::Host for WasiSocketsCtxView<'_> {}
1508
1509impl wasi::sockets::network::HostNetwork for WasiSocketsCtxView<'_> {
1510    fn drop(&mut self, rep: Resource<Network>) -> wasmtime::Result<()> {
1511        latest::sockets::network::HostNetwork::drop(self, rep)
1512    }
1513}
1514
1515impl wasi::sockets::ip_name_lookup::Host for WasiSocketsCtxView<'_> {
1516    fn resolve_addresses(
1517        &mut self,
1518        network: Resource<Network>,
1519        name: String,
1520        _address_family: Option<IpAddressFamily>,
1521        _include_unavailable: bool,
1522    ) -> wasmtime::Result<Result<Resource<ResolveAddressStream>, SocketErrorCode>> {
1523        convert_result(latest::sockets::ip_name_lookup::Host::resolve_addresses(
1524            self, network, name,
1525        ))
1526    }
1527}
1528
1529impl wasi::sockets::ip_name_lookup::HostResolveAddressStream for WasiSocketsCtxView<'_> {
1530    fn resolve_next_address(
1531        &mut self,
1532        self_: Resource<ResolveAddressStream>,
1533    ) -> wasmtime::Result<Result<Option<IpAddress>, SocketErrorCode>> {
1534        convert_result(
1535            latest::sockets::ip_name_lookup::HostResolveAddressStream::resolve_next_address(
1536                self, self_,
1537            )
1538            .map(|e| e.map(|e| e.into())),
1539        )
1540    }
1541
1542    fn subscribe(
1543        &mut self,
1544        self_: Resource<ResolveAddressStream>,
1545    ) -> wasmtime::Result<Resource<DynPollable>> {
1546        latest::sockets::ip_name_lookup::HostResolveAddressStream::subscribe(self, self_)
1547    }
1548
1549    fn drop(&mut self, rep: Resource<ResolveAddressStream>) -> wasmtime::Result<()> {
1550        latest::sockets::ip_name_lookup::HostResolveAddressStream::drop(self, rep)
1551    }
1552}
1553
1554pub fn convert_result<T, T2, E, E2>(
1555    result: Result<T, TrappableError<E>>,
1556) -> wasmtime::Result<Result<T2, E2>>
1557where
1558    T2: From<T>,
1559    E: std::error::Error + Send + Sync + 'static,
1560    E2: From<E>,
1561{
1562    match result {
1563        Ok(e) => Ok(Ok(e.into())),
1564        Err(e) => Ok(Err(e.downcast()?.into())),
1565    }
1566}
1567
1568fn convert_stream_result<T, T2>(
1569    table: &mut ResourceTable,
1570    result: Result<T, wasmtime_wasi::p2::StreamError>,
1571) -> wasmtime::Result<Result<T2, StreamError>>
1572where
1573    T2: From<T>,
1574{
1575    match result {
1576        Ok(e) => Ok(Ok(e.into())),
1577        Err(wasmtime_wasi::p2::StreamError::Closed) => Ok(Err(StreamError::Closed)),
1578        Err(wasmtime_wasi::p2::StreamError::LastOperationFailed(e)) => {
1579            let e = table.push(e)?;
1580            Ok(Err(StreamError::LastOperationFailed(e)))
1581        }
1582        Err(wasmtime_wasi::p2::StreamError::Trap(e)) => Err(e),
1583    }
1584}
1585
1586macro_rules! convert {
1587    () => {};
1588    ($kind:ident $from:path [<=>] $to:path { $($body:tt)* } $($rest:tt)*) => {
1589        convert!($kind $from => $to { $($body)* });
1590        convert!($kind $to => $from { $($body)* });
1591
1592        convert!($($rest)*);
1593    };
1594    (struct $from:ty => $to:path { $($field:ident,)* } $($rest:tt)*) => {
1595        impl From<$from> for $to {
1596            fn from(e: $from) -> $to {
1597                $to {
1598                    $( $field: e.$field.into(), )*
1599                }
1600            }
1601        }
1602
1603        convert!($($rest)*);
1604    };
1605    (enum $from:path => $to:path { $($variant:ident $(($e:ident))?,)* } $($rest:tt)*) => {
1606        impl From<$from> for $to {
1607            fn from(e: $from) -> $to {
1608                use $from as A;
1609                use $to as B;
1610                match e {
1611                    $(
1612                        A::$variant $(($e))? => B::$variant $(($e.into()))?,
1613                    )*
1614                }
1615            }
1616        }
1617
1618        convert!($($rest)*);
1619    };
1620    (flags $from:path => $to:path { $($flag:ident,)* } $($rest:tt)*) => {
1621        impl From<$from> for $to {
1622            fn from(e: $from) -> $to {
1623                use $from as A;
1624                use $to as B;
1625                let mut out = B::empty();
1626                $(
1627                    if e.contains(A::$flag) {
1628                        out |= B::$flag;
1629                    }
1630                )*
1631                out
1632            }
1633        }
1634
1635        convert!($($rest)*);
1636    };
1637}
1638
1639pub(crate) use convert;
1640
1641convert! {
1642    struct latest::clocks::wall_clock::Datetime [<=>] Datetime {
1643        seconds,
1644        nanoseconds,
1645    }
1646
1647    enum latest::filesystem::types::ErrorCode => FsErrorCode {
1648        Access,
1649        WouldBlock,
1650        Already,
1651        BadDescriptor,
1652        Busy,
1653        Deadlock,
1654        Quota,
1655        Exist,
1656        FileTooLarge,
1657        IllegalByteSequence,
1658        InProgress,
1659        Interrupted,
1660        Invalid,
1661        Io,
1662        IsDirectory,
1663        Loop,
1664        TooManyLinks,
1665        MessageSize,
1666        NameTooLong,
1667        NoDevice,
1668        NoEntry,
1669        NoLock,
1670        InsufficientMemory,
1671        InsufficientSpace,
1672        NotDirectory,
1673        NotEmpty,
1674        NotRecoverable,
1675        Unsupported,
1676        NoTty,
1677        NoSuchDevice,
1678        Overflow,
1679        NotPermitted,
1680        Pipe,
1681        ReadOnly,
1682        InvalidSeek,
1683        TextFileBusy,
1684        CrossDevice,
1685    }
1686
1687    enum Advice => latest::filesystem::types::Advice {
1688        Normal,
1689        Sequential,
1690        Random,
1691        WillNeed,
1692        DontNeed,
1693        NoReuse,
1694    }
1695
1696    flags DescriptorFlags [<=>] latest::filesystem::types::DescriptorFlags {
1697        READ,
1698        WRITE,
1699        FILE_INTEGRITY_SYNC,
1700        DATA_INTEGRITY_SYNC,
1701        REQUESTED_WRITE_SYNC,
1702        MUTATE_DIRECTORY,
1703    }
1704
1705    enum DescriptorType [<=>] latest::filesystem::types::DescriptorType {
1706        Unknown,
1707        BlockDevice,
1708        CharacterDevice,
1709        Directory,
1710        Fifo,
1711        SymbolicLink,
1712        RegularFile,
1713        Socket,
1714    }
1715
1716    enum NewTimestamp => latest::filesystem::types::NewTimestamp {
1717        NoChange,
1718        Now,
1719        Timestamp(e),
1720    }
1721
1722    flags PathFlags => latest::filesystem::types::PathFlags {
1723        SYMLINK_FOLLOW,
1724    }
1725
1726    flags OpenFlags => latest::filesystem::types::OpenFlags {
1727        CREATE,
1728        DIRECTORY,
1729        EXCLUSIVE,
1730        TRUNCATE,
1731    }
1732
1733    struct latest::filesystem::types::MetadataHashValue => MetadataHashValue {
1734        lower,
1735        upper,
1736    }
1737
1738    struct latest::filesystem::types::DirectoryEntry => DirectoryEntry {
1739        type_,
1740        name,
1741    }
1742
1743    enum latest::sockets::network::ErrorCode => SocketErrorCode {
1744        Unknown,
1745        AccessDenied,
1746        NotSupported,
1747        InvalidArgument,
1748        OutOfMemory,
1749        Timeout,
1750        ConcurrencyConflict,
1751        NotInProgress,
1752        WouldBlock,
1753        InvalidState,
1754        NewSocketLimit,
1755        AddressNotBindable,
1756        AddressInUse,
1757        RemoteUnreachable,
1758        ConnectionRefused,
1759        ConnectionReset,
1760        ConnectionAborted,
1761        DatagramTooLarge,
1762        NameUnresolvable,
1763        TemporaryResolverFailure,
1764        PermanentResolverFailure,
1765    }
1766
1767    enum latest::sockets::network::IpAddress [<=>] IpAddress {
1768        Ipv4(e),
1769        Ipv6(e),
1770    }
1771
1772    enum latest::sockets::network::IpSocketAddress [<=>] IpSocketAddress {
1773        Ipv4(e),
1774        Ipv6(e),
1775    }
1776
1777    struct latest::sockets::network::Ipv4SocketAddress [<=>] Ipv4SocketAddress {
1778        port,
1779        address,
1780    }
1781
1782    struct latest::sockets::network::Ipv6SocketAddress [<=>] Ipv6SocketAddress {
1783        port,
1784        flow_info,
1785        scope_id,
1786        address,
1787    }
1788
1789    enum latest::sockets::network::IpAddressFamily [<=>] IpAddressFamily {
1790        Ipv4,
1791        Ipv6,
1792    }
1793
1794    enum ShutdownType => latest::sockets::tcp::ShutdownType {
1795        Receive,
1796        Send,
1797        Both,
1798    }
1799
1800    struct latest::sockets::udp::IncomingDatagram => Datagram {
1801        data,
1802        remote_address,
1803    }
1804}
1805
1806impl From<latest::filesystem::types::DescriptorStat> for DescriptorStat {
1807    fn from(e: latest::filesystem::types::DescriptorStat) -> DescriptorStat {
1808        DescriptorStat {
1809            type_: e.type_.into(),
1810            link_count: e.link_count,
1811            size: e.size,
1812            data_access_timestamp: e.data_access_timestamp.map(|e| e.into()),
1813            data_modification_timestamp: e.data_modification_timestamp.map(|e| e.into()),
1814            status_change_timestamp: e.status_change_timestamp.map(|e| e.into()),
1815        }
1816    }
1817}