spin_factor_wasi/
wasi_2023_10_18.rs

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