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