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