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