From 18eb91d0be9cda48273e888872c75c6aee4e0aed Mon Sep 17 00:00:00 2001 From: Xinzhao Xu Date: Tue, 14 May 2024 11:01:54 +0800 Subject: [PATCH] Add integration tests --- .github/workflows/ci.yml | 9 +- tests/main.rs | 22 + tests/program/Cargo.toml | 26 + tests/program/src/bindings.rs | 9594 +++++++++++++++++ tests/program/src/lib.rs | 83 + tests/program/wit/deps/cli/command.wit | 7 + tests/program/wit/deps/cli/environment.wit | 18 + tests/program/wit/deps/cli/exit.wit | 4 + tests/program/wit/deps/cli/imports.wit | 20 + tests/program/wit/deps/cli/run.wit | 4 + tests/program/wit/deps/cli/stdio.wit | 17 + tests/program/wit/deps/cli/terminal.wit | 49 + .../wit/deps/clocks/monotonic-clock.wit | 45 + tests/program/wit/deps/clocks/wall-clock.wit | 42 + tests/program/wit/deps/clocks/world.wit | 6 + .../program/wit/deps/filesystem/preopens.wit | 8 + tests/program/wit/deps/filesystem/types.wit | 634 ++ tests/program/wit/deps/filesystem/world.wit | 6 + tests/program/wit/deps/io/error.wit | 34 + tests/program/wit/deps/io/poll.wit | 41 + tests/program/wit/deps/io/streams.wit | 262 + tests/program/wit/deps/io/world.wit | 6 + .../program/wit/deps/random/insecure-seed.wit | 25 + tests/program/wit/deps/random/insecure.wit | 22 + tests/program/wit/deps/random/random.wit | 26 + tests/program/wit/deps/random/world.wit | 7 + .../wit/deps/sockets/instance-network.wit | 9 + .../wit/deps/sockets/ip-name-lookup.wit | 51 + tests/program/wit/deps/sockets/network.wit | 145 + .../wit/deps/sockets/tcp-create-socket.wit | 27 + tests/program/wit/deps/sockets/tcp.wit | 353 + .../wit/deps/sockets/udp-create-socket.wit | 27 + tests/program/wit/deps/sockets/udp.wit | 266 + tests/program/wit/deps/sockets/world.wit | 11 + tests/program/wit/world.wit | 5 + 35 files changed, 11910 insertions(+), 1 deletion(-) create mode 100644 tests/main.rs create mode 100644 tests/program/Cargo.toml create mode 100644 tests/program/src/bindings.rs create mode 100644 tests/program/src/lib.rs create mode 100644 tests/program/wit/deps/cli/command.wit create mode 100644 tests/program/wit/deps/cli/environment.wit create mode 100644 tests/program/wit/deps/cli/exit.wit create mode 100644 tests/program/wit/deps/cli/imports.wit create mode 100644 tests/program/wit/deps/cli/run.wit create mode 100644 tests/program/wit/deps/cli/stdio.wit create mode 100644 tests/program/wit/deps/cli/terminal.wit create mode 100644 tests/program/wit/deps/clocks/monotonic-clock.wit create mode 100644 tests/program/wit/deps/clocks/wall-clock.wit create mode 100644 tests/program/wit/deps/clocks/world.wit create mode 100644 tests/program/wit/deps/filesystem/preopens.wit create mode 100644 tests/program/wit/deps/filesystem/types.wit create mode 100644 tests/program/wit/deps/filesystem/world.wit create mode 100644 tests/program/wit/deps/io/error.wit create mode 100644 tests/program/wit/deps/io/poll.wit create mode 100644 tests/program/wit/deps/io/streams.wit create mode 100644 tests/program/wit/deps/io/world.wit create mode 100644 tests/program/wit/deps/random/insecure-seed.wit create mode 100644 tests/program/wit/deps/random/insecure.wit create mode 100644 tests/program/wit/deps/random/random.wit create mode 100644 tests/program/wit/deps/random/world.wit create mode 100644 tests/program/wit/deps/sockets/instance-network.wit create mode 100644 tests/program/wit/deps/sockets/ip-name-lookup.wit create mode 100644 tests/program/wit/deps/sockets/network.wit create mode 100644 tests/program/wit/deps/sockets/tcp-create-socket.wit create mode 100644 tests/program/wit/deps/sockets/tcp.wit create mode 100644 tests/program/wit/deps/sockets/udp-create-socket.wit create mode 100644 tests/program/wit/deps/sockets/udp.wit create mode 100644 tests/program/wit/deps/sockets/world.wit create mode 100644 tests/program/wit/world.wit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ed6256..62e14c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,5 +20,12 @@ jobs: run: cargo fmt --all -- --check - name: cargo clippy run: cargo clippy --all-targets --all-features -- -D warnings + - name: Install wasmtime + uses: bytecodealliance/actions/wasmtime/setup@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + version: "v20.0.0" - name: cargo test - run: cargo test + run: | + cargo install cargo-component@0.11.0 + cargo test diff --git a/tests/main.rs b/tests/main.rs new file mode 100644 index 0000000..5c353c3 --- /dev/null +++ b/tests/main.rs @@ -0,0 +1,22 @@ +use anyhow::Result; +use std::process::Command; + +#[test] +fn main() -> Result<()> { + let status = Command::new("cargo") + .current_dir("tests/program") + .arg("component") + .arg("build") + .arg("--quiet") + .status()?; + assert!(status.success()); + + let status = Command::new("wasmtime") + .arg("-S") + .arg("http") + .arg("tests/program/target/wasm32-wasi/debug/wasi_http_client_test_program.wasm") + .status()?; + assert!(status.success()); + + Ok(()) +} diff --git a/tests/program/Cargo.toml b/tests/program/Cargo.toml new file mode 100644 index 0000000..a61b73d --- /dev/null +++ b/tests/program/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "wasi-http-client-test-program" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "component:wasi-http-client-test-program" + +[package.metadata.component.dependencies] + +[package.metadata.component.target.dependencies] +"wasi:cli" = { path = "wit/deps/cli" } +"wasi:io" = { path = "wit/deps/io" } +"wasi:clocks" = { path = "wit/deps/clocks" } +"wasi:filesystem" = { path = "wit/deps/filesystem" } +"wasi:sockets" = { path = "wit/deps/sockets" } +"wasi:random" = { path = "wit/deps/random" } + +[dependencies] +wasi-http-client = { path = "../../../wasi-http-client" } + +wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } diff --git a/tests/program/src/bindings.rs b/tests/program/src/bindings.rs new file mode 100644 index 0000000..3962cee --- /dev/null +++ b/tests/program/src/bindings.rs @@ -0,0 +1,9594 @@ +// Generated by `wit-bindgen` 0.24.0. DO NOT EDIT! +// Options used: +#[allow(dead_code)] +pub mod wasi { + #[allow(dead_code)] + pub mod cli { + #[allow(dead_code, clippy::all)] + pub mod environment { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + #[allow(unused_unsafe, clippy::all)] + /// Get the POSIX-style environment variables. + /// + /// Each environment variable is provided as a pair of string variable names + /// and string value. + /// + /// Morally, these are a value import, but until value imports are available + /// in the component model, this import function should return the same + /// values each time it is called. + pub fn get_environment() -> _rt::Vec<(_rt::String, _rt::String)> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/environment@0.2.0")] + extern "C" { + #[link_name = "get-environment"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let base9 = l1; + let len9 = l2; + let mut result9 = _rt::Vec::with_capacity(len9); + for i in 0..len9 { + let base = base9.add(i * 16); + let e9 = { + let l3 = *base.add(0).cast::<*mut u8>(); + let l4 = *base.add(4).cast::(); + let len5 = l4; + let bytes5 = _rt::Vec::from_raw_parts(l3.cast(), len5, len5); + let l6 = *base.add(8).cast::<*mut u8>(); + let l7 = *base.add(12).cast::(); + let len8 = l7; + let bytes8 = _rt::Vec::from_raw_parts(l6.cast(), len8, len8); + + (_rt::string_lift(bytes5), _rt::string_lift(bytes8)) + }; + result9.push(e9); + } + _rt::cabi_dealloc(base9, len9 * 16, 4); + result9 + } + } + #[allow(unused_unsafe, clippy::all)] + /// Get the POSIX-style arguments to the program. + pub fn get_arguments() -> _rt::Vec<_rt::String> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/environment@0.2.0")] + extern "C" { + #[link_name = "get-arguments"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let base6 = l1; + let len6 = l2; + let mut result6 = _rt::Vec::with_capacity(len6); + for i in 0..len6 { + let base = base6.add(i * 8); + let e6 = { + let l3 = *base.add(0).cast::<*mut u8>(); + let l4 = *base.add(4).cast::(); + let len5 = l4; + let bytes5 = _rt::Vec::from_raw_parts(l3.cast(), len5, len5); + + _rt::string_lift(bytes5) + }; + result6.push(e6); + } + _rt::cabi_dealloc(base6, len6 * 8, 4); + result6 + } + } + #[allow(unused_unsafe, clippy::all)] + /// Return a path that programs should use as their initial current working + /// directory, interpreting `.` as shorthand for this. + pub fn initial_cwd() -> Option<_rt::String> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/environment@0.2.0")] + extern "C" { + #[link_name = "initial-cwd"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + let bytes4 = _rt::Vec::from_raw_parts(l2.cast(), len4, len4); + + _rt::string_lift(bytes4) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod exit { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + #[allow(unused_unsafe, clippy::all)] + /// Exit the current instance and any linked instances. + pub fn exit(status: Result<(), ()>) { + unsafe { + let result0 = match status { + Ok(_) => 0i32, + Err(_) => 1i32, + }; + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/exit@0.2.0")] + extern "C" { + #[link_name = "exit"] + fn wit_import(_: i32); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) { + unreachable!() + } + wit_import(result0); + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod stdin { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + pub type InputStream = super::super::super::wasi::io::streams::InputStream; + #[allow(unused_unsafe, clippy::all)] + pub fn get_stdin() -> InputStream { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/stdin@0.2.0")] + extern "C" { + #[link_name = "get-stdin"] + fn wit_import() -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i32 { + unreachable!() + } + let ret = wit_import(); + super::super::super::wasi::io::streams::InputStream::from_handle(ret as u32) + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod stdout { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + pub type OutputStream = super::super::super::wasi::io::streams::OutputStream; + #[allow(unused_unsafe, clippy::all)] + pub fn get_stdout() -> OutputStream { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/stdout@0.2.0")] + extern "C" { + #[link_name = "get-stdout"] + fn wit_import() -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i32 { + unreachable!() + } + let ret = wit_import(); + super::super::super::wasi::io::streams::OutputStream::from_handle(ret as u32) + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod stderr { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + pub type OutputStream = super::super::super::wasi::io::streams::OutputStream; + #[allow(unused_unsafe, clippy::all)] + pub fn get_stderr() -> OutputStream { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/stderr@0.2.0")] + extern "C" { + #[link_name = "get-stderr"] + fn wit_import() -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i32 { + unreachable!() + } + let ret = wit_import(); + super::super::super::wasi::io::streams::OutputStream::from_handle(ret as u32) + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod terminal_input { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + /// The input side of a terminal. + + #[derive(Debug)] + #[repr(transparent)] + pub struct TerminalInput { + handle: _rt::Resource, + } + + impl TerminalInput { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for TerminalInput { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:cli/terminal-input@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]terminal-input"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod terminal_output { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + /// The output side of a terminal. + + #[derive(Debug)] + #[repr(transparent)] + pub struct TerminalOutput { + handle: _rt::Resource, + } + + impl TerminalOutput { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for TerminalOutput { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:cli/terminal-output@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]terminal-output"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod terminal_stdin { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type TerminalInput = super::super::super::wasi::cli::terminal_input::TerminalInput; + #[allow(unused_unsafe, clippy::all)] + /// If stdin is connected to a terminal, return a `terminal-input` handle + /// allowing further interaction with it. + pub fn get_terminal_stdin() -> Option { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/terminal-stdin@0.2.0")] + extern "C" { + #[link_name = "get-terminal-stdin"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::cli::terminal_input::TerminalInput::from_handle(l2 as u32) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod terminal_stdout { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type TerminalOutput = + super::super::super::wasi::cli::terminal_output::TerminalOutput; + #[allow(unused_unsafe, clippy::all)] + /// If stdout is connected to a terminal, return a `terminal-output` handle + /// allowing further interaction with it. + pub fn get_terminal_stdout() -> Option { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/terminal-stdout@0.2.0")] + extern "C" { + #[link_name = "get-terminal-stdout"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::cli::terminal_output::TerminalOutput::from_handle(l2 as u32) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod terminal_stderr { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type TerminalOutput = + super::super::super::wasi::cli::terminal_output::TerminalOutput; + #[allow(unused_unsafe, clippy::all)] + /// If stderr is connected to a terminal, return a `terminal-output` handle + /// allowing further interaction with it. + pub fn get_terminal_stderr() -> Option { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:cli/terminal-stderr@0.2.0")] + extern "C" { + #[link_name = "get-terminal-stderr"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::cli::terminal_output::TerminalOutput::from_handle(l2 as u32) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + } + #[allow(dead_code)] + pub mod clocks { + #[allow(dead_code, clippy::all)] + pub mod monotonic_clock { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + /// An instant in time, in nanoseconds. An instant is relative to an + /// unspecified initial value, and can only be compared to instances from + /// the same monotonic-clock. + pub type Instant = u64; + /// A duration of time, in nanoseconds. + pub type Duration = u64; + #[allow(unused_unsafe, clippy::all)] + /// Read the current value of the clock. + /// + /// The clock is monotonic, therefore calling this function repeatedly will + /// produce a sequence of non-decreasing values. + pub fn now() -> Instant { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:clocks/monotonic-clock@0.2.0")] + extern "C" { + #[link_name = "now"] + fn wit_import() -> i64; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i64 { + unreachable!() + } + let ret = wit_import(); + ret as u64 + } + } + #[allow(unused_unsafe, clippy::all)] + /// Query the resolution of the clock. Returns the duration of time + /// corresponding to a clock tick. + pub fn resolution() -> Duration { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:clocks/monotonic-clock@0.2.0")] + extern "C" { + #[link_name = "resolution"] + fn wit_import() -> i64; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i64 { + unreachable!() + } + let ret = wit_import(); + ret as u64 + } + } + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the specified instant + /// occured. + pub fn subscribe_instant(when: Instant) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:clocks/monotonic-clock@0.2.0")] + extern "C" { + #[link_name = "subscribe-instant"] + fn wit_import(_: i64) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i64) -> i32 { + unreachable!() + } + let ret = wit_import(_rt::as_i64(when)); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the given duration has + /// elapsed, starting at the time at which this function was called. + /// occured. + pub fn subscribe_duration(when: Duration) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:clocks/monotonic-clock@0.2.0")] + extern "C" { + #[link_name = "subscribe-duration"] + fn wit_import(_: i64) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i64) -> i32 { + unreachable!() + } + let ret = wit_import(_rt::as_i64(when)); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod wall_clock { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + /// A time and date in seconds plus nanoseconds. + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Datetime { + pub seconds: u64, + pub nanoseconds: u32, + } + impl ::core::fmt::Debug for Datetime { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Datetime") + .field("seconds", &self.seconds) + .field("nanoseconds", &self.nanoseconds) + .finish() + } + } + #[allow(unused_unsafe, clippy::all)] + /// Read the current value of the clock. + /// + /// This clock is not monotonic, therefore calling this function repeatedly + /// will not necessarily produce a sequence of non-decreasing values. + /// + /// The returned timestamps represent the number of seconds since + /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], + /// also known as [Unix Time]. + /// + /// The nanoseconds field of the output is always less than 1000000000. + /// + /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 + /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time + pub fn now() -> Datetime { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:clocks/wall-clock@0.2.0")] + extern "C" { + #[link_name = "now"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = *ptr0.add(0).cast::(); + let l2 = *ptr0.add(8).cast::(); + Datetime { + seconds: l1 as u64, + nanoseconds: l2 as u32, + } + } + } + #[allow(unused_unsafe, clippy::all)] + /// Query the resolution of the clock. + /// + /// The nanoseconds field of the output is always less than 1000000000. + pub fn resolution() -> Datetime { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:clocks/wall-clock@0.2.0")] + extern "C" { + #[link_name = "resolution"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = *ptr0.add(0).cast::(); + let l2 = *ptr0.add(8).cast::(); + Datetime { + seconds: l1 as u64, + nanoseconds: l2 as u32, + } + } + } + } + } + #[allow(dead_code)] + pub mod filesystem { + #[allow(dead_code, clippy::all)] + pub mod types { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type InputStream = super::super::super::wasi::io::streams::InputStream; + pub type OutputStream = super::super::super::wasi::io::streams::OutputStream; + pub type Error = super::super::super::wasi::io::streams::Error; + pub type Datetime = super::super::super::wasi::clocks::wall_clock::Datetime; + /// File size or length of a region within a file. + pub type Filesize = u64; + /// The type of a filesystem object referenced by a descriptor. + /// + /// Note: This was called `filetype` in earlier versions of WASI. + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum DescriptorType { + /// The type of the descriptor or file is unknown or is different from + /// any of the other types specified. + Unknown, + /// The descriptor refers to a block device inode. + BlockDevice, + /// The descriptor refers to a character device inode. + CharacterDevice, + /// The descriptor refers to a directory inode. + Directory, + /// The descriptor refers to a named pipe. + Fifo, + /// The file refers to a symbolic link inode. + SymbolicLink, + /// The descriptor refers to a regular file inode. + RegularFile, + /// The descriptor refers to a socket. + Socket, + } + impl ::core::fmt::Debug for DescriptorType { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + DescriptorType::Unknown => { + f.debug_tuple("DescriptorType::Unknown").finish() + } + DescriptorType::BlockDevice => { + f.debug_tuple("DescriptorType::BlockDevice").finish() + } + DescriptorType::CharacterDevice => { + f.debug_tuple("DescriptorType::CharacterDevice").finish() + } + DescriptorType::Directory => { + f.debug_tuple("DescriptorType::Directory").finish() + } + DescriptorType::Fifo => f.debug_tuple("DescriptorType::Fifo").finish(), + DescriptorType::SymbolicLink => { + f.debug_tuple("DescriptorType::SymbolicLink").finish() + } + DescriptorType::RegularFile => { + f.debug_tuple("DescriptorType::RegularFile").finish() + } + DescriptorType::Socket => f.debug_tuple("DescriptorType::Socket").finish(), + } + } + } + + impl DescriptorType { + pub(crate) unsafe fn _lift(val: u8) -> DescriptorType { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => DescriptorType::Unknown, + 1 => DescriptorType::BlockDevice, + 2 => DescriptorType::CharacterDevice, + 3 => DescriptorType::Directory, + 4 => DescriptorType::Fifo, + 5 => DescriptorType::SymbolicLink, + 6 => DescriptorType::RegularFile, + 7 => DescriptorType::Socket, + + _ => panic!("invalid enum discriminant"), + } + } + } + + wit_bindgen_rt::bitflags::bitflags! { + /// Descriptor flags. + /// + /// Note: This was called `fdflags` in earlier versions of WASI. + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] + pub struct DescriptorFlags: u8 { + /// Read mode: Data can be read. + const READ = 1 << 0; + /// Write mode: Data can be written to. + const WRITE = 1 << 1; + /// Request that writes be performed according to synchronized I/O file + /// integrity completion. The data stored in the file and the file's + /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + const FILE_INTEGRITY_SYNC = 1 << 2; + /// Request that writes be performed according to synchronized I/O data + /// integrity completion. Only the data stored in the file is + /// synchronized. This is similar to `O_DSYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + const DATA_INTEGRITY_SYNC = 1 << 3; + /// Requests that reads be performed at the same level of integrety + /// requested for writes. This is similar to `O_RSYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + const REQUESTED_WRITE_SYNC = 1 << 4; + /// Mutating directories mode: Directory contents may be mutated. + /// + /// When this flag is unset on a descriptor, operations using the + /// descriptor which would create, rename, delete, modify the data or + /// metadata of filesystem objects, or obtain another handle which + /// would permit any of those, shall fail with `error-code::read-only` if + /// they would otherwise succeed. + /// + /// This may only be set on directories. + const MUTATE_DIRECTORY = 1 << 5; + } + } + wit_bindgen_rt::bitflags::bitflags! { + /// Flags determining the method of how paths are resolved. + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] + pub struct PathFlags: u8 { + /// As long as the resolved path corresponds to a symbolic link, it is + /// expanded. + const SYMLINK_FOLLOW = 1 << 0; + } + } + wit_bindgen_rt::bitflags::bitflags! { + /// Open flags used by `open-at`. + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] + pub struct OpenFlags: u8 { + /// Create file if it does not exist, similar to `O_CREAT` in POSIX. + const CREATE = 1 << 0; + /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. + const DIRECTORY = 1 << 1; + /// Fail if file already exists, similar to `O_EXCL` in POSIX. + const EXCLUSIVE = 1 << 2; + /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. + const TRUNCATE = 1 << 3; + } + } + /// Number of hard links to an inode. + pub type LinkCount = u64; + /// File attributes. + /// + /// Note: This was called `filestat` in earlier versions of WASI. + #[repr(C)] + #[derive(Clone, Copy)] + pub struct DescriptorStat { + /// File type. + pub type_: DescriptorType, + /// Number of hard links to the file. + pub link_count: LinkCount, + /// For regular files, the file size in bytes. For symbolic links, the + /// length in bytes of the pathname contained in the symbolic link. + pub size: Filesize, + /// Last data access timestamp. + /// + /// If the `option` is none, the platform doesn't maintain an access + /// timestamp for this file. + pub data_access_timestamp: Option, + /// Last data modification timestamp. + /// + /// If the `option` is none, the platform doesn't maintain a + /// modification timestamp for this file. + pub data_modification_timestamp: Option, + /// Last file status-change timestamp. + /// + /// If the `option` is none, the platform doesn't maintain a + /// status-change timestamp for this file. + pub status_change_timestamp: Option, + } + impl ::core::fmt::Debug for DescriptorStat { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DescriptorStat") + .field("type", &self.type_) + .field("link-count", &self.link_count) + .field("size", &self.size) + .field("data-access-timestamp", &self.data_access_timestamp) + .field( + "data-modification-timestamp", + &self.data_modification_timestamp, + ) + .field("status-change-timestamp", &self.status_change_timestamp) + .finish() + } + } + /// When setting a timestamp, this gives the value to set it to. + #[derive(Clone, Copy)] + pub enum NewTimestamp { + /// Leave the timestamp set to its previous value. + NoChange, + /// Set the timestamp to the current time of the system clock associated + /// with the filesystem. + Now, + /// Set the timestamp to the given value. + Timestamp(Datetime), + } + impl ::core::fmt::Debug for NewTimestamp { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + NewTimestamp::NoChange => f.debug_tuple("NewTimestamp::NoChange").finish(), + NewTimestamp::Now => f.debug_tuple("NewTimestamp::Now").finish(), + NewTimestamp::Timestamp(e) => { + f.debug_tuple("NewTimestamp::Timestamp").field(e).finish() + } + } + } + } + /// A directory entry. + #[derive(Clone)] + pub struct DirectoryEntry { + /// The type of the file referred to by this directory entry. + pub type_: DescriptorType, + /// The name of the object. + pub name: _rt::String, + } + impl ::core::fmt::Debug for DirectoryEntry { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DirectoryEntry") + .field("type", &self.type_) + .field("name", &self.name) + .finish() + } + } + /// Error codes returned by functions, similar to `errno` in POSIX. + /// Not all of these error codes are returned by the functions provided by this + /// API; some are used in higher-level library layers, and others are provided + /// merely for alignment with POSIX. + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum ErrorCode { + /// Permission denied, similar to `EACCES` in POSIX. + Access, + /// Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX. + WouldBlock, + /// Connection already in progress, similar to `EALREADY` in POSIX. + Already, + /// Bad descriptor, similar to `EBADF` in POSIX. + BadDescriptor, + /// Device or resource busy, similar to `EBUSY` in POSIX. + Busy, + /// Resource deadlock would occur, similar to `EDEADLK` in POSIX. + Deadlock, + /// Storage quota exceeded, similar to `EDQUOT` in POSIX. + Quota, + /// File exists, similar to `EEXIST` in POSIX. + Exist, + /// File too large, similar to `EFBIG` in POSIX. + FileTooLarge, + /// Illegal byte sequence, similar to `EILSEQ` in POSIX. + IllegalByteSequence, + /// Operation in progress, similar to `EINPROGRESS` in POSIX. + InProgress, + /// Interrupted function, similar to `EINTR` in POSIX. + Interrupted, + /// Invalid argument, similar to `EINVAL` in POSIX. + Invalid, + /// I/O error, similar to `EIO` in POSIX. + Io, + /// Is a directory, similar to `EISDIR` in POSIX. + IsDirectory, + /// Too many levels of symbolic links, similar to `ELOOP` in POSIX. + Loop, + /// Too many links, similar to `EMLINK` in POSIX. + TooManyLinks, + /// Message too large, similar to `EMSGSIZE` in POSIX. + MessageSize, + /// Filename too long, similar to `ENAMETOOLONG` in POSIX. + NameTooLong, + /// No such device, similar to `ENODEV` in POSIX. + NoDevice, + /// No such file or directory, similar to `ENOENT` in POSIX. + NoEntry, + /// No locks available, similar to `ENOLCK` in POSIX. + NoLock, + /// Not enough space, similar to `ENOMEM` in POSIX. + InsufficientMemory, + /// No space left on device, similar to `ENOSPC` in POSIX. + InsufficientSpace, + /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX. + NotDirectory, + /// Directory not empty, similar to `ENOTEMPTY` in POSIX. + NotEmpty, + /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX. + NotRecoverable, + /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX. + Unsupported, + /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX. + NoTty, + /// No such device or address, similar to `ENXIO` in POSIX. + NoSuchDevice, + /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX. + Overflow, + /// Operation not permitted, similar to `EPERM` in POSIX. + NotPermitted, + /// Broken pipe, similar to `EPIPE` in POSIX. + Pipe, + /// Read-only file system, similar to `EROFS` in POSIX. + ReadOnly, + /// Invalid seek, similar to `ESPIPE` in POSIX. + InvalidSeek, + /// Text file busy, similar to `ETXTBSY` in POSIX. + TextFileBusy, + /// Cross-device link, similar to `EXDEV` in POSIX. + CrossDevice, + } + impl ErrorCode { + pub fn name(&self) -> &'static str { + match self { + ErrorCode::Access => "access", + ErrorCode::WouldBlock => "would-block", + ErrorCode::Already => "already", + ErrorCode::BadDescriptor => "bad-descriptor", + ErrorCode::Busy => "busy", + ErrorCode::Deadlock => "deadlock", + ErrorCode::Quota => "quota", + ErrorCode::Exist => "exist", + ErrorCode::FileTooLarge => "file-too-large", + ErrorCode::IllegalByteSequence => "illegal-byte-sequence", + ErrorCode::InProgress => "in-progress", + ErrorCode::Interrupted => "interrupted", + ErrorCode::Invalid => "invalid", + ErrorCode::Io => "io", + ErrorCode::IsDirectory => "is-directory", + ErrorCode::Loop => "loop", + ErrorCode::TooManyLinks => "too-many-links", + ErrorCode::MessageSize => "message-size", + ErrorCode::NameTooLong => "name-too-long", + ErrorCode::NoDevice => "no-device", + ErrorCode::NoEntry => "no-entry", + ErrorCode::NoLock => "no-lock", + ErrorCode::InsufficientMemory => "insufficient-memory", + ErrorCode::InsufficientSpace => "insufficient-space", + ErrorCode::NotDirectory => "not-directory", + ErrorCode::NotEmpty => "not-empty", + ErrorCode::NotRecoverable => "not-recoverable", + ErrorCode::Unsupported => "unsupported", + ErrorCode::NoTty => "no-tty", + ErrorCode::NoSuchDevice => "no-such-device", + ErrorCode::Overflow => "overflow", + ErrorCode::NotPermitted => "not-permitted", + ErrorCode::Pipe => "pipe", + ErrorCode::ReadOnly => "read-only", + ErrorCode::InvalidSeek => "invalid-seek", + ErrorCode::TextFileBusy => "text-file-busy", + ErrorCode::CrossDevice => "cross-device", + } + } + pub fn message(&self) -> &'static str { + match self { + ErrorCode::Access => "Permission denied, similar to `EACCES` in POSIX.", + ErrorCode::WouldBlock => "Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX.", + ErrorCode::Already => "Connection already in progress, similar to `EALREADY` in POSIX.", + ErrorCode::BadDescriptor => "Bad descriptor, similar to `EBADF` in POSIX.", + ErrorCode::Busy => "Device or resource busy, similar to `EBUSY` in POSIX.", + ErrorCode::Deadlock => "Resource deadlock would occur, similar to `EDEADLK` in POSIX.", + ErrorCode::Quota => "Storage quota exceeded, similar to `EDQUOT` in POSIX.", + ErrorCode::Exist => "File exists, similar to `EEXIST` in POSIX.", + ErrorCode::FileTooLarge => "File too large, similar to `EFBIG` in POSIX.", + ErrorCode::IllegalByteSequence => "Illegal byte sequence, similar to `EILSEQ` in POSIX.", + ErrorCode::InProgress => "Operation in progress, similar to `EINPROGRESS` in POSIX.", + ErrorCode::Interrupted => "Interrupted function, similar to `EINTR` in POSIX.", + ErrorCode::Invalid => "Invalid argument, similar to `EINVAL` in POSIX.", + ErrorCode::Io => "I/O error, similar to `EIO` in POSIX.", + ErrorCode::IsDirectory => "Is a directory, similar to `EISDIR` in POSIX.", + ErrorCode::Loop => "Too many levels of symbolic links, similar to `ELOOP` in POSIX.", + ErrorCode::TooManyLinks => "Too many links, similar to `EMLINK` in POSIX.", + ErrorCode::MessageSize => "Message too large, similar to `EMSGSIZE` in POSIX.", + ErrorCode::NameTooLong => "Filename too long, similar to `ENAMETOOLONG` in POSIX.", + ErrorCode::NoDevice => "No such device, similar to `ENODEV` in POSIX.", + ErrorCode::NoEntry => "No such file or directory, similar to `ENOENT` in POSIX.", + ErrorCode::NoLock => "No locks available, similar to `ENOLCK` in POSIX.", + ErrorCode::InsufficientMemory => "Not enough space, similar to `ENOMEM` in POSIX.", + ErrorCode::InsufficientSpace => "No space left on device, similar to `ENOSPC` in POSIX.", + ErrorCode::NotDirectory => "Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX.", + ErrorCode::NotEmpty => "Directory not empty, similar to `ENOTEMPTY` in POSIX.", + ErrorCode::NotRecoverable => "State not recoverable, similar to `ENOTRECOVERABLE` in POSIX.", + ErrorCode::Unsupported => "Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX.", + ErrorCode::NoTty => "Inappropriate I/O control operation, similar to `ENOTTY` in POSIX.", + ErrorCode::NoSuchDevice => "No such device or address, similar to `ENXIO` in POSIX.", + ErrorCode::Overflow => "Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX.", + ErrorCode::NotPermitted => "Operation not permitted, similar to `EPERM` in POSIX.", + ErrorCode::Pipe => "Broken pipe, similar to `EPIPE` in POSIX.", + ErrorCode::ReadOnly => "Read-only file system, similar to `EROFS` in POSIX.", + ErrorCode::InvalidSeek => "Invalid seek, similar to `ESPIPE` in POSIX.", + ErrorCode::TextFileBusy => "Text file busy, similar to `ETXTBSY` in POSIX.", + ErrorCode::CrossDevice => "Cross-device link, similar to `EXDEV` in POSIX.", + } + } + } + impl ::core::fmt::Debug for ErrorCode { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ErrorCode") + .field("code", &(*self as i32)) + .field("name", &self.name()) + .field("message", &self.message()) + .finish() + } + } + impl ::core::fmt::Display for ErrorCode { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "{} (error {})", self.name(), *self as i32) + } + } + + impl std::error::Error for ErrorCode {} + + impl ErrorCode { + pub(crate) unsafe fn _lift(val: u8) -> ErrorCode { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => ErrorCode::Access, + 1 => ErrorCode::WouldBlock, + 2 => ErrorCode::Already, + 3 => ErrorCode::BadDescriptor, + 4 => ErrorCode::Busy, + 5 => ErrorCode::Deadlock, + 6 => ErrorCode::Quota, + 7 => ErrorCode::Exist, + 8 => ErrorCode::FileTooLarge, + 9 => ErrorCode::IllegalByteSequence, + 10 => ErrorCode::InProgress, + 11 => ErrorCode::Interrupted, + 12 => ErrorCode::Invalid, + 13 => ErrorCode::Io, + 14 => ErrorCode::IsDirectory, + 15 => ErrorCode::Loop, + 16 => ErrorCode::TooManyLinks, + 17 => ErrorCode::MessageSize, + 18 => ErrorCode::NameTooLong, + 19 => ErrorCode::NoDevice, + 20 => ErrorCode::NoEntry, + 21 => ErrorCode::NoLock, + 22 => ErrorCode::InsufficientMemory, + 23 => ErrorCode::InsufficientSpace, + 24 => ErrorCode::NotDirectory, + 25 => ErrorCode::NotEmpty, + 26 => ErrorCode::NotRecoverable, + 27 => ErrorCode::Unsupported, + 28 => ErrorCode::NoTty, + 29 => ErrorCode::NoSuchDevice, + 30 => ErrorCode::Overflow, + 31 => ErrorCode::NotPermitted, + 32 => ErrorCode::Pipe, + 33 => ErrorCode::ReadOnly, + 34 => ErrorCode::InvalidSeek, + 35 => ErrorCode::TextFileBusy, + 36 => ErrorCode::CrossDevice, + + _ => panic!("invalid enum discriminant"), + } + } + } + + /// File or memory access pattern advisory information. + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum Advice { + /// The application has no advice to give on its behavior with respect + /// to the specified data. + Normal, + /// The application expects to access the specified data sequentially + /// from lower offsets to higher offsets. + Sequential, + /// The application expects to access the specified data in a random + /// order. + Random, + /// The application expects to access the specified data in the near + /// future. + WillNeed, + /// The application expects that it will not access the specified data + /// in the near future. + DontNeed, + /// The application expects to access the specified data once and then + /// not reuse it thereafter. + NoReuse, + } + impl ::core::fmt::Debug for Advice { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Advice::Normal => f.debug_tuple("Advice::Normal").finish(), + Advice::Sequential => f.debug_tuple("Advice::Sequential").finish(), + Advice::Random => f.debug_tuple("Advice::Random").finish(), + Advice::WillNeed => f.debug_tuple("Advice::WillNeed").finish(), + Advice::DontNeed => f.debug_tuple("Advice::DontNeed").finish(), + Advice::NoReuse => f.debug_tuple("Advice::NoReuse").finish(), + } + } + } + + impl Advice { + pub(crate) unsafe fn _lift(val: u8) -> Advice { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => Advice::Normal, + 1 => Advice::Sequential, + 2 => Advice::Random, + 3 => Advice::WillNeed, + 4 => Advice::DontNeed, + 5 => Advice::NoReuse, + + _ => panic!("invalid enum discriminant"), + } + } + } + + /// A 128-bit hash value, split into parts because wasm doesn't have a + /// 128-bit integer type. + #[repr(C)] + #[derive(Clone, Copy)] + pub struct MetadataHashValue { + /// 64 bits of a 128-bit hash value. + pub lower: u64, + /// Another 64 bits of a 128-bit hash value. + pub upper: u64, + } + impl ::core::fmt::Debug for MetadataHashValue { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MetadataHashValue") + .field("lower", &self.lower) + .field("upper", &self.upper) + .finish() + } + } + /// A descriptor is a reference to a filesystem object, which may be a file, + /// directory, named pipe, special file, or other object on which filesystem + /// calls may be made. + + #[derive(Debug)] + #[repr(transparent)] + pub struct Descriptor { + handle: _rt::Resource, + } + + impl Descriptor { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for Descriptor { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]descriptor"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + /// A stream of directory entries. + + #[derive(Debug)] + #[repr(transparent)] + pub struct DirectoryEntryStream { + handle: _rt::Resource, + } + + impl DirectoryEntryStream { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for DirectoryEntryStream { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]directory-entry-stream"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return a stream for reading from a file, if available. + /// + /// May fail with an error-code describing why the file cannot be read. + /// + /// Multiple read, write, and append streams may be active on the same open + /// file and they do not interfere with each other. + /// + /// Note: This allows using `read-stream`, which is similar to `read` in POSIX. + pub fn read_via_stream(&self, offset: Filesize) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.read-via-stream"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(offset), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::io::streams::InputStream::from_handle( + l2 as u32, + ) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return a stream for writing to a file, if available. + /// + /// May fail with an error-code describing why the file cannot be written. + /// + /// Note: This allows using `write-stream`, which is similar to `write` in + /// POSIX. + pub fn write_via_stream( + &self, + offset: Filesize, + ) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.write-via-stream"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(offset), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::io::streams::OutputStream::from_handle(l2 as u32) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return a stream for appending to a file, if available. + /// + /// May fail with an error-code describing why the file cannot be appended. + /// + /// Note: This allows using `write-stream`, which is similar to `write` with + /// `O_APPEND` in in POSIX. + pub fn append_via_stream(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.append-via-stream"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::io::streams::OutputStream::from_handle(l2 as u32) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Provide file advisory information on a descriptor. + /// + /// This is similar to `posix_fadvise` in POSIX. + pub fn advise( + &self, + offset: Filesize, + length: Filesize, + advice: Advice, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.advise"] + fn wit_import(_: i32, _: i64, _: i64, _: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: i64, _: i32, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + _rt::as_i64(offset), + _rt::as_i64(length), + advice.clone() as i32, + ptr0, + ); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l2 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Synchronize the data of a file to disk. + /// + /// This function succeeds with no effect if the file descriptor is not + /// opened for writing. + /// + /// Note: This is similar to `fdatasync` in POSIX. + pub fn sync_data(&self) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.sync-data"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l2 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Get flags associated with a descriptor. + /// + /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. + /// + /// Note: This returns the value that was the `fs_flags` value returned + /// from `fdstat_get` in earlier versions of WASI. + pub fn get_flags(&self) -> Result { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.get-flags"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + DescriptorFlags::empty() + | DescriptorFlags::from_bits_retain(((l2 as u8) << 0) as _) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Get the dynamic type of a descriptor. + /// + /// Note: This returns the same value as the `type` field of the `fd-stat` + /// returned by `stat`, `stat-at` and similar. + /// + /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided + /// by `fstat` in POSIX. + /// + /// Note: This returns the value that was the `fs_filetype` value returned + /// from `fdstat_get` in earlier versions of WASI. + pub fn get_type(&self) -> Result { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.get-type"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + DescriptorType::_lift(l2 as u8) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Adjust the size of an open file. If this increases the file's size, the + /// extra bytes are filled with zeros. + /// + /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. + pub fn set_size(&self, size: Filesize) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.set-size"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(size), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l2 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Adjust the timestamps of an open file or directory. + /// + /// Note: This is similar to `futimens` in POSIX. + /// + /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. + pub fn set_times( + &self, + data_access_timestamp: NewTimestamp, + data_modification_timestamp: NewTimestamp, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let (result1_0, result1_1, result1_2) = match data_access_timestamp { + NewTimestamp::NoChange => (0i32, 0i64, 0i32), + NewTimestamp::Now => (1i32, 0i64, 0i32), + NewTimestamp::Timestamp(e) => { + let super::super::super::wasi::clocks::wall_clock::Datetime { + seconds: seconds0, + nanoseconds: nanoseconds0, + } = e; + + (2i32, _rt::as_i64(seconds0), _rt::as_i32(nanoseconds0)) + } + }; + let (result3_0, result3_1, result3_2) = match data_modification_timestamp { + NewTimestamp::NoChange => (0i32, 0i64, 0i32), + NewTimestamp::Now => (1i32, 0i64, 0i32), + NewTimestamp::Timestamp(e) => { + let super::super::super::wasi::clocks::wall_clock::Datetime { + seconds: seconds2, + nanoseconds: nanoseconds2, + } = e; + + (2i32, _rt::as_i64(seconds2), _rt::as_i32(nanoseconds2)) + } + }; + let ptr4 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.set-times"] + fn wit_import( + _: i32, + _: i32, + _: i64, + _: i32, + _: i32, + _: i64, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: i64, + _: i32, + _: i32, + _: i64, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + result1_0, + result1_1, + result1_2, + result3_0, + result3_1, + result3_2, + ptr4, + ); + let l5 = i32::from(*ptr4.add(0).cast::()); + match l5 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l6 = i32::from(*ptr4.add(1).cast::()); + + ErrorCode::_lift(l6 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Read from a descriptor, without using and updating the descriptor's offset. + /// + /// This function returns a list of bytes containing the data that was + /// read, along with a bool which, when true, indicates that the end of the + /// file was reached. The returned list will contain up to `length` bytes; it + /// may return fewer than requested, if the end of the file is reached or + /// if the I/O operation is interrupted. + /// + /// In the future, this may change to return a `stream`. + /// + /// Note: This is similar to `pread` in POSIX. + pub fn read( + &self, + length: Filesize, + offset: Filesize, + ) -> Result<(_rt::Vec, bool), ErrorCode> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.read"] + fn wit_import(_: i32, _: i64, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: i64, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + _rt::as_i64(length), + _rt::as_i64(offset), + ptr0, + ); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + let l5 = i32::from(*ptr0.add(12).cast::()); + + ( + _rt::Vec::from_raw_parts(l2.cast(), len4, len4), + _rt::bool_lift(l5 as u8), + ) + }; + Ok(e) + } + 1 => { + let e = { + let l6 = i32::from(*ptr0.add(4).cast::()); + + ErrorCode::_lift(l6 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Write to a descriptor, without using and updating the descriptor's offset. + /// + /// It is valid to write past the end of a file; the file is extended to the + /// extent of the write, with bytes between the previous end and the start of + /// the write set to zero. + /// + /// In the future, this may change to take a `stream`. + /// + /// Note: This is similar to `pwrite` in POSIX. + pub fn write( + &self, + buffer: &[u8], + offset: Filesize, + ) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let vec0 = buffer; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.write"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: i64, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + ptr0.cast_mut(), + len0, + _rt::as_i64(offset), + ptr1, + ); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = { + let l3 = *ptr1.add(8).cast::(); + + l3 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l4 = i32::from(*ptr1.add(8).cast::()); + + ErrorCode::_lift(l4 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Read directory entries from a directory. + /// + /// On filesystems where directories contain entries referring to themselves + /// and their parents, often named `.` and `..` respectively, these entries + /// are omitted. + /// + /// This always returns a new stream which starts at the beginning of the + /// directory. Multiple streams may be active on the same directory, and they + /// do not interfere with each other. + pub fn read_directory(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.read-directory"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + DirectoryEntryStream::from_handle(l2 as u32) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Synchronize the data and metadata of a file to disk. + /// + /// This function succeeds with no effect if the file descriptor is not + /// opened for writing. + /// + /// Note: This is similar to `fsync` in POSIX. + pub fn sync(&self) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.sync"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l2 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Create a directory. + /// + /// Note: This is similar to `mkdirat` in POSIX. + pub fn create_directory_at(&self, path: &str) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let vec0 = path; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.create-directory-at"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr1.add(1).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return the attributes of an open file or directory. + /// + /// Note: This is similar to `fstat` in POSIX, except that it does not return + /// device and inode information. For testing whether two descriptors refer to + /// the same underlying filesystem object, use `is-same-object`. To obtain + /// additional data that can be used do determine whether a file has been + /// modified, use `metadata-hash`. + /// + /// Note: This was called `fd_filestat_get` in earlier versions of WASI. + pub fn stat(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 104]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 104]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.stat"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(8).cast::()); + let l3 = *ptr0.add(16).cast::(); + let l4 = *ptr0.add(24).cast::(); + let l5 = i32::from(*ptr0.add(32).cast::()); + let l8 = i32::from(*ptr0.add(56).cast::()); + let l11 = i32::from(*ptr0.add(80).cast::()); + + DescriptorStat { + type_: DescriptorType::_lift(l2 as u8), + link_count: l3 as u64, + size: l4 as u64, + data_access_timestamp: match l5 { + 0 => None, + 1 => { + let e = { + let l6 = *ptr0.add(40).cast::(); + let l7 = *ptr0.add(48).cast::(); + + super::super::super::wasi::clocks::wall_clock::Datetime{ + seconds: l6 as u64, + nanoseconds: l7 as u32, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + data_modification_timestamp: match l8 { + 0 => None, + 1 => { + let e = { + let l9 = *ptr0.add(64).cast::(); + let l10 = *ptr0.add(72).cast::(); + + super::super::super::wasi::clocks::wall_clock::Datetime{ + seconds: l9 as u64, + nanoseconds: l10 as u32, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + status_change_timestamp: match l11 { + 0 => None, + 1 => { + let e = { + let l12 = *ptr0.add(88).cast::(); + let l13 = *ptr0.add(96).cast::(); + + super::super::super::wasi::clocks::wall_clock::Datetime{ + seconds: l12 as u64, + nanoseconds: l13 as u32, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + } + }; + Ok(e) + } + 1 => { + let e = { + let l14 = i32::from(*ptr0.add(8).cast::()); + + ErrorCode::_lift(l14 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return the attributes of a file or directory. + /// + /// Note: This is similar to `fstatat` in POSIX, except that it does not + /// return device and inode information. See the `stat` description for a + /// discussion of alternatives. + /// + /// Note: This was called `path_filestat_get` in earlier versions of WASI. + pub fn stat_at( + &self, + path_flags: PathFlags, + path: &str, + ) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 104]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 104]); + let flags0 = path_flags; + let vec1 = path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let ptr2 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.stat-at"] + fn wit_import(_: i32, _: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (flags0.bits() >> 0) as i32, + ptr1.cast_mut(), + len1, + ptr2, + ); + let l3 = i32::from(*ptr2.add(0).cast::()); + match l3 { + 0 => { + let e = { + let l4 = i32::from(*ptr2.add(8).cast::()); + let l5 = *ptr2.add(16).cast::(); + let l6 = *ptr2.add(24).cast::(); + let l7 = i32::from(*ptr2.add(32).cast::()); + let l10 = i32::from(*ptr2.add(56).cast::()); + let l13 = i32::from(*ptr2.add(80).cast::()); + + DescriptorStat { + type_: DescriptorType::_lift(l4 as u8), + link_count: l5 as u64, + size: l6 as u64, + data_access_timestamp: match l7 { + 0 => None, + 1 => { + let e = { + let l8 = *ptr2.add(40).cast::(); + let l9 = *ptr2.add(48).cast::(); + + super::super::super::wasi::clocks::wall_clock::Datetime{ + seconds: l8 as u64, + nanoseconds: l9 as u32, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + data_modification_timestamp: match l10 { + 0 => None, + 1 => { + let e = { + let l11 = *ptr2.add(64).cast::(); + let l12 = *ptr2.add(72).cast::(); + + super::super::super::wasi::clocks::wall_clock::Datetime{ + seconds: l11 as u64, + nanoseconds: l12 as u32, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + status_change_timestamp: match l13 { + 0 => None, + 1 => { + let e = { + let l14 = *ptr2.add(88).cast::(); + let l15 = *ptr2.add(96).cast::(); + + super::super::super::wasi::clocks::wall_clock::Datetime{ + seconds: l14 as u64, + nanoseconds: l15 as u32, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + }, + } + }; + Ok(e) + } + 1 => { + let e = { + let l16 = i32::from(*ptr2.add(8).cast::()); + + ErrorCode::_lift(l16 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Adjust the timestamps of a file or directory. + /// + /// Note: This is similar to `utimensat` in POSIX. + /// + /// Note: This was called `path_filestat_set_times` in earlier versions of + /// WASI. + pub fn set_times_at( + &self, + path_flags: PathFlags, + path: &str, + data_access_timestamp: NewTimestamp, + data_modification_timestamp: NewTimestamp, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let flags0 = path_flags; + let vec1 = path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let (result3_0, result3_1, result3_2) = match data_access_timestamp { + NewTimestamp::NoChange => (0i32, 0i64, 0i32), + NewTimestamp::Now => (1i32, 0i64, 0i32), + NewTimestamp::Timestamp(e) => { + let super::super::super::wasi::clocks::wall_clock::Datetime { + seconds: seconds2, + nanoseconds: nanoseconds2, + } = e; + + (2i32, _rt::as_i64(seconds2), _rt::as_i32(nanoseconds2)) + } + }; + let (result5_0, result5_1, result5_2) = match data_modification_timestamp { + NewTimestamp::NoChange => (0i32, 0i64, 0i32), + NewTimestamp::Now => (1i32, 0i64, 0i32), + NewTimestamp::Timestamp(e) => { + let super::super::super::wasi::clocks::wall_clock::Datetime { + seconds: seconds4, + nanoseconds: nanoseconds4, + } = e; + + (2i32, _rt::as_i64(seconds4), _rt::as_i32(nanoseconds4)) + } + }; + let ptr6 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.set-times-at"] + fn wit_import( + _: i32, + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: i64, + _: i32, + _: i32, + _: i64, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: i64, + _: i32, + _: i32, + _: i64, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (flags0.bits() >> 0) as i32, + ptr1.cast_mut(), + len1, + result3_0, + result3_1, + result3_2, + result5_0, + result5_1, + result5_2, + ptr6, + ); + let l7 = i32::from(*ptr6.add(0).cast::()); + match l7 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l8 = i32::from(*ptr6.add(1).cast::()); + + ErrorCode::_lift(l8 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Create a hard link. + /// + /// Note: This is similar to `linkat` in POSIX. + pub fn link_at( + &self, + old_path_flags: PathFlags, + old_path: &str, + new_descriptor: &Descriptor, + new_path: &str, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let flags0 = old_path_flags; + let vec1 = old_path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let vec2 = new_path; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + let ptr3 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.link-at"] + fn wit_import( + _: i32, + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (flags0.bits() >> 0) as i32, + ptr1.cast_mut(), + len1, + (new_descriptor).handle() as i32, + ptr2.cast_mut(), + len2, + ptr3, + ); + let l4 = i32::from(*ptr3.add(0).cast::()); + match l4 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l5 = i32::from(*ptr3.add(1).cast::()); + + ErrorCode::_lift(l5 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Open a file or directory. + /// + /// The returned descriptor is not guaranteed to be the lowest-numbered + /// descriptor not currently open/ it is randomized to prevent applications + /// from depending on making assumptions about indexes, since this is + /// error-prone in multi-threaded contexts. The returned descriptor is + /// guaranteed to be less than 2**31. + /// + /// If `flags` contains `descriptor-flags::mutate-directory`, and the base + /// descriptor doesn't have `descriptor-flags::mutate-directory` set, + /// `open-at` fails with `error-code::read-only`. + /// + /// If `flags` contains `write` or `mutate-directory`, or `open-flags` + /// contains `truncate` or `create`, and the base descriptor doesn't have + /// `descriptor-flags::mutate-directory` set, `open-at` fails with + /// `error-code::read-only`. + /// + /// Note: This is similar to `openat` in POSIX. + pub fn open_at( + &self, + path_flags: PathFlags, + path: &str, + open_flags: OpenFlags, + flags: DescriptorFlags, + ) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let flags0 = path_flags; + let vec1 = path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let flags2 = open_flags; + let flags3 = flags; + let ptr4 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.open-at"] + fn wit_import( + _: i32, + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (flags0.bits() >> 0) as i32, + ptr1.cast_mut(), + len1, + (flags2.bits() >> 0) as i32, + (flags3.bits() >> 0) as i32, + ptr4, + ); + let l5 = i32::from(*ptr4.add(0).cast::()); + match l5 { + 0 => { + let e = { + let l6 = *ptr4.add(4).cast::(); + + Descriptor::from_handle(l6 as u32) + }; + Ok(e) + } + 1 => { + let e = { + let l7 = i32::from(*ptr4.add(4).cast::()); + + ErrorCode::_lift(l7 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Read the contents of a symbolic link. + /// + /// If the contents contain an absolute or rooted path in the underlying + /// filesystem, this function fails with `error-code::not-permitted`. + /// + /// Note: This is similar to `readlinkat` in POSIX. + pub fn readlink_at(&self, path: &str) -> Result<_rt::String, ErrorCode> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let vec0 = path; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.readlink-at"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = { + let l3 = *ptr1.add(4).cast::<*mut u8>(); + let l4 = *ptr1.add(8).cast::(); + let len5 = l4; + let bytes5 = _rt::Vec::from_raw_parts(l3.cast(), len5, len5); + + _rt::string_lift(bytes5) + }; + Ok(e) + } + 1 => { + let e = { + let l6 = i32::from(*ptr1.add(4).cast::()); + + ErrorCode::_lift(l6 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Remove a directory. + /// + /// Return `error-code::not-empty` if the directory is not empty. + /// + /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. + pub fn remove_directory_at(&self, path: &str) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let vec0 = path; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.remove-directory-at"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr1.add(1).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Rename a filesystem object. + /// + /// Note: This is similar to `renameat` in POSIX. + pub fn rename_at( + &self, + old_path: &str, + new_descriptor: &Descriptor, + new_path: &str, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let vec0 = old_path; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec1 = new_path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let ptr2 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.rename-at"] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + ptr0.cast_mut(), + len0, + (new_descriptor).handle() as i32, + ptr1.cast_mut(), + len1, + ptr2, + ); + let l3 = i32::from(*ptr2.add(0).cast::()); + match l3 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l4 = i32::from(*ptr2.add(1).cast::()); + + ErrorCode::_lift(l4 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Create a symbolic link (also known as a "symlink"). + /// + /// If `old-path` starts with `/`, the function fails with + /// `error-code::not-permitted`. + /// + /// Note: This is similar to `symlinkat` in POSIX. + pub fn symlink_at(&self, old_path: &str, new_path: &str) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let vec0 = old_path; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec1 = new_path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let ptr2 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.symlink-at"] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + ptr0.cast_mut(), + len0, + ptr1.cast_mut(), + len1, + ptr2, + ); + let l3 = i32::from(*ptr2.add(0).cast::()); + match l3 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l4 = i32::from(*ptr2.add(1).cast::()); + + ErrorCode::_lift(l4 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Unlink a filesystem object that is not a directory. + /// + /// Return `error-code::is-directory` if the path refers to a directory. + /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. + pub fn unlink_file_at(&self, path: &str) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let vec0 = path; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.unlink-file-at"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr1.add(1).cast::()); + + ErrorCode::_lift(l3 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Test whether two descriptors refer to the same filesystem object. + /// + /// In POSIX, this corresponds to testing whether the two descriptors have the + /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. + /// wasi-filesystem does not expose device and inode numbers, so this function + /// may be used instead. + pub fn is_same_object(&self, other: &Descriptor) -> bool { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.is-same-object"] + fn wit_import(_: i32, _: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32, (other).handle() as i32); + _rt::bool_lift(ret as u8) + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return a hash of the metadata associated with a filesystem object referred + /// to by a descriptor. + /// + /// This returns a hash of the last-modification timestamp and file size, and + /// may also include the inode number, device number, birth timestamp, and + /// other metadata fields that may change when the file is modified or + /// replaced. It may also include a secret value chosen by the + /// implementation and not otherwise exposed. + /// + /// Implementations are encourated to provide the following properties: + /// + /// - If the file is not modified or replaced, the computed hash value should + /// usually not change. + /// - If the object is modified or replaced, the computed hash value should + /// usually change. + /// - The inputs to the hash should not be easily computable from the + /// computed hash. + /// + /// However, none of these is required. + pub fn metadata_hash(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 24]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 24]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.metadata-hash"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + let l3 = *ptr0.add(16).cast::(); + + MetadataHashValue { + lower: l2 as u64, + upper: l3 as u64, + } + }; + Ok(e) + } + 1 => { + let e = { + let l4 = i32::from(*ptr0.add(8).cast::()); + + ErrorCode::_lift(l4 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl Descriptor { + #[allow(unused_unsafe, clippy::all)] + /// Return a hash of the metadata associated with a filesystem object referred + /// to by a directory descriptor and a relative path. + /// + /// This performs the same hash computation as `metadata-hash`. + pub fn metadata_hash_at( + &self, + path_flags: PathFlags, + path: &str, + ) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 24]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 24]); + let flags0 = path_flags; + let vec1 = path; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let ptr2 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]descriptor.metadata-hash-at"] + fn wit_import(_: i32, _: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (flags0.bits() >> 0) as i32, + ptr1.cast_mut(), + len1, + ptr2, + ); + let l3 = i32::from(*ptr2.add(0).cast::()); + match l3 { + 0 => { + let e = { + let l4 = *ptr2.add(8).cast::(); + let l5 = *ptr2.add(16).cast::(); + + MetadataHashValue { + lower: l4 as u64, + upper: l5 as u64, + } + }; + Ok(e) + } + 1 => { + let e = { + let l6 = i32::from(*ptr2.add(8).cast::()); + + ErrorCode::_lift(l6 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl DirectoryEntryStream { + #[allow(unused_unsafe, clippy::all)] + /// Read a single directory entry from a `directory-entry-stream`. + pub fn read_directory_entry(&self) -> Result, ErrorCode> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 20]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 20]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "[method]directory-entry-stream.read-directory-entry"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + + match l2 { + 0 => None, + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let l4 = *ptr0.add(12).cast::<*mut u8>(); + let l5 = *ptr0.add(16).cast::(); + let len6 = l5; + let bytes6 = + _rt::Vec::from_raw_parts(l4.cast(), len6, len6); + + DirectoryEntry { + type_: DescriptorType::_lift(l3 as u8), + name: _rt::string_lift(bytes6), + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Ok(e) + } + 1 => { + let e = { + let l7 = i32::from(*ptr0.add(4).cast::()); + + ErrorCode::_lift(l7 as u8) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + #[allow(unused_unsafe, clippy::all)] + /// Attempts to extract a filesystem-related `error-code` from the stream + /// `error` provided. + /// + /// Stream operations which return `stream-error::last-operation-failed` + /// have a payload with more information about the operation that failed. + /// This payload can be passed through to this function to see if there's + /// filesystem-related information about the error to return. + /// + /// Note that this function is fallible because not all stream-related + /// errors are filesystem-related errors. + pub fn filesystem_error_code(err: &Error) -> Option { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/types@0.2.0")] + extern "C" { + #[link_name = "filesystem-error-code"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((err).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + ErrorCode::_lift(l2 as u8) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod preopens { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Descriptor = super::super::super::wasi::filesystem::types::Descriptor; + #[allow(unused_unsafe, clippy::all)] + /// Return the set of preopened directories, and their path. + pub fn get_directories() -> _rt::Vec<(Descriptor, _rt::String)> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:filesystem/preopens@0.2.0")] + extern "C" { + #[link_name = "get-directories"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let base7 = l1; + let len7 = l2; + let mut result7 = _rt::Vec::with_capacity(len7); + for i in 0..len7 { + let base = base7.add(i * 12); + let e7 = { + let l3 = *base.add(0).cast::(); + let l4 = *base.add(4).cast::<*mut u8>(); + let l5 = *base.add(8).cast::(); + let len6 = l5; + let bytes6 = _rt::Vec::from_raw_parts(l4.cast(), len6, len6); + + (super::super::super::wasi::filesystem::types::Descriptor::from_handle(l3 as u32), _rt::string_lift(bytes6)) + }; + result7.push(e7); + } + _rt::cabi_dealloc(base7, len7 * 12, 4); + result7 + } + } + } + } + #[allow(dead_code)] + pub mod io { + #[allow(dead_code, clippy::all)] + pub mod error { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// provide functions to further "downcast" this error into more specific + /// error information. For example, `error`s returned in streams derived + /// from filesystem types to be described using the filesystem's own + /// error-code type, using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter + /// `borrow` and returns + /// `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + + #[derive(Debug)] + #[repr(transparent)] + pub struct Error { + handle: _rt::Resource, + } + + impl Error { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for Error { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:io/error@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]error"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl Error { + #[allow(unused_unsafe, clippy::all)] + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + pub fn to_debug_string(&self) -> _rt::String { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/error@0.2.0")] + extern "C" { + #[link_name = "[method]error.to-debug-string"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let len3 = l2; + let bytes3 = _rt::Vec::from_raw_parts(l1.cast(), len3, len3); + _rt::string_lift(bytes3) + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod poll { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + /// `pollable` represents a single I/O event which may be ready, or not. + + #[derive(Debug)] + #[repr(transparent)] + pub struct Pollable { + handle: _rt::Resource, + } + + impl Pollable { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for Pollable { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]pollable"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl Pollable { + #[allow(unused_unsafe, clippy::all)] + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + pub fn ready(&self) -> bool { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "[method]pollable.ready"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + _rt::bool_lift(ret as u8) + } + } + } + impl Pollable { + #[allow(unused_unsafe, clippy::all)] + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + pub fn block(&self) { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "[method]pollable.block"] + fn wit_import(_: i32); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) { + unreachable!() + } + wit_import((self).handle() as i32); + } + } + } + #[allow(unused_unsafe, clippy::all)] + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// If the list contains more elements than can be indexed with a `u32` + /// value, this function traps. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being reaedy for I/O. + pub fn poll(in_: &[&Pollable]) -> _rt::Vec { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let vec0 = in_; + let len0 = vec0.len(); + let layout0 = _rt::alloc::Layout::from_size_align_unchecked(vec0.len() * 4, 4); + let result0 = if layout0.size() != 0 { + let ptr = _rt::alloc::alloc(layout0).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout0); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec0.into_iter().enumerate() { + let base = result0.add(i * 4); + { + *base.add(0).cast::() = (e).handle() as i32; + } + } + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/poll@0.2.0")] + extern "C" { + #[link_name = "poll"] + fn wit_import(_: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import(result0, len0, ptr1); + let l2 = *ptr1.add(0).cast::<*mut u8>(); + let l3 = *ptr1.add(4).cast::(); + let len4 = l3; + if layout0.size() != 0 { + _rt::alloc::dealloc(result0.cast(), layout0); + } + _rt::Vec::from_raw_parts(l2.cast(), len4, len4) + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod streams { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Error = super::super::super::wasi::io::error::Error; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + /// An error for input-stream and output-stream operations. + pub enum StreamError { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + LastOperationFailed(Error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + Closed, + } + impl ::core::fmt::Debug for StreamError { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + StreamError::LastOperationFailed(e) => f + .debug_tuple("StreamError::LastOperationFailed") + .field(e) + .finish(), + StreamError::Closed => f.debug_tuple("StreamError::Closed").finish(), + } + } + } + impl ::core::fmt::Display for StreamError { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "{:?}", self) + } + } + + impl std::error::Error for StreamError {} + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + + #[derive(Debug)] + #[repr(transparent)] + pub struct InputStream { + handle: _rt::Resource, + } + + impl InputStream { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for InputStream { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]input-stream"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + + #[derive(Debug)] + #[repr(transparent)] + pub struct OutputStream { + handle: _rt::Resource, + } + + impl OutputStream { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for OutputStream { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]output-stream"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl InputStream { + #[allow(unused_unsafe, clippy::all)] + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + pub fn read(&self, len: u64) -> Result<_rt::Vec, StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]input-stream.read"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&len), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + + _rt::Vec::from_raw_parts(l2.cast(), len4, len4) + }; + Ok(e) + } + 1 => { + let e = { + let l5 = i32::from(*ptr0.add(4).cast::()); + let v7 = match l5 { + 0 => { + let e7 = { + let l6 = *ptr0.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l6 as u32) + }; + StreamError::LastOperationFailed(e7) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v7 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl InputStream { + #[allow(unused_unsafe, clippy::all)] + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + pub fn blocking_read(&self, len: u64) -> Result<_rt::Vec, StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]input-stream.blocking-read"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&len), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + + _rt::Vec::from_raw_parts(l2.cast(), len4, len4) + }; + Ok(e) + } + 1 => { + let e = { + let l5 = i32::from(*ptr0.add(4).cast::()); + let v7 = match l5 { + 0 => { + let e7 = { + let l6 = *ptr0.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l6 as u32) + }; + StreamError::LastOperationFailed(e7) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v7 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl InputStream { + #[allow(unused_unsafe, clippy::all)] + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + pub fn skip(&self, len: u64) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]input-stream.skip"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&len), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr0.add(12).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl InputStream { + #[allow(unused_unsafe, clippy::all)] + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + pub fn blocking_skip(&self, len: u64) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]input-stream.blocking-skip"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&len), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr0.add(12).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl InputStream { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]input-stream.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + pub fn check_write(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.check-write"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr0.add(12).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + pub fn write(&self, contents: &[u8]) -> Result<(), StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let vec0 = contents; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.write"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr1.add(4).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr1.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + pub fn blocking_write_and_flush(&self, contents: &[u8]) -> Result<(), StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let vec0 = contents; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.blocking-write-and-flush"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr1.add(4).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr1.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + pub fn flush(&self) -> Result<(), StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.flush"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + let v4 = match l2 { + 0 => { + let e4 = { + let l3 = *ptr0.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l3 as u32) + }; + StreamError::LastOperationFailed(e4) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v4 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + pub fn blocking_flush(&self) -> Result<(), StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.blocking-flush"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + let v4 = match l2 { + 0 => { + let e4 = { + let l3 = *ptr0.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l3 as u32) + }; + StreamError::LastOperationFailed(e4) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v4 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occured. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + pub fn write_zeroes(&self, len: u64) -> Result<(), StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.write-zeroes"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&len), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + let v4 = match l2 { + 0 => { + let e4 = { + let l3 = *ptr0.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l3 as u32) + }; + StreamError::LastOperationFailed(e4) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v4 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + pub fn blocking_write_zeroes_and_flush(&self, len: u64) -> Result<(), StreamError> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.blocking-write-zeroes-and-flush"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&len), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + let v4 = match l2 { + 0 => { + let e4 = { + let l3 = *ptr0.add(8).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l3 as u32) + }; + StreamError::LastOperationFailed(e4) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v4 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivelant to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + pub fn splice(&self, src: &InputStream, len: u64) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.splice"] + fn wit_import(_: i32, _: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (src).handle() as i32, + _rt::as_i64(&len), + ptr0, + ); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr0.add(12).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutputStream { + #[allow(unused_unsafe, clippy::all)] + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + pub fn blocking_splice( + &self, + src: &InputStream, + len: u64, + ) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:io/streams@0.2.0")] + extern "C" { + #[link_name = "[method]output-stream.blocking-splice"] + fn wit_import(_: i32, _: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (src).handle() as i32, + _rt::as_i64(&len), + ptr0, + ); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let v5 = match l3 { + 0 => { + let e5 = { + let l4 = *ptr0.add(12).cast::(); + + super::super::super::wasi::io::error::Error::from_handle(l4 as u32) + }; + StreamError::LastOperationFailed(e5) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + StreamError::Closed + } + }; + + v5 + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + } + } + #[allow(dead_code)] + pub mod random { + #[allow(dead_code, clippy::all)] + pub mod random { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + #[allow(unused_unsafe, clippy::all)] + /// Return `len` cryptographically-secure random or pseudo-random bytes. + /// + /// This function must produce data at least as cryptographically secure and + /// fast as an adequately seeded cryptographically-secure pseudo-random + /// number generator (CSPRNG). It must not block, from the perspective of + /// the calling program, under any circumstances, including on the first + /// request and on requests for numbers of bytes. The returned data must + /// always be unpredictable. + /// + /// This function must always return fresh data. Deterministic environments + /// must omit this function, rather than implementing it with deterministic + /// data. + pub fn get_random_bytes(len: u64) -> _rt::Vec { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:random/random@0.2.0")] + extern "C" { + #[link_name = "get-random-bytes"] + fn wit_import(_: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i64, _: *mut u8) { + unreachable!() + } + wit_import(_rt::as_i64(&len), ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let len3 = l2; + _rt::Vec::from_raw_parts(l1.cast(), len3, len3) + } + } + #[allow(unused_unsafe, clippy::all)] + /// Return a cryptographically-secure random or pseudo-random `u64` value. + /// + /// This function returns the same type of data as `get-random-bytes`, + /// represented as a `u64`. + pub fn get_random_u64() -> u64 { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:random/random@0.2.0")] + extern "C" { + #[link_name = "get-random-u64"] + fn wit_import() -> i64; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i64 { + unreachable!() + } + let ret = wit_import(); + ret as u64 + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod insecure { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + #[allow(unused_unsafe, clippy::all)] + /// Return `len` insecure pseudo-random bytes. + /// + /// This function is not cryptographically secure. Do not use it for + /// anything related to security. + /// + /// There are no requirements on the values of the returned bytes, however + /// implementations are encouraged to return evenly distributed values with + /// a long period. + pub fn get_insecure_random_bytes(len: u64) -> _rt::Vec { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:random/insecure@0.2.0")] + extern "C" { + #[link_name = "get-insecure-random-bytes"] + fn wit_import(_: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i64, _: *mut u8) { + unreachable!() + } + wit_import(_rt::as_i64(&len), ptr0); + let l1 = *ptr0.add(0).cast::<*mut u8>(); + let l2 = *ptr0.add(4).cast::(); + let len3 = l2; + _rt::Vec::from_raw_parts(l1.cast(), len3, len3) + } + } + #[allow(unused_unsafe, clippy::all)] + /// Return an insecure pseudo-random `u64` value. + /// + /// This function returns the same type of pseudo-random data as + /// `get-insecure-random-bytes`, represented as a `u64`. + pub fn get_insecure_random_u64() -> u64 { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:random/insecure@0.2.0")] + extern "C" { + #[link_name = "get-insecure-random-u64"] + fn wit_import() -> i64; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i64 { + unreachable!() + } + let ret = wit_import(); + ret as u64 + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod insecure_seed { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + #[allow(unused_unsafe, clippy::all)] + /// Return a 128-bit value that may contain a pseudo-random value. + /// + /// The returned value is not required to be computed from a CSPRNG, and may + /// even be entirely deterministic. Host implementations are encouraged to + /// provide pseudo-random values to any program exposed to + /// attacker-controlled content, to enable DoS protection built into many + /// languages' hash-map implementations. + /// + /// This function is intended to only be called once, by a source language + /// to initialize Denial Of Service (DoS) protection in its hash-map + /// implementation. + /// + /// # Expected future evolution + /// + /// This will likely be changed to a value import, to prevent it from being + /// called multiple times and potentially used for purposes other than DoS + /// protection. + pub fn insecure_seed() -> (u64, u64) { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:random/insecure-seed@0.2.0")] + extern "C" { + #[link_name = "insecure-seed"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = *ptr0.add(0).cast::(); + let l2 = *ptr0.add(8).cast::(); + (l1 as u64, l2 as u64) + } + } + } + } + #[allow(dead_code)] + pub mod sockets { + #[allow(dead_code, clippy::all)] + pub mod network { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + /// An opaque resource that represents access to (a subset of) the network. + /// This enables context-based security for networking. + /// There is no need for this to map 1:1 to a physical network interface. + + #[derive(Debug)] + #[repr(transparent)] + pub struct Network { + handle: _rt::Resource, + } + + impl Network { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for Network { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:sockets/network@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]network"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + /// Error codes. + /// + /// In theory, every API can return any error code. + /// In practice, API's typically only return the errors documented per API + /// combined with a couple of errors that are always possible: + /// - `unknown` + /// - `access-denied` + /// - `not-supported` + /// - `out-of-memory` + /// - `concurrency-conflict` + /// + /// See each individual API for what the POSIX equivalents are. They sometimes differ per API. + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum ErrorCode { + /// Unknown error + Unknown, + /// Access denied. + /// + /// POSIX equivalent: EACCES, EPERM + AccessDenied, + /// The operation is not supported. + /// + /// POSIX equivalent: EOPNOTSUPP + NotSupported, + /// One of the arguments is invalid. + /// + /// POSIX equivalent: EINVAL + InvalidArgument, + /// Not enough memory to complete the operation. + /// + /// POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY + OutOfMemory, + /// The operation timed out before it could finish completely. + Timeout, + /// This operation is incompatible with another asynchronous operation that is already in progress. + /// + /// POSIX equivalent: EALREADY + ConcurrencyConflict, + /// Trying to finish an asynchronous operation that: + /// - has not been started yet, or: + /// - was already finished by a previous `finish-*` call. + /// + /// Note: this is scheduled to be removed when `future`s are natively supported. + NotInProgress, + /// The operation has been aborted because it could not be completed immediately. + /// + /// Note: this is scheduled to be removed when `future`s are natively supported. + WouldBlock, + /// The operation is not valid in the socket's current state. + InvalidState, + /// A new socket resource could not be created because of a system limit. + NewSocketLimit, + /// A bind operation failed because the provided address is not an address that the `network` can bind to. + AddressNotBindable, + /// A bind operation failed because the provided address is already in use or because there are no ephemeral ports available. + AddressInUse, + /// The remote address is not reachable + RemoteUnreachable, + /// The TCP connection was forcefully rejected + ConnectionRefused, + /// The TCP connection was reset. + ConnectionReset, + /// A TCP connection was aborted. + ConnectionAborted, + /// The size of a datagram sent to a UDP socket exceeded the maximum + /// supported size. + DatagramTooLarge, + /// Name does not exist or has no suitable associated IP addresses. + NameUnresolvable, + /// A temporary failure in name resolution occurred. + TemporaryResolverFailure, + /// A permanent failure in name resolution occurred. + PermanentResolverFailure, + } + impl ErrorCode { + pub fn name(&self) -> &'static str { + match self { + ErrorCode::Unknown => "unknown", + ErrorCode::AccessDenied => "access-denied", + ErrorCode::NotSupported => "not-supported", + ErrorCode::InvalidArgument => "invalid-argument", + ErrorCode::OutOfMemory => "out-of-memory", + ErrorCode::Timeout => "timeout", + ErrorCode::ConcurrencyConflict => "concurrency-conflict", + ErrorCode::NotInProgress => "not-in-progress", + ErrorCode::WouldBlock => "would-block", + ErrorCode::InvalidState => "invalid-state", + ErrorCode::NewSocketLimit => "new-socket-limit", + ErrorCode::AddressNotBindable => "address-not-bindable", + ErrorCode::AddressInUse => "address-in-use", + ErrorCode::RemoteUnreachable => "remote-unreachable", + ErrorCode::ConnectionRefused => "connection-refused", + ErrorCode::ConnectionReset => "connection-reset", + ErrorCode::ConnectionAborted => "connection-aborted", + ErrorCode::DatagramTooLarge => "datagram-too-large", + ErrorCode::NameUnresolvable => "name-unresolvable", + ErrorCode::TemporaryResolverFailure => "temporary-resolver-failure", + ErrorCode::PermanentResolverFailure => "permanent-resolver-failure", + } + } + pub fn message(&self) -> &'static str { + match self { + ErrorCode::Unknown => "Unknown error", + ErrorCode::AccessDenied => "Access denied. + + POSIX equivalent: EACCES, EPERM", + ErrorCode::NotSupported => "The operation is not supported. + + POSIX equivalent: EOPNOTSUPP", + ErrorCode::InvalidArgument => "One of the arguments is invalid. + + POSIX equivalent: EINVAL", + ErrorCode::OutOfMemory => "Not enough memory to complete the operation. + + POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY", + ErrorCode::Timeout => "The operation timed out before it could finish completely.", + ErrorCode::ConcurrencyConflict => "This operation is incompatible with another asynchronous operation that is already in progress. + + POSIX equivalent: EALREADY", + ErrorCode::NotInProgress => "Trying to finish an asynchronous operation that: + - has not been started yet, or: + - was already finished by a previous `finish-*` call. + + Note: this is scheduled to be removed when `future`s are natively supported.", + ErrorCode::WouldBlock => "The operation has been aborted because it could not be completed immediately. + + Note: this is scheduled to be removed when `future`s are natively supported.", + ErrorCode::InvalidState => "The operation is not valid in the socket's current state.", + ErrorCode::NewSocketLimit => "A new socket resource could not be created because of a system limit.", + ErrorCode::AddressNotBindable => "A bind operation failed because the provided address is not an address that the `network` can bind to.", + ErrorCode::AddressInUse => "A bind operation failed because the provided address is already in use or because there are no ephemeral ports available.", + ErrorCode::RemoteUnreachable => "The remote address is not reachable", + ErrorCode::ConnectionRefused => "The TCP connection was forcefully rejected", + ErrorCode::ConnectionReset => "The TCP connection was reset.", + ErrorCode::ConnectionAborted => "A TCP connection was aborted.", + ErrorCode::DatagramTooLarge => "The size of a datagram sent to a UDP socket exceeded the maximum + supported size.", + ErrorCode::NameUnresolvable => "Name does not exist or has no suitable associated IP addresses.", + ErrorCode::TemporaryResolverFailure => "A temporary failure in name resolution occurred.", + ErrorCode::PermanentResolverFailure => "A permanent failure in name resolution occurred.", + } + } + } + impl ::core::fmt::Debug for ErrorCode { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ErrorCode") + .field("code", &(*self as i32)) + .field("name", &self.name()) + .field("message", &self.message()) + .finish() + } + } + impl ::core::fmt::Display for ErrorCode { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "{} (error {})", self.name(), *self as i32) + } + } + + impl std::error::Error for ErrorCode {} + + impl ErrorCode { + pub(crate) unsafe fn _lift(val: u8) -> ErrorCode { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => ErrorCode::Unknown, + 1 => ErrorCode::AccessDenied, + 2 => ErrorCode::NotSupported, + 3 => ErrorCode::InvalidArgument, + 4 => ErrorCode::OutOfMemory, + 5 => ErrorCode::Timeout, + 6 => ErrorCode::ConcurrencyConflict, + 7 => ErrorCode::NotInProgress, + 8 => ErrorCode::WouldBlock, + 9 => ErrorCode::InvalidState, + 10 => ErrorCode::NewSocketLimit, + 11 => ErrorCode::AddressNotBindable, + 12 => ErrorCode::AddressInUse, + 13 => ErrorCode::RemoteUnreachable, + 14 => ErrorCode::ConnectionRefused, + 15 => ErrorCode::ConnectionReset, + 16 => ErrorCode::ConnectionAborted, + 17 => ErrorCode::DatagramTooLarge, + 18 => ErrorCode::NameUnresolvable, + 19 => ErrorCode::TemporaryResolverFailure, + 20 => ErrorCode::PermanentResolverFailure, + + _ => panic!("invalid enum discriminant"), + } + } + } + + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum IpAddressFamily { + /// Similar to `AF_INET` in POSIX. + Ipv4, + /// Similar to `AF_INET6` in POSIX. + Ipv6, + } + impl ::core::fmt::Debug for IpAddressFamily { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + IpAddressFamily::Ipv4 => f.debug_tuple("IpAddressFamily::Ipv4").finish(), + IpAddressFamily::Ipv6 => f.debug_tuple("IpAddressFamily::Ipv6").finish(), + } + } + } + + impl IpAddressFamily { + pub(crate) unsafe fn _lift(val: u8) -> IpAddressFamily { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => IpAddressFamily::Ipv4, + 1 => IpAddressFamily::Ipv6, + + _ => panic!("invalid enum discriminant"), + } + } + } + + pub type Ipv4Address = (u8, u8, u8, u8); + pub type Ipv6Address = (u16, u16, u16, u16, u16, u16, u16, u16); + #[derive(Clone, Copy)] + pub enum IpAddress { + Ipv4(Ipv4Address), + Ipv6(Ipv6Address), + } + impl ::core::fmt::Debug for IpAddress { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + IpAddress::Ipv4(e) => f.debug_tuple("IpAddress::Ipv4").field(e).finish(), + IpAddress::Ipv6(e) => f.debug_tuple("IpAddress::Ipv6").field(e).finish(), + } + } + } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Ipv4SocketAddress { + /// sin_port + pub port: u16, + /// sin_addr + pub address: Ipv4Address, + } + impl ::core::fmt::Debug for Ipv4SocketAddress { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Ipv4SocketAddress") + .field("port", &self.port) + .field("address", &self.address) + .finish() + } + } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Ipv6SocketAddress { + /// sin6_port + pub port: u16, + /// sin6_flowinfo + pub flow_info: u32, + /// sin6_addr + pub address: Ipv6Address, + /// sin6_scope_id + pub scope_id: u32, + } + impl ::core::fmt::Debug for Ipv6SocketAddress { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Ipv6SocketAddress") + .field("port", &self.port) + .field("flow-info", &self.flow_info) + .field("address", &self.address) + .field("scope-id", &self.scope_id) + .finish() + } + } + #[derive(Clone, Copy)] + pub enum IpSocketAddress { + Ipv4(Ipv4SocketAddress), + Ipv6(Ipv6SocketAddress), + } + impl ::core::fmt::Debug for IpSocketAddress { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + IpSocketAddress::Ipv4(e) => { + f.debug_tuple("IpSocketAddress::Ipv4").field(e).finish() + } + IpSocketAddress::Ipv6(e) => { + f.debug_tuple("IpSocketAddress::Ipv6").field(e).finish() + } + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod instance_network { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + pub type Network = super::super::super::wasi::sockets::network::Network; + #[allow(unused_unsafe, clippy::all)] + /// Get a handle to the default network. + pub fn instance_network() -> Network { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/instance-network@0.2.0")] + extern "C" { + #[link_name = "instance-network"] + fn wit_import() -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import() -> i32 { + unreachable!() + } + let ret = wit_import(); + super::super::super::wasi::sockets::network::Network::from_handle(ret as u32) + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod udp { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + pub type Network = super::super::super::wasi::sockets::network::Network; + pub type ErrorCode = super::super::super::wasi::sockets::network::ErrorCode; + pub type IpSocketAddress = super::super::super::wasi::sockets::network::IpSocketAddress; + pub type IpAddressFamily = super::super::super::wasi::sockets::network::IpAddressFamily; + /// A received datagram. + #[derive(Clone)] + pub struct IncomingDatagram { + /// The payload. + /// + /// Theoretical max size: ~64 KiB. In practice, typically less than 1500 bytes. + pub data: _rt::Vec, + /// The source address. + /// + /// This field is guaranteed to match the remote address the stream was initialized with, if any. + /// + /// Equivalent to the `src_addr` out parameter of `recvfrom`. + pub remote_address: IpSocketAddress, + } + impl ::core::fmt::Debug for IncomingDatagram { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("IncomingDatagram") + .field("data", &self.data) + .field("remote-address", &self.remote_address) + .finish() + } + } + /// A datagram to be sent out. + #[derive(Clone)] + pub struct OutgoingDatagram { + /// The payload. + pub data: _rt::Vec, + /// The destination address. + /// + /// The requirements on this field depend on how the stream was initialized: + /// - with a remote address: this field must be None or match the stream's remote address exactly. + /// - without a remote address: this field is required. + /// + /// If this value is None, the send operation is equivalent to `send` in POSIX. Otherwise it is equivalent to `sendto`. + pub remote_address: Option, + } + impl ::core::fmt::Debug for OutgoingDatagram { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("OutgoingDatagram") + .field("data", &self.data) + .field("remote-address", &self.remote_address) + .finish() + } + } + /// A UDP socket handle. + + #[derive(Debug)] + #[repr(transparent)] + pub struct UdpSocket { + handle: _rt::Resource, + } + + impl UdpSocket { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for UdpSocket { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]udp-socket"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct IncomingDatagramStream { + handle: _rt::Resource, + } + + impl IncomingDatagramStream { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for IncomingDatagramStream { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]incoming-datagram-stream"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] + #[repr(transparent)] + pub struct OutgoingDatagramStream { + handle: _rt::Resource, + } + + impl OutgoingDatagramStream { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for OutgoingDatagramStream { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]outgoing-datagram-stream"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Bind the socket to a specific network on the provided IP address and port. + /// + /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which + /// network interface(s) to bind to. + /// If the port is zero, the socket will be bound to a random free port. + /// + /// # Typical errors + /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) + /// - `invalid-state`: The socket is already bound. (EINVAL) + /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) + /// - `address-in-use`: Address is already in use. (EADDRINUSE) + /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) + /// - `not-in-progress`: A `bind` operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// Unlike in POSIX, in WASI the bind operation is async. This enables + /// interactive WASI hosts to inject permission prompts. Runtimes that + /// don't want to make use of this ability can simply call the native + /// `bind` as part of either `start-bind` or `finish-bind`. + /// + /// # References + /// - + /// - + /// - + /// - + pub fn start_bind( + &self, + network: &Network, + local_address: IpSocketAddress, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + use super::super::super::wasi::sockets::network::IpSocketAddress as V4; + let ( + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ) = match local_address { + V4::Ipv4(e) => { + let super::super::super::wasi::sockets::network::Ipv4SocketAddress{ port:port0, address:address0, } = e; + let (t1_0, t1_1, t1_2, t1_3) = address0; + + ( + 0i32, + _rt::as_i32(port0), + _rt::as_i32(t1_0), + _rt::as_i32(t1_1), + _rt::as_i32(t1_2), + _rt::as_i32(t1_3), + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + ) + } + V4::Ipv6(e) => { + let super::super::super::wasi::sockets::network::Ipv6SocketAddress{ port:port2, flow_info:flow_info2, address:address2, scope_id:scope_id2, } = e; + let (t3_0, t3_1, t3_2, t3_3, t3_4, t3_5, t3_6, t3_7) = address2; + + ( + 1i32, + _rt::as_i32(port2), + _rt::as_i32(flow_info2), + _rt::as_i32(t3_0), + _rt::as_i32(t3_1), + _rt::as_i32(t3_2), + _rt::as_i32(t3_3), + _rt::as_i32(t3_4), + _rt::as_i32(t3_5), + _rt::as_i32(t3_6), + _rt::as_i32(t3_7), + _rt::as_i32(scope_id2), + ) + } + }; + let ptr6 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.start-bind"] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (network).handle() as i32, + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ptr6, + ); + let l7 = i32::from(*ptr6.add(0).cast::()); + match l7 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l8 = i32::from(*ptr6.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l8 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn finish_bind(&self) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.finish-bind"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Set up inbound & outbound communication channels, optionally to a specific peer. + /// + /// This function only changes the local socket configuration and does not generate any network traffic. + /// On success, the `remote-address` of the socket is updated. The `local-address` may be updated as well, + /// based on the best network path to `remote-address`. + /// + /// When a `remote-address` is provided, the returned streams are limited to communicating with that specific peer: + /// - `send` can only be used to send to this destination. + /// - `receive` will only return datagrams sent from the provided `remote-address`. + /// + /// This method may be called multiple times on the same socket to change its association, but + /// only the most recently returned pair of streams will be operational. Implementations may trap if + /// the streams returned by a previous invocation haven't been dropped yet before calling `stream` again. + /// + /// The POSIX equivalent in pseudo-code is: + /// ```text + /// if (was previously connected) { + /// connect(s, AF_UNSPEC) + /// } + /// if (remote_address is Some) { + /// connect(s, remote_address) + /// } + /// ``` + /// + /// Unlike in POSIX, the socket must already be explicitly bound. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-state`: The socket is not bound. + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// + /// # References + /// - + /// - + /// - + /// - + pub fn stream( + &self, + remote_address: Option, + ) -> Result<(IncomingDatagramStream, OutgoingDatagramStream), ErrorCode> + { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ( + result6_0, + result6_1, + result6_2, + result6_3, + result6_4, + result6_5, + result6_6, + result6_7, + result6_8, + result6_9, + result6_10, + result6_11, + result6_12, + ) = match remote_address { + Some(e) => { + use super::super::super::wasi::sockets::network::IpSocketAddress as V4; + let ( + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ) = match e { + V4::Ipv4(e) => { + let super::super::super::wasi::sockets::network::Ipv4SocketAddress{ port:port0, address:address0, } = e; + let (t1_0, t1_1, t1_2, t1_3) = address0; + + ( + 0i32, + _rt::as_i32(port0), + _rt::as_i32(t1_0), + _rt::as_i32(t1_1), + _rt::as_i32(t1_2), + _rt::as_i32(t1_3), + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + ) + } + V4::Ipv6(e) => { + let super::super::super::wasi::sockets::network::Ipv6SocketAddress{ port:port2, flow_info:flow_info2, address:address2, scope_id:scope_id2, } = e; + let (t3_0, t3_1, t3_2, t3_3, t3_4, t3_5, t3_6, t3_7) = + address2; + + ( + 1i32, + _rt::as_i32(port2), + _rt::as_i32(flow_info2), + _rt::as_i32(t3_0), + _rt::as_i32(t3_1), + _rt::as_i32(t3_2), + _rt::as_i32(t3_3), + _rt::as_i32(t3_4), + _rt::as_i32(t3_5), + _rt::as_i32(t3_6), + _rt::as_i32(t3_7), + _rt::as_i32(scope_id2), + ) + } + }; + + ( + 1i32, result5_0, result5_1, result5_2, result5_3, result5_4, + result5_5, result5_6, result5_7, result5_8, result5_9, + result5_10, result5_11, + ) + } + None => ( + 0i32, 0i32, 0i32, 0i32, 0i32, 0i32, 0i32, 0i32, 0i32, 0i32, 0i32, + 0i32, 0i32, + ), + }; + let ptr7 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.stream"] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + result6_0, + result6_1, + result6_2, + result6_3, + result6_4, + result6_5, + result6_6, + result6_7, + result6_8, + result6_9, + result6_10, + result6_11, + result6_12, + ptr7, + ); + let l8 = i32::from(*ptr7.add(0).cast::()); + match l8 { + 0 => { + let e = { + let l9 = *ptr7.add(4).cast::(); + let l10 = *ptr7.add(8).cast::(); + + ( + IncomingDatagramStream::from_handle(l9 as u32), + OutgoingDatagramStream::from_handle(l10 as u32), + ) + }; + Ok(e) + } + 1 => { + let e = { + let l11 = i32::from(*ptr7.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l11 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Get the current bound address. + /// + /// POSIX mentions: + /// > If the socket has not been bound to a local name, the value + /// > stored in the object pointed to by `address` is unspecified. + /// + /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. + /// + /// # References + /// - + /// - + /// - + /// - + pub fn local_address(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 36]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 36]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.local-address"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + use super::super::super::wasi::sockets::network::IpSocketAddress as V19; + let v19 = match l2 { + 0 => { + let e19 = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let l4 = i32::from(*ptr0.add(10).cast::()); + let l5 = i32::from(*ptr0.add(11).cast::()); + let l6 = i32::from(*ptr0.add(12).cast::()); + let l7 = i32::from(*ptr0.add(13).cast::()); + + super::super::super::wasi::sockets::network::Ipv4SocketAddress{ + port: l3 as u16, + address: (l4 as u8, l5 as u8, l6 as u8, l7 as u8), + } + }; + V19::Ipv4(e19) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + let e19 = { + let l8 = i32::from(*ptr0.add(8).cast::()); + let l9 = *ptr0.add(12).cast::(); + let l10 = i32::from(*ptr0.add(16).cast::()); + let l11 = i32::from(*ptr0.add(18).cast::()); + let l12 = i32::from(*ptr0.add(20).cast::()); + let l13 = i32::from(*ptr0.add(22).cast::()); + let l14 = i32::from(*ptr0.add(24).cast::()); + let l15 = i32::from(*ptr0.add(26).cast::()); + let l16 = i32::from(*ptr0.add(28).cast::()); + let l17 = i32::from(*ptr0.add(30).cast::()); + let l18 = *ptr0.add(32).cast::(); + + super::super::super::wasi::sockets::network::Ipv6SocketAddress{ + port: l8 as u16, + flow_info: l9 as u32, + address: (l10 as u16, l11 as u16, l12 as u16, l13 as u16, l14 as u16, l15 as u16, l16 as u16, l17 as u16), + scope_id: l18 as u32, + } + }; + V19::Ipv6(e19) + } + }; + + v19 + }; + Ok(e) + } + 1 => { + let e = { + let l20 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l20 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Get the address the socket is currently streaming to. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not streaming to a specific remote address. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + pub fn remote_address(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 36]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 36]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.remote-address"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + use super::super::super::wasi::sockets::network::IpSocketAddress as V19; + let v19 = match l2 { + 0 => { + let e19 = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let l4 = i32::from(*ptr0.add(10).cast::()); + let l5 = i32::from(*ptr0.add(11).cast::()); + let l6 = i32::from(*ptr0.add(12).cast::()); + let l7 = i32::from(*ptr0.add(13).cast::()); + + super::super::super::wasi::sockets::network::Ipv4SocketAddress{ + port: l3 as u16, + address: (l4 as u8, l5 as u8, l6 as u8, l7 as u8), + } + }; + V19::Ipv4(e19) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + let e19 = { + let l8 = i32::from(*ptr0.add(8).cast::()); + let l9 = *ptr0.add(12).cast::(); + let l10 = i32::from(*ptr0.add(16).cast::()); + let l11 = i32::from(*ptr0.add(18).cast::()); + let l12 = i32::from(*ptr0.add(20).cast::()); + let l13 = i32::from(*ptr0.add(22).cast::()); + let l14 = i32::from(*ptr0.add(24).cast::()); + let l15 = i32::from(*ptr0.add(26).cast::()); + let l16 = i32::from(*ptr0.add(28).cast::()); + let l17 = i32::from(*ptr0.add(30).cast::()); + let l18 = *ptr0.add(32).cast::(); + + super::super::super::wasi::sockets::network::Ipv6SocketAddress{ + port: l8 as u16, + flow_info: l9 as u32, + address: (l10 as u16, l11 as u16, l12 as u16, l13 as u16, l14 as u16, l15 as u16, l16 as u16, l17 as u16), + scope_id: l18 as u32, + } + }; + V19::Ipv6(e19) + } + }; + + v19 + }; + Ok(e) + } + 1 => { + let e = { + let l20 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l20 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Whether this is a IPv4 or IPv6 socket. + /// + /// Equivalent to the SO_DOMAIN socket option. + pub fn address_family(&self) -> IpAddressFamily { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.address-family"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::sockets::network::IpAddressFamily::_lift( + ret as u8, + ) + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The TTL value must be 1 or higher. + pub fn unicast_hop_limit(&self) -> Result { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.unicast-hop-limit"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + l2 as u8 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_unicast_hop_limit(&self, value: u8) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.set-unicast-hop-limit"] + fn wit_import(_: i32, _: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i32(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// The kernel buffer space reserved for sends/receives on this socket. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + pub fn receive_buffer_size(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.receive-buffer-size"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_receive_buffer_size(&self, value: u64) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.set-receive-buffer-size"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn send_buffer_size(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.send-buffer-size"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_send_buffer_size(&self, value: u64) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.set-send-buffer-size"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl UdpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the socket is ready for I/O. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]udp-socket.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl IncomingDatagramStream { + #[allow(unused_unsafe, clippy::all)] + /// Receive messages on the socket. + /// + /// This function attempts to receive up to `max-results` datagrams on the socket without blocking. + /// The returned list may contain fewer elements than requested, but never more. + /// + /// This function returns successfully with an empty list when either: + /// - `max-results` is 0, or: + /// - `max-results` is greater than 0, but no results are immediately available. + /// This function never returns `error(would-block)`. + /// + /// # Typical errors + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + /// - + pub fn receive( + &self, + max_results: u64, + ) -> Result<_rt::Vec, ErrorCode> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]incoming-datagram-stream.receive"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&max_results), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let base25 = l2; + let len25 = l3; + let mut result25 = _rt::Vec::with_capacity(len25); + for i in 0..len25 { + let base = base25.add(i * 40); + let e25 = { + let l4 = *base.add(0).cast::<*mut u8>(); + let l5 = *base.add(4).cast::(); + let len6 = l5; + let l7 = i32::from(*base.add(8).cast::()); + use super::super::super::wasi::sockets::network::IpSocketAddress as V24; + let v24 = match l7 { + 0 => { + let e24 = { + let l8 = + i32::from(*base.add(12).cast::()); + let l9 = + i32::from(*base.add(14).cast::()); + let l10 = + i32::from(*base.add(15).cast::()); + let l11 = + i32::from(*base.add(16).cast::()); + let l12 = + i32::from(*base.add(17).cast::()); + + super::super::super::wasi::sockets::network::Ipv4SocketAddress{ + port: l8 as u16, + address: (l9 as u8, l10 as u8, l11 as u8, l12 as u8), + } + }; + V24::Ipv4(e24) + } + n => { + debug_assert_eq!( + n, 1, + "invalid enum discriminant" + ); + let e24 = { + let l13 = + i32::from(*base.add(12).cast::()); + let l14 = *base.add(16).cast::(); + let l15 = + i32::from(*base.add(20).cast::()); + let l16 = + i32::from(*base.add(22).cast::()); + let l17 = + i32::from(*base.add(24).cast::()); + let l18 = + i32::from(*base.add(26).cast::()); + let l19 = + i32::from(*base.add(28).cast::()); + let l20 = + i32::from(*base.add(30).cast::()); + let l21 = + i32::from(*base.add(32).cast::()); + let l22 = + i32::from(*base.add(34).cast::()); + let l23 = *base.add(36).cast::(); + + super::super::super::wasi::sockets::network::Ipv6SocketAddress{ + port: l13 as u16, + flow_info: l14 as u32, + address: (l15 as u16, l16 as u16, l17 as u16, l18 as u16, l19 as u16, l20 as u16, l21 as u16, l22 as u16), + scope_id: l23 as u32, + } + }; + V24::Ipv6(e24) + } + }; + + IncomingDatagram { + data: _rt::Vec::from_raw_parts( + l4.cast(), + len6, + len6, + ), + remote_address: v24, + } + }; + result25.push(e25); + } + _rt::cabi_dealloc(base25, len25 * 40, 4); + + result25 + }; + Ok(e) + } + 1 => { + let e = { + let l26 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l26 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl IncomingDatagramStream { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the stream is ready to receive again. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]incoming-datagram-stream.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl OutgoingDatagramStream { + #[allow(unused_unsafe, clippy::all)] + /// Check readiness for sending. This function never blocks. + /// + /// Returns the number of datagrams permitted for the next call to `send`, + /// or an error. Calling `send` with more datagrams than this function has + /// permitted will trap. + /// + /// When this function returns ok(0), the `subscribe` pollable will + /// become ready when this function will report at least ok(1), or an + /// error. + /// + /// Never returns `would-block`. + pub fn check_send(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]outgoing-datagram-stream.check-send"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutgoingDatagramStream { + #[allow(unused_unsafe, clippy::all)] + /// Send messages on the socket. + /// + /// This function attempts to send all provided `datagrams` on the socket without blocking and + /// returns how many messages were actually sent (or queued for sending). This function never + /// returns `error(would-block)`. If none of the datagrams were able to be sent, `ok(0)` is returned. + /// + /// This function semantically behaves the same as iterating the `datagrams` list and sequentially + /// sending each individual datagram until either the end of the list has been reached or the first error occurred. + /// If at least one datagram has been sent successfully, this function never returns an error. + /// + /// If the input list is empty, the function returns `ok(0)`. + /// + /// Each call to `send` must be permitted by a preceding `check-send`. Implementations must trap if + /// either `check-send` was not called or `datagrams` contains more items than `check-send` permitted. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The socket is in "connected" mode and `remote-address` is `some` value that does not match the address passed to `stream`. (EISCONN) + /// - `invalid-argument`: The socket is not "connected" and no value for `remote-address` was provided. (EDESTADDRREQ) + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// - `datagram-too-large`: The datagram is too large. (EMSGSIZE) + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + /// - + pub fn send(&self, datagrams: &[OutgoingDatagram]) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let vec7 = datagrams; + let len7 = vec7.len(); + let layout7 = + _rt::alloc::Layout::from_size_align_unchecked(vec7.len() * 44, 4); + let result7 = if layout7.size() != 0 { + let ptr = _rt::alloc::alloc(layout7).cast::(); + if ptr.is_null() { + _rt::alloc::handle_alloc_error(layout7); + } + ptr + } else { + { + ::core::ptr::null_mut() + } + }; + for (i, e) in vec7.into_iter().enumerate() { + let base = result7.add(i * 44); + { + let OutgoingDatagram { + data: data0, + remote_address: remote_address0, + } = e; + let vec1 = data0; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + *base.add(4).cast::() = len1; + *base.add(0).cast::<*mut u8>() = ptr1.cast_mut(); + match remote_address0 { + Some(e) => { + *base.add(8).cast::() = (1i32) as u8; + use super::super::super::wasi::sockets::network::IpSocketAddress as V6; + match e { + V6::Ipv4(e) => { + *base.add(12).cast::() = (0i32) as u8; + let super::super::super::wasi::sockets::network::Ipv4SocketAddress{ port:port2, address:address2, } = e; + *base.add(16).cast::() = + (_rt::as_i32(port2)) as u16; + let (t3_0, t3_1, t3_2, t3_3) = address2; + *base.add(18).cast::() = + (_rt::as_i32(t3_0)) as u8; + *base.add(19).cast::() = + (_rt::as_i32(t3_1)) as u8; + *base.add(20).cast::() = + (_rt::as_i32(t3_2)) as u8; + *base.add(21).cast::() = + (_rt::as_i32(t3_3)) as u8; + } + V6::Ipv6(e) => { + *base.add(12).cast::() = (1i32) as u8; + let super::super::super::wasi::sockets::network::Ipv6SocketAddress{ port:port4, flow_info:flow_info4, address:address4, scope_id:scope_id4, } = e; + *base.add(16).cast::() = + (_rt::as_i32(port4)) as u16; + *base.add(20).cast::() = + _rt::as_i32(flow_info4); + let ( + t5_0, + t5_1, + t5_2, + t5_3, + t5_4, + t5_5, + t5_6, + t5_7, + ) = address4; + *base.add(24).cast::() = + (_rt::as_i32(t5_0)) as u16; + *base.add(26).cast::() = + (_rt::as_i32(t5_1)) as u16; + *base.add(28).cast::() = + (_rt::as_i32(t5_2)) as u16; + *base.add(30).cast::() = + (_rt::as_i32(t5_3)) as u16; + *base.add(32).cast::() = + (_rt::as_i32(t5_4)) as u16; + *base.add(34).cast::() = + (_rt::as_i32(t5_5)) as u16; + *base.add(36).cast::() = + (_rt::as_i32(t5_6)) as u16; + *base.add(38).cast::() = + (_rt::as_i32(t5_7)) as u16; + *base.add(40).cast::() = + _rt::as_i32(scope_id4); + } + } + } + None => { + *base.add(8).cast::() = (0i32) as u8; + } + }; + } + } + let ptr8 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]outgoing-datagram-stream.send"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, result7, len7, ptr8); + let l9 = i32::from(*ptr8.add(0).cast::()); + if layout7.size() != 0 { + _rt::alloc::dealloc(result7.cast(), layout7); + } + match l9 { + 0 => { + let e = { + let l10 = *ptr8.add(8).cast::(); + + l10 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l11 = i32::from(*ptr8.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l11 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl OutgoingDatagramStream { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the stream is ready to send again. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp@0.2.0")] + extern "C" { + #[link_name = "[method]outgoing-datagram-stream.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod udp_create_socket { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type ErrorCode = super::super::super::wasi::sockets::network::ErrorCode; + pub type IpAddressFamily = super::super::super::wasi::sockets::network::IpAddressFamily; + pub type UdpSocket = super::super::super::wasi::sockets::udp::UdpSocket; + #[allow(unused_unsafe, clippy::all)] + /// Create a new UDP socket. + /// + /// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX. + /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. + /// + /// This function does not require a network capability handle. This is considered to be safe because + /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind` is called, + /// the socket is effectively an in-memory configuration object, unable to communicate with the outside world. + /// + /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. + /// + /// # Typical errors + /// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) + /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) + /// + /// # References: + /// - + /// - + /// - + /// - + pub fn create_udp_socket( + address_family: IpAddressFamily, + ) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/udp-create-socket@0.2.0")] + extern "C" { + #[link_name = "create-udp-socket"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import(address_family.clone() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::sockets::udp::UdpSocket::from_handle( + l2 as u32, + ) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod tcp { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type InputStream = super::super::super::wasi::io::streams::InputStream; + pub type OutputStream = super::super::super::wasi::io::streams::OutputStream; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + pub type Duration = super::super::super::wasi::clocks::monotonic_clock::Duration; + pub type Network = super::super::super::wasi::sockets::network::Network; + pub type ErrorCode = super::super::super::wasi::sockets::network::ErrorCode; + pub type IpSocketAddress = super::super::super::wasi::sockets::network::IpSocketAddress; + pub type IpAddressFamily = super::super::super::wasi::sockets::network::IpAddressFamily; + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum ShutdownType { + /// Similar to `SHUT_RD` in POSIX. + Receive, + /// Similar to `SHUT_WR` in POSIX. + Send, + /// Similar to `SHUT_RDWR` in POSIX. + Both, + } + impl ::core::fmt::Debug for ShutdownType { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + ShutdownType::Receive => f.debug_tuple("ShutdownType::Receive").finish(), + ShutdownType::Send => f.debug_tuple("ShutdownType::Send").finish(), + ShutdownType::Both => f.debug_tuple("ShutdownType::Both").finish(), + } + } + } + + impl ShutdownType { + pub(crate) unsafe fn _lift(val: u8) -> ShutdownType { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => ShutdownType::Receive, + 1 => ShutdownType::Send, + 2 => ShutdownType::Both, + + _ => panic!("invalid enum discriminant"), + } + } + } + + /// A TCP socket resource. + /// + /// The socket can be in one of the following states: + /// - `unbound` + /// - `bind-in-progress` + /// - `bound` (See note below) + /// - `listen-in-progress` + /// - `listening` + /// - `connect-in-progress` + /// - `connected` + /// - `closed` + /// See + /// for a more information. + /// + /// Note: Except where explicitly mentioned, whenever this documentation uses + /// the term "bound" without backticks it actually means: in the `bound` state *or higher*. + /// (i.e. `bound`, `listen-in-progress`, `listening`, `connect-in-progress` or `connected`) + /// + /// In addition to the general error codes documented on the + /// `network::error-code` type, TCP socket methods may always return + /// `error(invalid-state)` when in the `closed` state. + + #[derive(Debug)] + #[repr(transparent)] + pub struct TcpSocket { + handle: _rt::Resource, + } + + impl TcpSocket { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for TcpSocket { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]tcp-socket"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Bind the socket to a specific network on the provided IP address and port. + /// + /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which + /// network interface(s) to bind to. + /// If the TCP/UDP port is zero, the socket will be bound to a random free port. + /// + /// Bind can be attempted multiple times on the same socket, even with + /// different arguments on each iteration. But never concurrently and + /// only as long as the previous bind failed. Once a bind succeeds, the + /// binding can't be changed anymore. + /// + /// # Typical errors + /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) + /// - `invalid-argument`: `local-address` is not a unicast address. (EINVAL) + /// - `invalid-argument`: `local-address` is an IPv4-mapped IPv6 address. (EINVAL) + /// - `invalid-state`: The socket is already bound. (EINVAL) + /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) + /// - `address-in-use`: Address is already in use. (EADDRINUSE) + /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) + /// - `not-in-progress`: A `bind` operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT + /// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR + /// socket option should be set implicitly on all platforms, except on Windows where this is the default behavior + /// and SO_REUSEADDR performs something different entirely. + /// + /// Unlike in POSIX, in WASI the bind operation is async. This enables + /// interactive WASI hosts to inject permission prompts. Runtimes that + /// don't want to make use of this ability can simply call the native + /// `bind` as part of either `start-bind` or `finish-bind`. + /// + /// # References + /// - + /// - + /// - + /// - + pub fn start_bind( + &self, + network: &Network, + local_address: IpSocketAddress, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + use super::super::super::wasi::sockets::network::IpSocketAddress as V4; + let ( + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ) = match local_address { + V4::Ipv4(e) => { + let super::super::super::wasi::sockets::network::Ipv4SocketAddress{ port:port0, address:address0, } = e; + let (t1_0, t1_1, t1_2, t1_3) = address0; + + ( + 0i32, + _rt::as_i32(port0), + _rt::as_i32(t1_0), + _rt::as_i32(t1_1), + _rt::as_i32(t1_2), + _rt::as_i32(t1_3), + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + ) + } + V4::Ipv6(e) => { + let super::super::super::wasi::sockets::network::Ipv6SocketAddress{ port:port2, flow_info:flow_info2, address:address2, scope_id:scope_id2, } = e; + let (t3_0, t3_1, t3_2, t3_3, t3_4, t3_5, t3_6, t3_7) = address2; + + ( + 1i32, + _rt::as_i32(port2), + _rt::as_i32(flow_info2), + _rt::as_i32(t3_0), + _rt::as_i32(t3_1), + _rt::as_i32(t3_2), + _rt::as_i32(t3_3), + _rt::as_i32(t3_4), + _rt::as_i32(t3_5), + _rt::as_i32(t3_6), + _rt::as_i32(t3_7), + _rt::as_i32(scope_id2), + ) + } + }; + let ptr6 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.start-bind"] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (network).handle() as i32, + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ptr6, + ); + let l7 = i32::from(*ptr6.add(0).cast::()); + match l7 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l8 = i32::from(*ptr6.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l8 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn finish_bind(&self) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.finish-bind"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Connect to a remote endpoint. + /// + /// On success: + /// - the socket is transitioned into the `connection` state. + /// - a pair of streams is returned that can be used to read & write to the connection + /// + /// After a failed connection attempt, the socket will be in the `closed` + /// state and the only valid action left is to `drop` the socket. A single + /// socket can not be used to connect more than once. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: `remote-address` is not a unicast address. (EINVAL, ENETUNREACH on Linux, EAFNOSUPPORT on MacOS) + /// - `invalid-argument`: `remote-address` is an IPv4-mapped IPv6 address. (EINVAL, EADDRNOTAVAIL on Illumos) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EADDRNOTAVAIL on Windows) + /// - `invalid-argument`: The socket is already attached to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`. + /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN) + /// - `invalid-state`: The socket is already in the `listening` state. (EOPNOTSUPP, EINVAL on Windows) + /// - `timeout`: Connection timed out. (ETIMEDOUT) + /// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED) + /// - `connection-reset`: The connection was reset. (ECONNRESET) + /// - `connection-aborted`: The connection was aborted. (ECONNABORTED) + /// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) + /// - `not-in-progress`: A connect operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// The POSIX equivalent of `start-connect` is the regular `connect` syscall. + /// Because all WASI sockets are non-blocking this is expected to return + /// EINPROGRESS, which should be translated to `ok()` in WASI. + /// + /// The POSIX equivalent of `finish-connect` is a `poll` for event `POLLOUT` + /// with a timeout of 0 on the socket descriptor. Followed by a check for + /// the `SO_ERROR` socket option, in case the poll signaled readiness. + /// + /// # References + /// - + /// - + /// - + /// - + pub fn start_connect( + &self, + network: &Network, + remote_address: IpSocketAddress, + ) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + use super::super::super::wasi::sockets::network::IpSocketAddress as V4; + let ( + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ) = match remote_address { + V4::Ipv4(e) => { + let super::super::super::wasi::sockets::network::Ipv4SocketAddress{ port:port0, address:address0, } = e; + let (t1_0, t1_1, t1_2, t1_3) = address0; + + ( + 0i32, + _rt::as_i32(port0), + _rt::as_i32(t1_0), + _rt::as_i32(t1_1), + _rt::as_i32(t1_2), + _rt::as_i32(t1_3), + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + 0i32, + ) + } + V4::Ipv6(e) => { + let super::super::super::wasi::sockets::network::Ipv6SocketAddress{ port:port2, flow_info:flow_info2, address:address2, scope_id:scope_id2, } = e; + let (t3_0, t3_1, t3_2, t3_3, t3_4, t3_5, t3_6, t3_7) = address2; + + ( + 1i32, + _rt::as_i32(port2), + _rt::as_i32(flow_info2), + _rt::as_i32(t3_0), + _rt::as_i32(t3_1), + _rt::as_i32(t3_2), + _rt::as_i32(t3_3), + _rt::as_i32(t3_4), + _rt::as_i32(t3_5), + _rt::as_i32(t3_6), + _rt::as_i32(t3_7), + _rt::as_i32(scope_id2), + ) + } + }; + let ptr6 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.start-connect"] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: i32, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + (self).handle() as i32, + (network).handle() as i32, + result5_0, + result5_1, + result5_2, + result5_3, + result5_4, + result5_5, + result5_6, + result5_7, + result5_8, + result5_9, + result5_10, + result5_11, + ptr6, + ); + let l7 = i32::from(*ptr6.add(0).cast::()); + match l7 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l8 = i32::from(*ptr6.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l8 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn finish_connect(&self) -> Result<(InputStream, OutputStream), ErrorCode> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.finish-connect"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + let l3 = *ptr0.add(8).cast::(); + + (super::super::super::wasi::io::streams::InputStream::from_handle(l2 as u32), super::super::super::wasi::io::streams::OutputStream::from_handle(l3 as u32)) + }; + Ok(e) + } + 1 => { + let e = { + let l4 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l4 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Start listening for new connections. + /// + /// Transitions the socket into the `listening` state. + /// + /// Unlike POSIX, the socket must already be explicitly bound. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. (EDESTADDRREQ) + /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN, EINVAL on BSD) + /// - `invalid-state`: The socket is already in the `listening` state. + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE) + /// - `not-in-progress`: A listen operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// Unlike in POSIX, in WASI the listen operation is async. This enables + /// interactive WASI hosts to inject permission prompts. Runtimes that + /// don't want to make use of this ability can simply call the native + /// `listen` as part of either `start-listen` or `finish-listen`. + /// + /// # References + /// - + /// - + /// - + /// - + pub fn start_listen(&self) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.start-listen"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn finish_listen(&self) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.finish-listen"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Accept a new client socket. + /// + /// The returned socket is bound and in the `connected` state. The following properties are inherited from the listener socket: + /// - `address-family` + /// - `keep-alive-enabled` + /// - `keep-alive-idle-time` + /// - `keep-alive-interval` + /// - `keep-alive-count` + /// - `hop-limit` + /// - `receive-buffer-size` + /// - `send-buffer-size` + /// + /// On success, this function returns the newly accepted client socket along with + /// a pair of streams that can be used to read & write to the connection. + /// + /// # Typical errors + /// - `invalid-state`: Socket is not in the `listening` state. (EINVAL) + /// - `would-block`: No pending connections at the moment. (EWOULDBLOCK, EAGAIN) + /// - `connection-aborted`: An incoming connection was pending, but was terminated by the client before this listener could accept it. (ECONNABORTED) + /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) + /// + /// # References + /// - + /// - + /// - + /// - + pub fn accept(&self) -> Result<(TcpSocket, InputStream, OutputStream), ErrorCode> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.accept"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + let l3 = *ptr0.add(8).cast::(); + let l4 = *ptr0.add(12).cast::(); + + (TcpSocket::from_handle(l2 as u32), super::super::super::wasi::io::streams::InputStream::from_handle(l3 as u32), super::super::super::wasi::io::streams::OutputStream::from_handle(l4 as u32)) + }; + Ok(e) + } + 1 => { + let e = { + let l5 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l5 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Get the bound local address. + /// + /// POSIX mentions: + /// > If the socket has not been bound to a local name, the value + /// > stored in the object pointed to by `address` is unspecified. + /// + /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. + /// + /// # References + /// - + /// - + /// - + /// - + pub fn local_address(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 36]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 36]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.local-address"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + use super::super::super::wasi::sockets::network::IpSocketAddress as V19; + let v19 = match l2 { + 0 => { + let e19 = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let l4 = i32::from(*ptr0.add(10).cast::()); + let l5 = i32::from(*ptr0.add(11).cast::()); + let l6 = i32::from(*ptr0.add(12).cast::()); + let l7 = i32::from(*ptr0.add(13).cast::()); + + super::super::super::wasi::sockets::network::Ipv4SocketAddress{ + port: l3 as u16, + address: (l4 as u8, l5 as u8, l6 as u8, l7 as u8), + } + }; + V19::Ipv4(e19) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + let e19 = { + let l8 = i32::from(*ptr0.add(8).cast::()); + let l9 = *ptr0.add(12).cast::(); + let l10 = i32::from(*ptr0.add(16).cast::()); + let l11 = i32::from(*ptr0.add(18).cast::()); + let l12 = i32::from(*ptr0.add(20).cast::()); + let l13 = i32::from(*ptr0.add(22).cast::()); + let l14 = i32::from(*ptr0.add(24).cast::()); + let l15 = i32::from(*ptr0.add(26).cast::()); + let l16 = i32::from(*ptr0.add(28).cast::()); + let l17 = i32::from(*ptr0.add(30).cast::()); + let l18 = *ptr0.add(32).cast::(); + + super::super::super::wasi::sockets::network::Ipv6SocketAddress{ + port: l8 as u16, + flow_info: l9 as u32, + address: (l10 as u16, l11 as u16, l12 as u16, l13 as u16, l14 as u16, l15 as u16, l16 as u16, l17 as u16), + scope_id: l18 as u32, + } + }; + V19::Ipv6(e19) + } + }; + + v19 + }; + Ok(e) + } + 1 => { + let e = { + let l20 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l20 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Get the remote address. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not connected to a remote address. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + pub fn remote_address(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 36]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 36]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.remote-address"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(4).cast::()); + use super::super::super::wasi::sockets::network::IpSocketAddress as V19; + let v19 = match l2 { + 0 => { + let e19 = { + let l3 = i32::from(*ptr0.add(8).cast::()); + let l4 = i32::from(*ptr0.add(10).cast::()); + let l5 = i32::from(*ptr0.add(11).cast::()); + let l6 = i32::from(*ptr0.add(12).cast::()); + let l7 = i32::from(*ptr0.add(13).cast::()); + + super::super::super::wasi::sockets::network::Ipv4SocketAddress{ + port: l3 as u16, + address: (l4 as u8, l5 as u8, l6 as u8, l7 as u8), + } + }; + V19::Ipv4(e19) + } + n => { + debug_assert_eq!(n, 1, "invalid enum discriminant"); + let e19 = { + let l8 = i32::from(*ptr0.add(8).cast::()); + let l9 = *ptr0.add(12).cast::(); + let l10 = i32::from(*ptr0.add(16).cast::()); + let l11 = i32::from(*ptr0.add(18).cast::()); + let l12 = i32::from(*ptr0.add(20).cast::()); + let l13 = i32::from(*ptr0.add(22).cast::()); + let l14 = i32::from(*ptr0.add(24).cast::()); + let l15 = i32::from(*ptr0.add(26).cast::()); + let l16 = i32::from(*ptr0.add(28).cast::()); + let l17 = i32::from(*ptr0.add(30).cast::()); + let l18 = *ptr0.add(32).cast::(); + + super::super::super::wasi::sockets::network::Ipv6SocketAddress{ + port: l8 as u16, + flow_info: l9 as u32, + address: (l10 as u16, l11 as u16, l12 as u16, l13 as u16, l14 as u16, l15 as u16, l16 as u16, l17 as u16), + scope_id: l18 as u32, + } + }; + V19::Ipv6(e19) + } + }; + + v19 + }; + Ok(e) + } + 1 => { + let e = { + let l20 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l20 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Whether the socket is in the `listening` state. + /// + /// Equivalent to the SO_ACCEPTCONN socket option. + pub fn is_listening(&self) -> bool { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.is-listening"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + _rt::bool_lift(ret as u8) + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Whether this is a IPv4 or IPv6 socket. + /// + /// Equivalent to the SO_DOMAIN socket option. + pub fn address_family(&self) -> IpAddressFamily { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.address-family"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::sockets::network::IpAddressFamily::_lift( + ret as u8, + ) + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Hints the desired listen queue size. Implementations are free to ignore this. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// + /// # Typical errors + /// - `not-supported`: (set) The platform does not support changing the backlog size after the initial listen. + /// - `invalid-argument`: (set) The provided value was 0. + /// - `invalid-state`: (set) The socket is in the `connect-in-progress` or `connected` state. + pub fn set_listen_backlog_size(&self, value: u64) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-listen-backlog-size"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Enables or disables keepalive. + /// + /// The keepalive behavior can be adjusted using: + /// - `keep-alive-idle-time` + /// - `keep-alive-interval` + /// - `keep-alive-count` + /// These properties can be configured while `keep-alive-enabled` is false, but only come into effect when `keep-alive-enabled` is true. + /// + /// Equivalent to the SO_KEEPALIVE socket option. + pub fn keep_alive_enabled(&self) -> Result { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.keep-alive-enabled"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + _rt::bool_lift(l2 as u8) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_keep_alive_enabled(&self, value: bool) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-keep-alive-enabled"] + fn wit_import(_: i32, _: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8) { + unreachable!() + } + wit_import( + (self).handle() as i32, + match &value { + true => 1, + false => 0, + }, + ptr0, + ); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Amount of time the connection has to be idle before TCP starts sending keepalive packets. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPIDLE socket option. (TCP_KEEPALIVE on MacOS) + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + pub fn keep_alive_idle_time(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.keep-alive-idle-time"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_keep_alive_idle_time(&self, value: Duration) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-keep-alive-idle-time"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// The time between keepalive packets. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPINTVL socket option. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + pub fn keep_alive_interval(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.keep-alive-interval"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_keep_alive_interval(&self, value: Duration) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-keep-alive-interval"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// The maximum amount of keepalive packets TCP should send before aborting the connection. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPCNT socket option. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + pub fn keep_alive_count(&self) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.keep-alive-count"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + l2 as u32 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_keep_alive_count(&self, value: u32) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-keep-alive-count"] + fn wit_import(_: i32, _: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i32(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The TTL value must be 1 or higher. + pub fn hop_limit(&self) -> Result { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.hop-limit"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + l2 as u8 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_hop_limit(&self, value: u8) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-hop-limit"] + fn wit_import(_: i32, _: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i32(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// The kernel buffer space reserved for sends/receives on this socket. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + pub fn receive_buffer_size(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.receive-buffer-size"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_receive_buffer_size(&self, value: u64) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-receive-buffer-size"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn send_buffer_size(&self) -> Result { + unsafe { + #[repr(align(8))] + struct RetArea([::core::mem::MaybeUninit; 16]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.send-buffer-size"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(8).cast::(); + + l2 as u64 + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(8).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + pub fn set_send_buffer_size(&self, value: u64) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.set-send-buffer-size"] + fn wit_import(_: i32, _: i64, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i64, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, _rt::as_i64(&value), ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which can be used to poll for, or block on, + /// completion of any of the asynchronous operations of this socket. + /// + /// When `finish-bind`, `finish-listen`, `finish-connect` or `accept` + /// return `error(would-block)`, this pollable can be used to wait for + /// their success or failure, after which the method can be retried. + /// + /// The pollable is not limited to the async operation that happens to be + /// in progress at the time of calling `subscribe` (if any). Theoretically, + /// `subscribe` only has to be called once per socket and can then be + /// (re)used for the remainder of the socket's lifetime. + /// + /// See + /// for a more information. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + impl TcpSocket { + #[allow(unused_unsafe, clippy::all)] + /// Initiate a graceful shutdown. + /// + /// - `receive`: The socket is not expecting to receive any data from + /// the peer. The `input-stream` associated with this socket will be + /// closed. Any data still in the receive queue at time of calling + /// this method will be discarded. + /// - `send`: The socket has no more data to send to the peer. The `output-stream` + /// associated with this socket will be closed and a FIN packet will be sent. + /// - `both`: Same effect as `receive` & `send` combined. + /// + /// This function is idempotent. Shutting a down a direction more than once + /// has no effect and returns `ok`. + /// + /// The shutdown function does not close (drop) the socket. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + pub fn shutdown(&self, shutdown_type: ShutdownType) -> Result<(), ErrorCode> { + unsafe { + #[repr(align(1))] + struct RetArea([::core::mem::MaybeUninit; 2]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 2]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp@0.2.0")] + extern "C" { + #[link_name = "[method]tcp-socket.shutdown"] + fn wit_import(_: i32, _: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, shutdown_type.clone() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = (); + Ok(e) + } + 1 => { + let e = { + let l2 = i32::from(*ptr0.add(1).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l2 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod tcp_create_socket { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type ErrorCode = super::super::super::wasi::sockets::network::ErrorCode; + pub type IpAddressFamily = super::super::super::wasi::sockets::network::IpAddressFamily; + pub type TcpSocket = super::super::super::wasi::sockets::tcp::TcpSocket; + #[allow(unused_unsafe, clippy::all)] + /// Create a new TCP socket. + /// + /// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX. + /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. + /// + /// This function does not require a network capability handle. This is considered to be safe because + /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect` + /// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world. + /// + /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. + /// + /// # Typical errors + /// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) + /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) + /// + /// # References + /// - + /// - + /// - + /// - + pub fn create_tcp_socket( + address_family: IpAddressFamily, + ) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/tcp-create-socket@0.2.0")] + extern "C" { + #[link_name = "create-tcp-socket"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import(address_family.clone() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = *ptr0.add(4).cast::(); + + super::super::super::wasi::sockets::tcp::TcpSocket::from_handle( + l2 as u32, + ) + }; + Ok(e) + } + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l3 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + + #[allow(dead_code, clippy::all)] + pub mod ip_name_lookup { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + pub type Pollable = super::super::super::wasi::io::poll::Pollable; + pub type Network = super::super::super::wasi::sockets::network::Network; + pub type ErrorCode = super::super::super::wasi::sockets::network::ErrorCode; + pub type IpAddress = super::super::super::wasi::sockets::network::IpAddress; + + #[derive(Debug)] + #[repr(transparent)] + pub struct ResolveAddressStream { + handle: _rt::Resource, + } + + impl ResolveAddressStream { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: _rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn take_handle(&self) -> u32 { + _rt::Resource::take_handle(&self.handle) + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + _rt::Resource::handle(&self.handle) + } + } + + unsafe impl _rt::WasmResource for ResolveAddressStream { + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "wasi:sockets/ip-name-lookup@0.2.0")] + extern "C" { + #[link_name = "[resource-drop]resolve-address-stream"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[allow(unused_unsafe, clippy::all)] + /// Resolve an internet host name to a list of IP addresses. + /// + /// Unicode domain names are automatically converted to ASCII using IDNA encoding. + /// If the input is an IP address string, the address is parsed and returned + /// as-is without making any external requests. + /// + /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. + /// + /// This function never blocks. It either immediately fails or immediately + /// returns successfully with a `resolve-address-stream` that can be used + /// to (asynchronously) fetch the results. + /// + /// # Typical errors + /// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address. + /// + /// # References: + /// - + /// - + /// - + /// - + pub fn resolve_addresses( + network: &Network, + name: &str, + ) -> Result { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 8]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 8]); + let vec0 = name; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let ptr1 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/ip-name-lookup@0.2.0")] + extern "C" { + #[link_name = "resolve-addresses"] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import((network).handle() as i32, ptr0.cast_mut(), len0, ptr1); + let l2 = i32::from(*ptr1.add(0).cast::()); + match l2 { + 0 => { + let e = { + let l3 = *ptr1.add(4).cast::(); + + ResolveAddressStream::from_handle(l3 as u32) + }; + Ok(e) + } + 1 => { + let e = { + let l4 = i32::from(*ptr1.add(4).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l4 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + impl ResolveAddressStream { + #[allow(unused_unsafe, clippy::all)] + /// Returns the next address from the resolver. + /// + /// This function should be called multiple times. On each call, it will + /// return the next address in connection order preference. If all + /// addresses have been exhausted, this function returns `none`. + /// + /// This function never returns IPv4-mapped IPv6 addresses. + /// + /// # Typical errors + /// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY) + /// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN) + /// - `permanent-resolver-failure`: A permanent failure in name resolution occurred. (EAI_FAIL) + /// - `would-block`: A result is not available yet. (EWOULDBLOCK, EAGAIN) + pub fn resolve_next_address(&self) -> Result, ErrorCode> { + unsafe { + #[repr(align(2))] + struct RetArea([::core::mem::MaybeUninit; 22]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 22]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/ip-name-lookup@0.2.0")] + extern "C" { + #[link_name = "[method]resolve-address-stream.resolve-next-address"] + fn wit_import(_: i32, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: *mut u8) { + unreachable!() + } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => { + let e = { + let l2 = i32::from(*ptr0.add(2).cast::()); + + match l2 { + 0 => None, + 1 => { + let e = { + let l3 = i32::from(*ptr0.add(4).cast::()); + use super::super::super::wasi::sockets::network::IpAddress as V16; + let v16 = match l3 { + 0 => { + let e16 = { + let l4 = i32::from( + *ptr0.add(6).cast::(), + ); + let l5 = i32::from( + *ptr0.add(7).cast::(), + ); + let l6 = i32::from( + *ptr0.add(8).cast::(), + ); + let l7 = i32::from( + *ptr0.add(9).cast::(), + ); + + (l4 as u8, l5 as u8, l6 as u8, l7 as u8) + }; + V16::Ipv4(e16) + } + n => { + debug_assert_eq!( + n, 1, + "invalid enum discriminant" + ); + let e16 = { + let l8 = i32::from( + *ptr0.add(6).cast::(), + ); + let l9 = i32::from( + *ptr0.add(8).cast::(), + ); + let l10 = i32::from( + *ptr0.add(10).cast::(), + ); + let l11 = i32::from( + *ptr0.add(12).cast::(), + ); + let l12 = i32::from( + *ptr0.add(14).cast::(), + ); + let l13 = i32::from( + *ptr0.add(16).cast::(), + ); + let l14 = i32::from( + *ptr0.add(18).cast::(), + ); + let l15 = i32::from( + *ptr0.add(20).cast::(), + ); + + ( + l8 as u16, l9 as u16, l10 as u16, + l11 as u16, l12 as u16, l13 as u16, + l14 as u16, l15 as u16, + ) + }; + V16::Ipv6(e16) + } + }; + + v16 + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + }; + Ok(e) + } + 1 => { + let e = { + let l17 = i32::from(*ptr0.add(2).cast::()); + + super::super::super::wasi::sockets::network::ErrorCode::_lift( + l17 as u8, + ) + }; + Err(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + impl ResolveAddressStream { + #[allow(unused_unsafe, clippy::all)] + /// Create a `pollable` which will resolve once the stream is ready for I/O. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + pub fn subscribe(&self) -> Pollable { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "wasi:sockets/ip-name-lookup@0.2.0")] + extern "C" { + #[link_name = "[method]resolve-address-stream.subscribe"] + fn wit_import(_: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32) -> i32 { + unreachable!() + } + let ret = wit_import((self).handle() as i32); + super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) + } + } + } + } + } +} +#[allow(dead_code)] +pub mod exports { + #[allow(dead_code)] + pub mod wasi { + #[allow(dead_code)] + pub mod cli { + #[allow(dead_code, clippy::all)] + pub mod run { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_run_cabi() -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::run(); + let result1 = match result0 { + Ok(_) => 0i32, + Err(_) => 1i32, + }; + result1 + } + pub trait Guest { + /// Run the program. + fn run() -> Result<(), ()>; + } + #[doc(hidden)] + + macro_rules! __export_wasi_cli_run_0_2_0_cabi{ + ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { + + #[export_name = "wasi:cli/run@0.2.0#run"] + unsafe extern "C" fn export_run() -> i32 { + $($path_to_types)*::_export_run_cabi::<$ty>() + } + };); + } + #[doc(hidden)] + pub(crate) use __export_wasi_cli_run_0_2_0_cabi; + } + } + } +} +mod _rt { + pub use alloc_crate::string::String; + pub use alloc_crate::vec::Vec; + pub unsafe fn string_lift(bytes: Vec) -> String { + if cfg!(debug_assertions) { + String::from_utf8(bytes).unwrap() + } else { + String::from_utf8_unchecked(bytes) + } + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr as *mut u8, layout); + } + pub unsafe fn invalid_enum_discriminant() -> T { + if cfg!(debug_assertions) { + panic!("invalid enum discriminant") + } else { + core::hint::unreachable_unchecked() + } + } + + use core::fmt; + use core::marker; + use core::sync::atomic::{AtomicU32, Ordering::Relaxed}; + + /// A type which represents a component model resource, either imported or + /// exported into this component. + /// + /// This is a low-level wrapper which handles the lifetime of the resource + /// (namely this has a destructor). The `T` provided defines the component model + /// intrinsics that this wrapper uses. + /// + /// One of the chief purposes of this type is to provide `Deref` implementations + /// to access the underlying data when it is owned. + /// + /// This type is primarily used in generated code for exported and imported + /// resources. + #[repr(transparent)] + pub struct Resource { + // NB: This would ideally be `u32` but it is not. The fact that this has + // interior mutability is not exposed in the API of this type except for the + // `take_handle` method which is supposed to in theory be private. + // + // This represents, almost all the time, a valid handle value. When it's + // invalid it's stored as `u32::MAX`. + handle: AtomicU32, + _marker: marker::PhantomData, + } + + /// A trait which all wasm resources implement, namely providing the ability to + /// drop a resource. + /// + /// This generally is implemented by generated code, not user-facing code. + pub unsafe trait WasmResource { + /// Invokes the `[resource-drop]...` intrinsic. + unsafe fn drop(handle: u32); + } + + impl Resource { + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + debug_assert!(handle != u32::MAX); + Self { + handle: AtomicU32::new(handle), + _marker: marker::PhantomData, + } + } + + /// Takes ownership of the handle owned by `resource`. + /// + /// Note that this ideally would be `into_handle` taking `Resource` by + /// ownership. The code generator does not enable that in all situations, + /// unfortunately, so this is provided instead. + /// + /// Also note that `take_handle` is in theory only ever called on values + /// owned by a generated function. For example a generated function might + /// take `Resource` as an argument but then call `take_handle` on a + /// reference to that argument. In that sense the dynamic nature of + /// `take_handle` should only be exposed internally to generated code, not + /// to user code. + #[doc(hidden)] + pub fn take_handle(resource: &Resource) -> u32 { + resource.handle.swap(u32::MAX, Relaxed) + } + + #[doc(hidden)] + pub fn handle(resource: &Resource) -> u32 { + resource.handle.load(Relaxed) + } + } + + impl fmt::Debug for Resource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Resource") + .field("handle", &self.handle) + .finish() + } + } + + impl Drop for Resource { + fn drop(&mut self) { + unsafe { + match self.handle.load(Relaxed) { + // If this handle was "taken" then don't do anything in the + // destructor. + u32::MAX => {} + + // ... but otherwise do actually destroy it with the imported + // component model intrinsic as defined through `T`. + other => T::drop(other), + } + } + } + } + pub unsafe fn bool_lift(val: u8) -> bool { + if cfg!(debug_assertions) { + match val { + 0 => false, + 1 => true, + _ => panic!("invalid bool discriminant"), + } + } else { + val != 0 + } + } + pub use alloc_crate::alloc; + + pub fn as_i64(t: T) -> i64 { + t.as_i64() + } + + pub trait AsI64 { + fn as_i64(self) -> i64; + } + + impl<'a, T: Copy + AsI64> AsI64 for &'a T { + fn as_i64(self) -> i64 { + (*self).as_i64() + } + } + + impl AsI64 for i64 { + #[inline] + fn as_i64(self) -> i64 { + self as i64 + } + } + + impl AsI64 for u64 { + #[inline] + fn as_i64(self) -> i64 { + self as i64 + } + } + + pub fn as_i32(t: T) -> i32 { + t.as_i32() + } + + pub trait AsI32 { + fn as_i32(self) -> i32; + } + + impl<'a, T: Copy + AsI32> AsI32 for &'a T { + fn as_i32(self) -> i32 { + (*self).as_i32() + } + } + + impl AsI32 for i32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for char { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for usize { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + extern crate alloc as alloc_crate; +} + +/// Generates `#[no_mangle]` functions to export the specified type as the +/// root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] + +macro_rules! __export_http_client_impl { + ($ty:ident) => (self::export!($ty with_types_in self);); + ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( + $($path_to_types_root)*::exports::wasi::cli::run::__export_wasi_cli_run_0_2_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::wasi::cli::run); + ) +} +#[doc(inline)] +pub(crate) use __export_http_client_impl as export; + +#[cfg(target_arch = "wasm32")] +#[link_section = "component-type:wit-bindgen:0.24.0:http-client:encoded world"] +#[doc(hidden)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 10805] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xb3S\x01A\x02\x01AI\x01\ +B\x0a\x01o\x02ss\x01p\0\x01@\0\0\x01\x04\0\x0fget-environment\x01\x02\x01ps\x01@\ +\0\0\x03\x04\0\x0dget-arguments\x01\x04\x01ks\x01@\0\0\x05\x04\0\x0binitial-cwd\x01\ +\x06\x03\x01\x1awasi:cli/environment@0.2.0\x05\0\x01B\x03\x01j\0\0\x01@\x01\x06s\ +tatus\0\x01\0\x04\0\x04exit\x01\x01\x03\x01\x13wasi:cli/exit@0.2.0\x05\x01\x01B\x04\ +\x04\0\x05error\x03\x01\x01h\0\x01@\x01\x04self\x01\0s\x04\0\x1d[method]error.to\ +-debug-string\x01\x02\x03\x01\x13wasi:io/error@0.2.0\x05\x02\x01B\x0a\x04\0\x08p\ +ollable\x03\x01\x01h\0\x01@\x01\x04self\x01\0\x7f\x04\0\x16[method]pollable.read\ +y\x01\x02\x01@\x01\x04self\x01\x01\0\x04\0\x16[method]pollable.block\x01\x03\x01\ +p\x01\x01py\x01@\x01\x02in\x04\0\x05\x04\0\x04poll\x01\x06\x03\x01\x12wasi:io/po\ +ll@0.2.0\x05\x03\x02\x03\0\x02\x05error\x02\x03\0\x03\x08pollable\x01B(\x02\x03\x02\ +\x01\x04\x04\0\x05error\x03\0\0\x02\x03\x02\x01\x05\x04\0\x08pollable\x03\0\x02\x01\ +i\x01\x01q\x02\x15last-operation-failed\x01\x04\0\x06closed\0\0\x04\0\x0cstream-\ +error\x03\0\x05\x04\0\x0cinput-stream\x03\x01\x04\0\x0doutput-stream\x03\x01\x01\ +h\x07\x01p}\x01j\x01\x0a\x01\x06\x01@\x02\x04self\x09\x03lenw\0\x0b\x04\0\x19[me\ +thod]input-stream.read\x01\x0c\x04\0\"[method]input-stream.blocking-read\x01\x0c\ +\x01j\x01w\x01\x06\x01@\x02\x04self\x09\x03lenw\0\x0d\x04\0\x19[method]input-str\ +eam.skip\x01\x0e\x04\0\"[method]input-stream.blocking-skip\x01\x0e\x01i\x03\x01@\ +\x01\x04self\x09\0\x0f\x04\0\x1e[method]input-stream.subscribe\x01\x10\x01h\x08\x01\ +@\x01\x04self\x11\0\x0d\x04\0![method]output-stream.check-write\x01\x12\x01j\0\x01\ +\x06\x01@\x02\x04self\x11\x08contents\x0a\0\x13\x04\0\x1b[method]output-stream.w\ +rite\x01\x14\x04\0.[method]output-stream.blocking-write-and-flush\x01\x14\x01@\x01\ +\x04self\x11\0\x13\x04\0\x1b[method]output-stream.flush\x01\x15\x04\0$[method]ou\ +tput-stream.blocking-flush\x01\x15\x01@\x01\x04self\x11\0\x0f\x04\0\x1f[method]o\ +utput-stream.subscribe\x01\x16\x01@\x02\x04self\x11\x03lenw\0\x13\x04\0\"[method\ +]output-stream.write-zeroes\x01\x17\x04\05[method]output-stream.blocking-write-z\ +eroes-and-flush\x01\x17\x01@\x03\x04self\x11\x03src\x09\x03lenw\0\x0d\x04\0\x1c[\ +method]output-stream.splice\x01\x18\x04\0%[method]output-stream.blocking-splice\x01\ +\x18\x03\x01\x15wasi:io/streams@0.2.0\x05\x06\x02\x03\0\x04\x0cinput-stream\x01B\ +\x05\x02\x03\x02\x01\x07\x04\0\x0cinput-stream\x03\0\0\x01i\x01\x01@\0\0\x02\x04\ +\0\x09get-stdin\x01\x03\x03\x01\x14wasi:cli/stdin@0.2.0\x05\x08\x02\x03\0\x04\x0d\ +output-stream\x01B\x05\x02\x03\x02\x01\x09\x04\0\x0doutput-stream\x03\0\0\x01i\x01\ +\x01@\0\0\x02\x04\0\x0aget-stdout\x01\x03\x03\x01\x15wasi:cli/stdout@0.2.0\x05\x0a\ +\x01B\x05\x02\x03\x02\x01\x09\x04\0\x0doutput-stream\x03\0\0\x01i\x01\x01@\0\0\x02\ +\x04\0\x0aget-stderr\x01\x03\x03\x01\x15wasi:cli/stderr@0.2.0\x05\x0b\x01B\x01\x04\ +\0\x0eterminal-input\x03\x01\x03\x01\x1dwasi:cli/terminal-input@0.2.0\x05\x0c\x01\ +B\x01\x04\0\x0fterminal-output\x03\x01\x03\x01\x1ewasi:cli/terminal-output@0.2.0\ +\x05\x0d\x02\x03\0\x08\x0eterminal-input\x01B\x06\x02\x03\x02\x01\x0e\x04\0\x0et\ +erminal-input\x03\0\0\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x12get-terminal-stdin\ +\x01\x04\x03\x01\x1dwasi:cli/terminal-stdin@0.2.0\x05\x0f\x02\x03\0\x09\x0ftermi\ +nal-output\x01B\x06\x02\x03\x02\x01\x10\x04\0\x0fterminal-output\x03\0\0\x01i\x01\ +\x01k\x02\x01@\0\0\x03\x04\0\x13get-terminal-stdout\x01\x04\x03\x01\x1ewasi:cli/\ +terminal-stdout@0.2.0\x05\x11\x01B\x06\x02\x03\x02\x01\x10\x04\0\x0fterminal-out\ +put\x03\0\0\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x13get-terminal-stderr\x01\x04\x03\ +\x01\x1ewasi:cli/terminal-stderr@0.2.0\x05\x12\x01B\x0f\x02\x03\x02\x01\x05\x04\0\ +\x08pollable\x03\0\0\x01w\x04\0\x07instant\x03\0\x02\x01w\x04\0\x08duration\x03\0\ +\x04\x01@\0\0\x03\x04\0\x03now\x01\x06\x01@\0\0\x05\x04\0\x0aresolution\x01\x07\x01\ +i\x01\x01@\x01\x04when\x03\0\x08\x04\0\x11subscribe-instant\x01\x09\x01@\x01\x04\ +when\x05\0\x08\x04\0\x12subscribe-duration\x01\x0a\x03\x01!wasi:clocks/monotonic\ +-clock@0.2.0\x05\x13\x01B\x05\x01r\x02\x07secondsw\x0bnanosecondsy\x04\0\x08date\ +time\x03\0\0\x01@\0\0\x01\x04\0\x03now\x01\x02\x04\0\x0aresolution\x01\x02\x03\x01\ +\x1cwasi:clocks/wall-clock@0.2.0\x05\x14\x02\x03\0\x04\x05error\x02\x03\0\x0e\x08\ +datetime\x01Br\x02\x03\x02\x01\x07\x04\0\x0cinput-stream\x03\0\0\x02\x03\x02\x01\ +\x09\x04\0\x0doutput-stream\x03\0\x02\x02\x03\x02\x01\x15\x04\0\x05error\x03\0\x04\ +\x02\x03\x02\x01\x16\x04\0\x08datetime\x03\0\x06\x01w\x04\0\x08filesize\x03\0\x08\ +\x01m\x08\x07unknown\x0cblock-device\x10character-device\x09directory\x04fifo\x0d\ +symbolic-link\x0cregular-file\x06socket\x04\0\x0fdescriptor-type\x03\0\x0a\x01n\x06\ +\x04read\x05write\x13file-integrity-sync\x13data-integrity-sync\x14requested-wri\ +te-sync\x10mutate-directory\x04\0\x10descriptor-flags\x03\0\x0c\x01n\x01\x0esyml\ +ink-follow\x04\0\x0apath-flags\x03\0\x0e\x01n\x04\x06create\x09directory\x09excl\ +usive\x08truncate\x04\0\x0aopen-flags\x03\0\x10\x01w\x04\0\x0alink-count\x03\0\x12\ +\x01k\x07\x01r\x06\x04type\x0b\x0alink-count\x13\x04size\x09\x15data-access-time\ +stamp\x14\x1bdata-modification-timestamp\x14\x17status-change-timestamp\x14\x04\0\ +\x0fdescriptor-stat\x03\0\x15\x01q\x03\x09no-change\0\0\x03now\0\0\x09timestamp\x01\ +\x07\0\x04\0\x0dnew-timestamp\x03\0\x17\x01r\x02\x04type\x0b\x04names\x04\0\x0fd\ +irectory-entry\x03\0\x19\x01m%\x06access\x0bwould-block\x07already\x0ebad-descri\ +ptor\x04busy\x08deadlock\x05quota\x05exist\x0efile-too-large\x15illegal-byte-seq\ +uence\x0bin-progress\x0binterrupted\x07invalid\x02io\x0cis-directory\x04loop\x0e\ +too-many-links\x0cmessage-size\x0dname-too-long\x09no-device\x08no-entry\x07no-l\ +ock\x13insufficient-memory\x12insufficient-space\x0dnot-directory\x09not-empty\x0f\ +not-recoverable\x0bunsupported\x06no-tty\x0eno-such-device\x08overflow\x0dnot-pe\ +rmitted\x04pipe\x09read-only\x0cinvalid-seek\x0etext-file-busy\x0ccross-device\x04\ +\0\x0aerror-code\x03\0\x1b\x01m\x06\x06normal\x0asequential\x06random\x09will-ne\ +ed\x09dont-need\x08no-reuse\x04\0\x06advice\x03\0\x1d\x01r\x02\x05lowerw\x05uppe\ +rw\x04\0\x13metadata-hash-value\x03\0\x1f\x04\0\x0adescriptor\x03\x01\x04\0\x16d\ +irectory-entry-stream\x03\x01\x01h!\x01i\x01\x01j\x01$\x01\x1c\x01@\x02\x04self#\ +\x06offset\x09\0%\x04\0\"[method]descriptor.read-via-stream\x01&\x01i\x03\x01j\x01\ +'\x01\x1c\x01@\x02\x04self#\x06offset\x09\0(\x04\0#[method]descriptor.write-via-\ +stream\x01)\x01@\x01\x04self#\0(\x04\0$[method]descriptor.append-via-stream\x01*\ +\x01j\0\x01\x1c\x01@\x04\x04self#\x06offset\x09\x06length\x09\x06advice\x1e\0+\x04\ +\0\x19[method]descriptor.advise\x01,\x01@\x01\x04self#\0+\x04\0\x1c[method]descr\ +iptor.sync-data\x01-\x01j\x01\x0d\x01\x1c\x01@\x01\x04self#\0.\x04\0\x1c[method]\ +descriptor.get-flags\x01/\x01j\x01\x0b\x01\x1c\x01@\x01\x04self#\00\x04\0\x1b[me\ +thod]descriptor.get-type\x011\x01@\x02\x04self#\x04size\x09\0+\x04\0\x1b[method]\ +descriptor.set-size\x012\x01@\x03\x04self#\x15data-access-timestamp\x18\x1bdata-\ +modification-timestamp\x18\0+\x04\0\x1c[method]descriptor.set-times\x013\x01p}\x01\ +o\x024\x7f\x01j\x015\x01\x1c\x01@\x03\x04self#\x06length\x09\x06offset\x09\06\x04\ +\0\x17[method]descriptor.read\x017\x01j\x01\x09\x01\x1c\x01@\x03\x04self#\x06buf\ +fer4\x06offset\x09\08\x04\0\x18[method]descriptor.write\x019\x01i\"\x01j\x01:\x01\ +\x1c\x01@\x01\x04self#\0;\x04\0![method]descriptor.read-directory\x01<\x04\0\x17\ +[method]descriptor.sync\x01-\x01@\x02\x04self#\x04paths\0+\x04\0&[method]descrip\ +tor.create-directory-at\x01=\x01j\x01\x16\x01\x1c\x01@\x01\x04self#\0>\x04\0\x17\ +[method]descriptor.stat\x01?\x01@\x03\x04self#\x0apath-flags\x0f\x04paths\0>\x04\ +\0\x1a[method]descriptor.stat-at\x01@\x01@\x05\x04self#\x0apath-flags\x0f\x04pat\ +hs\x15data-access-timestamp\x18\x1bdata-modification-timestamp\x18\0+\x04\0\x1f[\ +method]descriptor.set-times-at\x01A\x01@\x05\x04self#\x0eold-path-flags\x0f\x08o\ +ld-paths\x0enew-descriptor#\x08new-paths\0+\x04\0\x1a[method]descriptor.link-at\x01\ +B\x01i!\x01j\x01\xc3\0\x01\x1c\x01@\x05\x04self#\x0apath-flags\x0f\x04paths\x0ao\ +pen-flags\x11\x05flags\x0d\0\xc4\0\x04\0\x1a[method]descriptor.open-at\x01E\x01j\ +\x01s\x01\x1c\x01@\x02\x04self#\x04paths\0\xc6\0\x04\0\x1e[method]descriptor.rea\ +dlink-at\x01G\x04\0&[method]descriptor.remove-directory-at\x01=\x01@\x04\x04self\ +#\x08old-paths\x0enew-descriptor#\x08new-paths\0+\x04\0\x1c[method]descriptor.re\ +name-at\x01H\x01@\x03\x04self#\x08old-paths\x08new-paths\0+\x04\0\x1d[method]des\ +criptor.symlink-at\x01I\x04\0![method]descriptor.unlink-file-at\x01=\x01@\x02\x04\ +self#\x05other#\0\x7f\x04\0![method]descriptor.is-same-object\x01J\x01j\x01\x20\x01\ +\x1c\x01@\x01\x04self#\0\xcb\0\x04\0\x20[method]descriptor.metadata-hash\x01L\x01\ +@\x03\x04self#\x0apath-flags\x0f\x04paths\0\xcb\0\x04\0#[method]descriptor.metad\ +ata-hash-at\x01M\x01h\"\x01k\x1a\x01j\x01\xcf\0\x01\x1c\x01@\x01\x04self\xce\0\0\ +\xd0\0\x04\03[method]directory-entry-stream.read-directory-entry\x01Q\x01h\x05\x01\ +k\x1c\x01@\x01\x03err\xd2\0\0\xd3\0\x04\0\x15filesystem-error-code\x01T\x03\x01\x1b\ +wasi:filesystem/types@0.2.0\x05\x17\x02\x03\0\x0f\x0adescriptor\x01B\x07\x02\x03\ +\x02\x01\x18\x04\0\x0adescriptor\x03\0\0\x01i\x01\x01o\x02\x02s\x01p\x03\x01@\0\0\ +\x04\x04\0\x0fget-directories\x01\x05\x03\x01\x1ewasi:filesystem/preopens@0.2.0\x05\ +\x19\x01B\x11\x04\0\x07network\x03\x01\x01m\x15\x07unknown\x0daccess-denied\x0dn\ +ot-supported\x10invalid-argument\x0dout-of-memory\x07timeout\x14concurrency-conf\ +lict\x0fnot-in-progress\x0bwould-block\x0dinvalid-state\x10new-socket-limit\x14a\ +ddress-not-bindable\x0eaddress-in-use\x12remote-unreachable\x12connection-refuse\ +d\x10connection-reset\x12connection-aborted\x12datagram-too-large\x11name-unreso\ +lvable\x1atemporary-resolver-failure\x1apermanent-resolver-failure\x04\0\x0aerro\ +r-code\x03\0\x01\x01m\x02\x04ipv4\x04ipv6\x04\0\x11ip-address-family\x03\0\x03\x01\ +o\x04}}}}\x04\0\x0cipv4-address\x03\0\x05\x01o\x08{{{{{{{{\x04\0\x0cipv6-address\ +\x03\0\x07\x01q\x02\x04ipv4\x01\x06\0\x04ipv6\x01\x08\0\x04\0\x0aip-address\x03\0\ +\x09\x01r\x02\x04port{\x07address\x06\x04\0\x13ipv4-socket-address\x03\0\x0b\x01\ +r\x04\x04port{\x09flow-infoy\x07address\x08\x08scope-idy\x04\0\x13ipv6-socket-ad\ +dress\x03\0\x0d\x01q\x02\x04ipv4\x01\x0c\0\x04ipv6\x01\x0e\0\x04\0\x11ip-socket-\ +address\x03\0\x0f\x03\x01\x1awasi:sockets/network@0.2.0\x05\x1a\x02\x03\0\x11\x07\ +network\x01B\x05\x02\x03\x02\x01\x1b\x04\0\x07network\x03\0\0\x01i\x01\x01@\0\0\x02\ +\x04\0\x10instance-network\x01\x03\x03\x01#wasi:sockets/instance-network@0.2.0\x05\ +\x1c\x02\x03\0\x11\x0aerror-code\x02\x03\0\x11\x11ip-socket-address\x02\x03\0\x11\ +\x11ip-address-family\x01BD\x02\x03\x02\x01\x05\x04\0\x08pollable\x03\0\0\x02\x03\ +\x02\x01\x1b\x04\0\x07network\x03\0\x02\x02\x03\x02\x01\x1d\x04\0\x0aerror-code\x03\ +\0\x04\x02\x03\x02\x01\x1e\x04\0\x11ip-socket-address\x03\0\x06\x02\x03\x02\x01\x1f\ +\x04\0\x11ip-address-family\x03\0\x08\x01p}\x01r\x02\x04data\x0a\x0eremote-addre\ +ss\x07\x04\0\x11incoming-datagram\x03\0\x0b\x01k\x07\x01r\x02\x04data\x0a\x0erem\ +ote-address\x0d\x04\0\x11outgoing-datagram\x03\0\x0e\x04\0\x0audp-socket\x03\x01\ +\x04\0\x18incoming-datagram-stream\x03\x01\x04\0\x18outgoing-datagram-stream\x03\ +\x01\x01h\x10\x01h\x03\x01j\0\x01\x05\x01@\x03\x04self\x13\x07network\x14\x0dloc\ +al-address\x07\0\x15\x04\0\x1d[method]udp-socket.start-bind\x01\x16\x01@\x01\x04\ +self\x13\0\x15\x04\0\x1e[method]udp-socket.finish-bind\x01\x17\x01i\x11\x01i\x12\ +\x01o\x02\x18\x19\x01j\x01\x1a\x01\x05\x01@\x02\x04self\x13\x0eremote-address\x0d\ +\0\x1b\x04\0\x19[method]udp-socket.stream\x01\x1c\x01j\x01\x07\x01\x05\x01@\x01\x04\ +self\x13\0\x1d\x04\0\x20[method]udp-socket.local-address\x01\x1e\x04\0![method]u\ +dp-socket.remote-address\x01\x1e\x01@\x01\x04self\x13\0\x09\x04\0![method]udp-so\ +cket.address-family\x01\x1f\x01j\x01}\x01\x05\x01@\x01\x04self\x13\0\x20\x04\0$[\ +method]udp-socket.unicast-hop-limit\x01!\x01@\x02\x04self\x13\x05value}\0\x15\x04\ +\0([method]udp-socket.set-unicast-hop-limit\x01\"\x01j\x01w\x01\x05\x01@\x01\x04\ +self\x13\0#\x04\0&[method]udp-socket.receive-buffer-size\x01$\x01@\x02\x04self\x13\ +\x05valuew\0\x15\x04\0*[method]udp-socket.set-receive-buffer-size\x01%\x04\0#[me\ +thod]udp-socket.send-buffer-size\x01$\x04\0'[method]udp-socket.set-send-buffer-s\ +ize\x01%\x01i\x01\x01@\x01\x04self\x13\0&\x04\0\x1c[method]udp-socket.subscribe\x01\ +'\x01h\x11\x01p\x0c\x01j\x01)\x01\x05\x01@\x02\x04self(\x0bmax-resultsw\0*\x04\0\ +([method]incoming-datagram-stream.receive\x01+\x01@\x01\x04self(\0&\x04\0*[metho\ +d]incoming-datagram-stream.subscribe\x01,\x01h\x12\x01@\x01\x04self-\0#\x04\0+[m\ +ethod]outgoing-datagram-stream.check-send\x01.\x01p\x0f\x01@\x02\x04self-\x09dat\ +agrams/\0#\x04\0%[method]outgoing-datagram-stream.send\x010\x01@\x01\x04self-\0&\ +\x04\0*[method]outgoing-datagram-stream.subscribe\x011\x03\x01\x16wasi:sockets/u\ +dp@0.2.0\x05\x20\x02\x03\0\x13\x0audp-socket\x01B\x0c\x02\x03\x02\x01\x1b\x04\0\x07\ +network\x03\0\0\x02\x03\x02\x01\x1d\x04\0\x0aerror-code\x03\0\x02\x02\x03\x02\x01\ +\x1f\x04\0\x11ip-address-family\x03\0\x04\x02\x03\x02\x01!\x04\0\x0audp-socket\x03\ +\0\x06\x01i\x07\x01j\x01\x08\x01\x03\x01@\x01\x0eaddress-family\x05\0\x09\x04\0\x11\ +create-udp-socket\x01\x0a\x03\x01$wasi:sockets/udp-create-socket@0.2.0\x05\"\x02\ +\x03\0\x0d\x08duration\x01BT\x02\x03\x02\x01\x07\x04\0\x0cinput-stream\x03\0\0\x02\ +\x03\x02\x01\x09\x04\0\x0doutput-stream\x03\0\x02\x02\x03\x02\x01\x05\x04\0\x08p\ +ollable\x03\0\x04\x02\x03\x02\x01#\x04\0\x08duration\x03\0\x06\x02\x03\x02\x01\x1b\ +\x04\0\x07network\x03\0\x08\x02\x03\x02\x01\x1d\x04\0\x0aerror-code\x03\0\x0a\x02\ +\x03\x02\x01\x1e\x04\0\x11ip-socket-address\x03\0\x0c\x02\x03\x02\x01\x1f\x04\0\x11\ +ip-address-family\x03\0\x0e\x01m\x03\x07receive\x04send\x04both\x04\0\x0dshutdow\ +n-type\x03\0\x10\x04\0\x0atcp-socket\x03\x01\x01h\x12\x01h\x09\x01j\0\x01\x0b\x01\ +@\x03\x04self\x13\x07network\x14\x0dlocal-address\x0d\0\x15\x04\0\x1d[method]tcp\ +-socket.start-bind\x01\x16\x01@\x01\x04self\x13\0\x15\x04\0\x1e[method]tcp-socke\ +t.finish-bind\x01\x17\x01@\x03\x04self\x13\x07network\x14\x0eremote-address\x0d\0\ +\x15\x04\0\x20[method]tcp-socket.start-connect\x01\x18\x01i\x01\x01i\x03\x01o\x02\ +\x19\x1a\x01j\x01\x1b\x01\x0b\x01@\x01\x04self\x13\0\x1c\x04\0![method]tcp-socke\ +t.finish-connect\x01\x1d\x04\0\x1f[method]tcp-socket.start-listen\x01\x17\x04\0\x20\ +[method]tcp-socket.finish-listen\x01\x17\x01i\x12\x01o\x03\x1e\x19\x1a\x01j\x01\x1f\ +\x01\x0b\x01@\x01\x04self\x13\0\x20\x04\0\x19[method]tcp-socket.accept\x01!\x01j\ +\x01\x0d\x01\x0b\x01@\x01\x04self\x13\0\"\x04\0\x20[method]tcp-socket.local-addr\ +ess\x01#\x04\0![method]tcp-socket.remote-address\x01#\x01@\x01\x04self\x13\0\x7f\ +\x04\0\x1f[method]tcp-socket.is-listening\x01$\x01@\x01\x04self\x13\0\x0f\x04\0!\ +[method]tcp-socket.address-family\x01%\x01@\x02\x04self\x13\x05valuew\0\x15\x04\0\ +*[method]tcp-socket.set-listen-backlog-size\x01&\x01j\x01\x7f\x01\x0b\x01@\x01\x04\ +self\x13\0'\x04\0%[method]tcp-socket.keep-alive-enabled\x01(\x01@\x02\x04self\x13\ +\x05value\x7f\0\x15\x04\0)[method]tcp-socket.set-keep-alive-enabled\x01)\x01j\x01\ +\x07\x01\x0b\x01@\x01\x04self\x13\0*\x04\0'[method]tcp-socket.keep-alive-idle-ti\ +me\x01+\x01@\x02\x04self\x13\x05value\x07\0\x15\x04\0+[method]tcp-socket.set-kee\ +p-alive-idle-time\x01,\x04\0&[method]tcp-socket.keep-alive-interval\x01+\x04\0*[\ +method]tcp-socket.set-keep-alive-interval\x01,\x01j\x01y\x01\x0b\x01@\x01\x04sel\ +f\x13\0-\x04\0#[method]tcp-socket.keep-alive-count\x01.\x01@\x02\x04self\x13\x05\ +valuey\0\x15\x04\0'[method]tcp-socket.set-keep-alive-count\x01/\x01j\x01}\x01\x0b\ +\x01@\x01\x04self\x13\00\x04\0\x1c[method]tcp-socket.hop-limit\x011\x01@\x02\x04\ +self\x13\x05value}\0\x15\x04\0\x20[method]tcp-socket.set-hop-limit\x012\x01j\x01\ +w\x01\x0b\x01@\x01\x04self\x13\03\x04\0&[method]tcp-socket.receive-buffer-size\x01\ +4\x04\0*[method]tcp-socket.set-receive-buffer-size\x01&\x04\0#[method]tcp-socket\ +.send-buffer-size\x014\x04\0'[method]tcp-socket.set-send-buffer-size\x01&\x01i\x05\ +\x01@\x01\x04self\x13\05\x04\0\x1c[method]tcp-socket.subscribe\x016\x01@\x02\x04\ +self\x13\x0dshutdown-type\x11\0\x15\x04\0\x1b[method]tcp-socket.shutdown\x017\x03\ +\x01\x16wasi:sockets/tcp@0.2.0\x05$\x02\x03\0\x15\x0atcp-socket\x01B\x0c\x02\x03\ +\x02\x01\x1b\x04\0\x07network\x03\0\0\x02\x03\x02\x01\x1d\x04\0\x0aerror-code\x03\ +\0\x02\x02\x03\x02\x01\x1f\x04\0\x11ip-address-family\x03\0\x04\x02\x03\x02\x01%\ +\x04\0\x0atcp-socket\x03\0\x06\x01i\x07\x01j\x01\x08\x01\x03\x01@\x01\x0eaddress\ +-family\x05\0\x09\x04\0\x11create-tcp-socket\x01\x0a\x03\x01$wasi:sockets/tcp-cr\ +eate-socket@0.2.0\x05&\x02\x03\0\x11\x0aip-address\x01B\x16\x02\x03\x02\x01\x05\x04\ +\0\x08pollable\x03\0\0\x02\x03\x02\x01\x1b\x04\0\x07network\x03\0\x02\x02\x03\x02\ +\x01\x1d\x04\0\x0aerror-code\x03\0\x04\x02\x03\x02\x01'\x04\0\x0aip-address\x03\0\ +\x06\x04\0\x16resolve-address-stream\x03\x01\x01h\x08\x01k\x07\x01j\x01\x0a\x01\x05\ +\x01@\x01\x04self\x09\0\x0b\x04\03[method]resolve-address-stream.resolve-next-ad\ +dress\x01\x0c\x01i\x01\x01@\x01\x04self\x09\0\x0d\x04\0([method]resolve-address-\ +stream.subscribe\x01\x0e\x01h\x03\x01i\x08\x01j\x01\x10\x01\x05\x01@\x02\x07netw\ +ork\x0f\x04names\0\x11\x04\0\x11resolve-addresses\x01\x12\x03\x01!wasi:sockets/i\ +p-name-lookup@0.2.0\x05(\x01B\x05\x01p}\x01@\x01\x03lenw\0\0\x04\0\x10get-random\ +-bytes\x01\x01\x01@\0\0w\x04\0\x0eget-random-u64\x01\x02\x03\x01\x18wasi:random/\ +random@0.2.0\x05)\x01B\x05\x01p}\x01@\x01\x03lenw\0\0\x04\0\x19get-insecure-rand\ +om-bytes\x01\x01\x01@\0\0w\x04\0\x17get-insecure-random-u64\x01\x02\x03\x01\x1aw\ +asi:random/insecure@0.2.0\x05*\x01B\x03\x01o\x02ww\x01@\0\0\0\x04\0\x0dinsecure-\ +seed\x01\x01\x03\x01\x1fwasi:random/insecure-seed@0.2.0\x05+\x01B\x03\x01j\0\0\x01\ +@\0\0\0\x04\0\x03run\x01\x01\x04\x01\x12wasi:cli/run@0.2.0\x05,\x04\x012iawia002\ +:wasi-http-client-test-program/http-client\x04\0\x0b\x11\x01\0\x0bhttp-client\x03\ +\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.202.0\x10wit-\ +bindgen-rust\x060.24.0"; + +#[inline(never)] +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/tests/program/src/lib.rs b/tests/program/src/lib.rs new file mode 100644 index 0000000..5457c2c --- /dev/null +++ b/tests/program/src/lib.rs @@ -0,0 +1,83 @@ +#[allow(warnings)] +mod bindings; + +use bindings::exports::wasi::cli::run::Guest; +use std::time::Duration; +use wasi_http_client::Client; + +struct Component; + +bindings::export!(Component with_types_in bindings); + +impl Guest for Component { + fn run() -> Result<(), ()> { + // get with query + let resp = Client::new() + .get("https://httpbin.org/get?a=b") + .send() + .unwrap(); + println!( + "GET https://httpbin.org/get, status code: {}, body:\n{}", + resp.status(), + String::from_utf8_lossy(resp.body()) + ); + + // post with json data + let resp = Client::new() + .post("https://httpbin.org/post") + .header("Content-Type", "application/json") + .unwrap() + .body("{\"data\": \"hello\"}".as_bytes()) + .connect_timeout(Duration::from_secs(5)) + .send() + .unwrap(); + println!( + "POST https://httpbin.org/post, status code: {}, body:\n{}", + resp.status(), + String::from_utf8_lossy(resp.body()) + ); + + // post with form data + let resp = Client::new() + .post("https://httpbin.org/post") + .header("Content-Type", "application/x-www-form-urlencoded") + .unwrap() + .body("a=b&c=".as_bytes()) + .connect_timeout(Duration::from_secs(5)) + .send() + .unwrap(); + println!( + "POST https://httpbin.org/post, status code: {}, body:\n{}", + resp.status(), + String::from_utf8_lossy(resp.body()) + ); + + // post with file form data + let resp = Client::new() + .post("https://httpbin.org/post") + .header("Content-Type", "multipart/form-data; boundary=boundary") + .unwrap() + .body( + "--boundary +Content-Disposition: form-data; name=field1 + +value1 +--boundary +Content-Disposition: form-data; name=field2; filename=file.txt +Content-Type: text/plain + +hello +--boundary--" + .as_bytes(), + ) + .connect_timeout(Duration::from_secs(5)) + .send() + .unwrap(); + println!( + "POST https://httpbin.org/post, status code: {}, body:\n{}", + resp.status(), + String::from_utf8_lossy(resp.body()) + ); + Ok(()) + } +} diff --git a/tests/program/wit/deps/cli/command.wit b/tests/program/wit/deps/cli/command.wit new file mode 100644 index 0000000..d8005bd --- /dev/null +++ b/tests/program/wit/deps/cli/command.wit @@ -0,0 +1,7 @@ +package wasi:cli@0.2.0; + +world command { + include imports; + + export run; +} diff --git a/tests/program/wit/deps/cli/environment.wit b/tests/program/wit/deps/cli/environment.wit new file mode 100644 index 0000000..7006523 --- /dev/null +++ b/tests/program/wit/deps/cli/environment.wit @@ -0,0 +1,18 @@ +interface environment { + /// Get the POSIX-style environment variables. + /// + /// Each environment variable is provided as a pair of string variable names + /// and string value. + /// + /// Morally, these are a value import, but until value imports are available + /// in the component model, this import function should return the same + /// values each time it is called. + get-environment: func() -> list>; + + /// Get the POSIX-style arguments to the program. + get-arguments: func() -> list; + + /// Return a path that programs should use as their initial current working + /// directory, interpreting `.` as shorthand for this. + initial-cwd: func() -> option; +} diff --git a/tests/program/wit/deps/cli/exit.wit b/tests/program/wit/deps/cli/exit.wit new file mode 100644 index 0000000..d0c2b82 --- /dev/null +++ b/tests/program/wit/deps/cli/exit.wit @@ -0,0 +1,4 @@ +interface exit { + /// Exit the current instance and any linked instances. + exit: func(status: result); +} diff --git a/tests/program/wit/deps/cli/imports.wit b/tests/program/wit/deps/cli/imports.wit new file mode 100644 index 0000000..083b84a --- /dev/null +++ b/tests/program/wit/deps/cli/imports.wit @@ -0,0 +1,20 @@ +package wasi:cli@0.2.0; + +world imports { + include wasi:clocks/imports@0.2.0; + include wasi:filesystem/imports@0.2.0; + include wasi:sockets/imports@0.2.0; + include wasi:random/imports@0.2.0; + include wasi:io/imports@0.2.0; + + import environment; + import exit; + import stdin; + import stdout; + import stderr; + import terminal-input; + import terminal-output; + import terminal-stdin; + import terminal-stdout; + import terminal-stderr; +} diff --git a/tests/program/wit/deps/cli/run.wit b/tests/program/wit/deps/cli/run.wit new file mode 100644 index 0000000..a70ee8c --- /dev/null +++ b/tests/program/wit/deps/cli/run.wit @@ -0,0 +1,4 @@ +interface run { + /// Run the program. + run: func() -> result; +} diff --git a/tests/program/wit/deps/cli/stdio.wit b/tests/program/wit/deps/cli/stdio.wit new file mode 100644 index 0000000..31ef35b --- /dev/null +++ b/tests/program/wit/deps/cli/stdio.wit @@ -0,0 +1,17 @@ +interface stdin { + use wasi:io/streams@0.2.0.{input-stream}; + + get-stdin: func() -> input-stream; +} + +interface stdout { + use wasi:io/streams@0.2.0.{output-stream}; + + get-stdout: func() -> output-stream; +} + +interface stderr { + use wasi:io/streams@0.2.0.{output-stream}; + + get-stderr: func() -> output-stream; +} diff --git a/tests/program/wit/deps/cli/terminal.wit b/tests/program/wit/deps/cli/terminal.wit new file mode 100644 index 0000000..38c724e --- /dev/null +++ b/tests/program/wit/deps/cli/terminal.wit @@ -0,0 +1,49 @@ +/// Terminal input. +/// +/// In the future, this may include functions for disabling echoing, +/// disabling input buffering so that keyboard events are sent through +/// immediately, querying supported features, and so on. +interface terminal-input { + /// The input side of a terminal. + resource terminal-input; +} + +/// Terminal output. +/// +/// In the future, this may include functions for querying the terminal +/// size, being notified of terminal size changes, querying supported +/// features, and so on. +interface terminal-output { + /// The output side of a terminal. + resource terminal-output; +} + +/// An interface providing an optional `terminal-input` for stdin as a +/// link-time authority. +interface terminal-stdin { + use terminal-input.{terminal-input}; + + /// If stdin is connected to a terminal, return a `terminal-input` handle + /// allowing further interaction with it. + get-terminal-stdin: func() -> option; +} + +/// An interface providing an optional `terminal-output` for stdout as a +/// link-time authority. +interface terminal-stdout { + use terminal-output.{terminal-output}; + + /// If stdout is connected to a terminal, return a `terminal-output` handle + /// allowing further interaction with it. + get-terminal-stdout: func() -> option; +} + +/// An interface providing an optional `terminal-output` for stderr as a +/// link-time authority. +interface terminal-stderr { + use terminal-output.{terminal-output}; + + /// If stderr is connected to a terminal, return a `terminal-output` handle + /// allowing further interaction with it. + get-terminal-stderr: func() -> option; +} diff --git a/tests/program/wit/deps/clocks/monotonic-clock.wit b/tests/program/wit/deps/clocks/monotonic-clock.wit new file mode 100644 index 0000000..4e4dc3a --- /dev/null +++ b/tests/program/wit/deps/clocks/monotonic-clock.wit @@ -0,0 +1,45 @@ +package wasi:clocks@0.2.0; +/// WASI Monotonic Clock is a clock API intended to let users measure elapsed +/// time. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A monotonic clock is a clock which has an unspecified initial value, and +/// successive reads of the clock will produce non-decreasing values. +/// +/// It is intended for measuring elapsed time. +interface monotonic-clock { + use wasi:io/poll@0.2.0.{pollable}; + + /// An instant in time, in nanoseconds. An instant is relative to an + /// unspecified initial value, and can only be compared to instances from + /// the same monotonic-clock. + type instant = u64; + + /// A duration of time, in nanoseconds. + type duration = u64; + + /// Read the current value of the clock. + /// + /// The clock is monotonic, therefore calling this function repeatedly will + /// produce a sequence of non-decreasing values. + now: func() -> instant; + + /// Query the resolution of the clock. Returns the duration of time + /// corresponding to a clock tick. + resolution: func() -> duration; + + /// Create a `pollable` which will resolve once the specified instant + /// occured. + subscribe-instant: func( + when: instant, + ) -> pollable; + + /// Create a `pollable` which will resolve once the given duration has + /// elapsed, starting at the time at which this function was called. + /// occured. + subscribe-duration: func( + when: duration, + ) -> pollable; +} diff --git a/tests/program/wit/deps/clocks/wall-clock.wit b/tests/program/wit/deps/clocks/wall-clock.wit new file mode 100644 index 0000000..440ca0f --- /dev/null +++ b/tests/program/wit/deps/clocks/wall-clock.wit @@ -0,0 +1,42 @@ +package wasi:clocks@0.2.0; +/// WASI Wall Clock is a clock API intended to let users query the current +/// time. The name "wall" makes an analogy to a "clock on the wall", which +/// is not necessarily monotonic as it may be reset. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A wall clock is a clock which measures the date and time according to +/// some external reference. +/// +/// External references may be reset, so this clock is not necessarily +/// monotonic, making it unsuitable for measuring elapsed time. +/// +/// It is intended for reporting the current date and time for humans. +interface wall-clock { + /// A time and date in seconds plus nanoseconds. + record datetime { + seconds: u64, + nanoseconds: u32, + } + + /// Read the current value of the clock. + /// + /// This clock is not monotonic, therefore calling this function repeatedly + /// will not necessarily produce a sequence of non-decreasing values. + /// + /// The returned timestamps represent the number of seconds since + /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], + /// also known as [Unix Time]. + /// + /// The nanoseconds field of the output is always less than 1000000000. + /// + /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 + /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time + now: func() -> datetime; + + /// Query the resolution of the clock. + /// + /// The nanoseconds field of the output is always less than 1000000000. + resolution: func() -> datetime; +} diff --git a/tests/program/wit/deps/clocks/world.wit b/tests/program/wit/deps/clocks/world.wit new file mode 100644 index 0000000..c022457 --- /dev/null +++ b/tests/program/wit/deps/clocks/world.wit @@ -0,0 +1,6 @@ +package wasi:clocks@0.2.0; + +world imports { + import monotonic-clock; + import wall-clock; +} diff --git a/tests/program/wit/deps/filesystem/preopens.wit b/tests/program/wit/deps/filesystem/preopens.wit new file mode 100644 index 0000000..da801f6 --- /dev/null +++ b/tests/program/wit/deps/filesystem/preopens.wit @@ -0,0 +1,8 @@ +package wasi:filesystem@0.2.0; + +interface preopens { + use types.{descriptor}; + + /// Return the set of preopened directories, and their path. + get-directories: func() -> list>; +} diff --git a/tests/program/wit/deps/filesystem/types.wit b/tests/program/wit/deps/filesystem/types.wit new file mode 100644 index 0000000..11108fc --- /dev/null +++ b/tests/program/wit/deps/filesystem/types.wit @@ -0,0 +1,634 @@ +package wasi:filesystem@0.2.0; +/// WASI filesystem is a filesystem API primarily intended to let users run WASI +/// programs that access their files on their existing filesystems, without +/// significant overhead. +/// +/// It is intended to be roughly portable between Unix-family platforms and +/// Windows, though it does not hide many of the major differences. +/// +/// Paths are passed as interface-type `string`s, meaning they must consist of +/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain +/// paths which are not accessible by this API. +/// +/// The directory separator in WASI is always the forward-slash (`/`). +/// +/// All paths in WASI are relative paths, and are interpreted relative to a +/// `descriptor` referring to a base directory. If a `path` argument to any WASI +/// function starts with `/`, or if any step of resolving a `path`, including +/// `..` and symbolic link steps, reaches a directory outside of the base +/// directory, or reaches a symlink to an absolute or rooted path in the +/// underlying filesystem, the function fails with `error-code::not-permitted`. +/// +/// For more information about WASI path resolution and sandboxing, see +/// [WASI filesystem path resolution]. +/// +/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md +interface types { + use wasi:io/streams@0.2.0.{input-stream, output-stream, error}; + use wasi:clocks/wall-clock@0.2.0.{datetime}; + + /// File size or length of a region within a file. + type filesize = u64; + + /// The type of a filesystem object referenced by a descriptor. + /// + /// Note: This was called `filetype` in earlier versions of WASI. + enum descriptor-type { + /// The type of the descriptor or file is unknown or is different from + /// any of the other types specified. + unknown, + /// The descriptor refers to a block device inode. + block-device, + /// The descriptor refers to a character device inode. + character-device, + /// The descriptor refers to a directory inode. + directory, + /// The descriptor refers to a named pipe. + fifo, + /// The file refers to a symbolic link inode. + symbolic-link, + /// The descriptor refers to a regular file inode. + regular-file, + /// The descriptor refers to a socket. + socket, + } + + /// Descriptor flags. + /// + /// Note: This was called `fdflags` in earlier versions of WASI. + flags descriptor-flags { + /// Read mode: Data can be read. + read, + /// Write mode: Data can be written to. + write, + /// Request that writes be performed according to synchronized I/O file + /// integrity completion. The data stored in the file and the file's + /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + file-integrity-sync, + /// Request that writes be performed according to synchronized I/O data + /// integrity completion. Only the data stored in the file is + /// synchronized. This is similar to `O_DSYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + data-integrity-sync, + /// Requests that reads be performed at the same level of integrety + /// requested for writes. This is similar to `O_RSYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + requested-write-sync, + /// Mutating directories mode: Directory contents may be mutated. + /// + /// When this flag is unset on a descriptor, operations using the + /// descriptor which would create, rename, delete, modify the data or + /// metadata of filesystem objects, or obtain another handle which + /// would permit any of those, shall fail with `error-code::read-only` if + /// they would otherwise succeed. + /// + /// This may only be set on directories. + mutate-directory, + } + + /// File attributes. + /// + /// Note: This was called `filestat` in earlier versions of WASI. + record descriptor-stat { + /// File type. + %type: descriptor-type, + /// Number of hard links to the file. + link-count: link-count, + /// For regular files, the file size in bytes. For symbolic links, the + /// length in bytes of the pathname contained in the symbolic link. + size: filesize, + /// Last data access timestamp. + /// + /// If the `option` is none, the platform doesn't maintain an access + /// timestamp for this file. + data-access-timestamp: option, + /// Last data modification timestamp. + /// + /// If the `option` is none, the platform doesn't maintain a + /// modification timestamp for this file. + data-modification-timestamp: option, + /// Last file status-change timestamp. + /// + /// If the `option` is none, the platform doesn't maintain a + /// status-change timestamp for this file. + status-change-timestamp: option, + } + + /// Flags determining the method of how paths are resolved. + flags path-flags { + /// As long as the resolved path corresponds to a symbolic link, it is + /// expanded. + symlink-follow, + } + + /// Open flags used by `open-at`. + flags open-flags { + /// Create file if it does not exist, similar to `O_CREAT` in POSIX. + create, + /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. + directory, + /// Fail if file already exists, similar to `O_EXCL` in POSIX. + exclusive, + /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. + truncate, + } + + /// Number of hard links to an inode. + type link-count = u64; + + /// When setting a timestamp, this gives the value to set it to. + variant new-timestamp { + /// Leave the timestamp set to its previous value. + no-change, + /// Set the timestamp to the current time of the system clock associated + /// with the filesystem. + now, + /// Set the timestamp to the given value. + timestamp(datetime), + } + + /// A directory entry. + record directory-entry { + /// The type of the file referred to by this directory entry. + %type: descriptor-type, + + /// The name of the object. + name: string, + } + + /// Error codes returned by functions, similar to `errno` in POSIX. + /// Not all of these error codes are returned by the functions provided by this + /// API; some are used in higher-level library layers, and others are provided + /// merely for alignment with POSIX. + enum error-code { + /// Permission denied, similar to `EACCES` in POSIX. + access, + /// Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX. + would-block, + /// Connection already in progress, similar to `EALREADY` in POSIX. + already, + /// Bad descriptor, similar to `EBADF` in POSIX. + bad-descriptor, + /// Device or resource busy, similar to `EBUSY` in POSIX. + busy, + /// Resource deadlock would occur, similar to `EDEADLK` in POSIX. + deadlock, + /// Storage quota exceeded, similar to `EDQUOT` in POSIX. + quota, + /// File exists, similar to `EEXIST` in POSIX. + exist, + /// File too large, similar to `EFBIG` in POSIX. + file-too-large, + /// Illegal byte sequence, similar to `EILSEQ` in POSIX. + illegal-byte-sequence, + /// Operation in progress, similar to `EINPROGRESS` in POSIX. + in-progress, + /// Interrupted function, similar to `EINTR` in POSIX. + interrupted, + /// Invalid argument, similar to `EINVAL` in POSIX. + invalid, + /// I/O error, similar to `EIO` in POSIX. + io, + /// Is a directory, similar to `EISDIR` in POSIX. + is-directory, + /// Too many levels of symbolic links, similar to `ELOOP` in POSIX. + loop, + /// Too many links, similar to `EMLINK` in POSIX. + too-many-links, + /// Message too large, similar to `EMSGSIZE` in POSIX. + message-size, + /// Filename too long, similar to `ENAMETOOLONG` in POSIX. + name-too-long, + /// No such device, similar to `ENODEV` in POSIX. + no-device, + /// No such file or directory, similar to `ENOENT` in POSIX. + no-entry, + /// No locks available, similar to `ENOLCK` in POSIX. + no-lock, + /// Not enough space, similar to `ENOMEM` in POSIX. + insufficient-memory, + /// No space left on device, similar to `ENOSPC` in POSIX. + insufficient-space, + /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX. + not-directory, + /// Directory not empty, similar to `ENOTEMPTY` in POSIX. + not-empty, + /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX. + not-recoverable, + /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX. + unsupported, + /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX. + no-tty, + /// No such device or address, similar to `ENXIO` in POSIX. + no-such-device, + /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX. + overflow, + /// Operation not permitted, similar to `EPERM` in POSIX. + not-permitted, + /// Broken pipe, similar to `EPIPE` in POSIX. + pipe, + /// Read-only file system, similar to `EROFS` in POSIX. + read-only, + /// Invalid seek, similar to `ESPIPE` in POSIX. + invalid-seek, + /// Text file busy, similar to `ETXTBSY` in POSIX. + text-file-busy, + /// Cross-device link, similar to `EXDEV` in POSIX. + cross-device, + } + + /// File or memory access pattern advisory information. + enum advice { + /// The application has no advice to give on its behavior with respect + /// to the specified data. + normal, + /// The application expects to access the specified data sequentially + /// from lower offsets to higher offsets. + sequential, + /// The application expects to access the specified data in a random + /// order. + random, + /// The application expects to access the specified data in the near + /// future. + will-need, + /// The application expects that it will not access the specified data + /// in the near future. + dont-need, + /// The application expects to access the specified data once and then + /// not reuse it thereafter. + no-reuse, + } + + /// A 128-bit hash value, split into parts because wasm doesn't have a + /// 128-bit integer type. + record metadata-hash-value { + /// 64 bits of a 128-bit hash value. + lower: u64, + /// Another 64 bits of a 128-bit hash value. + upper: u64, + } + + /// A descriptor is a reference to a filesystem object, which may be a file, + /// directory, named pipe, special file, or other object on which filesystem + /// calls may be made. + resource descriptor { + /// Return a stream for reading from a file, if available. + /// + /// May fail with an error-code describing why the file cannot be read. + /// + /// Multiple read, write, and append streams may be active on the same open + /// file and they do not interfere with each other. + /// + /// Note: This allows using `read-stream`, which is similar to `read` in POSIX. + read-via-stream: func( + /// The offset within the file at which to start reading. + offset: filesize, + ) -> result; + + /// Return a stream for writing to a file, if available. + /// + /// May fail with an error-code describing why the file cannot be written. + /// + /// Note: This allows using `write-stream`, which is similar to `write` in + /// POSIX. + write-via-stream: func( + /// The offset within the file at which to start writing. + offset: filesize, + ) -> result; + + /// Return a stream for appending to a file, if available. + /// + /// May fail with an error-code describing why the file cannot be appended. + /// + /// Note: This allows using `write-stream`, which is similar to `write` with + /// `O_APPEND` in in POSIX. + append-via-stream: func() -> result; + + /// Provide file advisory information on a descriptor. + /// + /// This is similar to `posix_fadvise` in POSIX. + advise: func( + /// The offset within the file to which the advisory applies. + offset: filesize, + /// The length of the region to which the advisory applies. + length: filesize, + /// The advice. + advice: advice + ) -> result<_, error-code>; + + /// Synchronize the data of a file to disk. + /// + /// This function succeeds with no effect if the file descriptor is not + /// opened for writing. + /// + /// Note: This is similar to `fdatasync` in POSIX. + sync-data: func() -> result<_, error-code>; + + /// Get flags associated with a descriptor. + /// + /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. + /// + /// Note: This returns the value that was the `fs_flags` value returned + /// from `fdstat_get` in earlier versions of WASI. + get-flags: func() -> result; + + /// Get the dynamic type of a descriptor. + /// + /// Note: This returns the same value as the `type` field of the `fd-stat` + /// returned by `stat`, `stat-at` and similar. + /// + /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided + /// by `fstat` in POSIX. + /// + /// Note: This returns the value that was the `fs_filetype` value returned + /// from `fdstat_get` in earlier versions of WASI. + get-type: func() -> result; + + /// Adjust the size of an open file. If this increases the file's size, the + /// extra bytes are filled with zeros. + /// + /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. + set-size: func(size: filesize) -> result<_, error-code>; + + /// Adjust the timestamps of an open file or directory. + /// + /// Note: This is similar to `futimens` in POSIX. + /// + /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. + set-times: func( + /// The desired values of the data access timestamp. + data-access-timestamp: new-timestamp, + /// The desired values of the data modification timestamp. + data-modification-timestamp: new-timestamp, + ) -> result<_, error-code>; + + /// Read from a descriptor, without using and updating the descriptor's offset. + /// + /// This function returns a list of bytes containing the data that was + /// read, along with a bool which, when true, indicates that the end of the + /// file was reached. The returned list will contain up to `length` bytes; it + /// may return fewer than requested, if the end of the file is reached or + /// if the I/O operation is interrupted. + /// + /// In the future, this may change to return a `stream`. + /// + /// Note: This is similar to `pread` in POSIX. + read: func( + /// The maximum number of bytes to read. + length: filesize, + /// The offset within the file at which to read. + offset: filesize, + ) -> result, bool>, error-code>; + + /// Write to a descriptor, without using and updating the descriptor's offset. + /// + /// It is valid to write past the end of a file; the file is extended to the + /// extent of the write, with bytes between the previous end and the start of + /// the write set to zero. + /// + /// In the future, this may change to take a `stream`. + /// + /// Note: This is similar to `pwrite` in POSIX. + write: func( + /// Data to write + buffer: list, + /// The offset within the file at which to write. + offset: filesize, + ) -> result; + + /// Read directory entries from a directory. + /// + /// On filesystems where directories contain entries referring to themselves + /// and their parents, often named `.` and `..` respectively, these entries + /// are omitted. + /// + /// This always returns a new stream which starts at the beginning of the + /// directory. Multiple streams may be active on the same directory, and they + /// do not interfere with each other. + read-directory: func() -> result; + + /// Synchronize the data and metadata of a file to disk. + /// + /// This function succeeds with no effect if the file descriptor is not + /// opened for writing. + /// + /// Note: This is similar to `fsync` in POSIX. + sync: func() -> result<_, error-code>; + + /// Create a directory. + /// + /// Note: This is similar to `mkdirat` in POSIX. + create-directory-at: func( + /// The relative path at which to create the directory. + path: string, + ) -> result<_, error-code>; + + /// Return the attributes of an open file or directory. + /// + /// Note: This is similar to `fstat` in POSIX, except that it does not return + /// device and inode information. For testing whether two descriptors refer to + /// the same underlying filesystem object, use `is-same-object`. To obtain + /// additional data that can be used do determine whether a file has been + /// modified, use `metadata-hash`. + /// + /// Note: This was called `fd_filestat_get` in earlier versions of WASI. + stat: func() -> result; + + /// Return the attributes of a file or directory. + /// + /// Note: This is similar to `fstatat` in POSIX, except that it does not + /// return device and inode information. See the `stat` description for a + /// discussion of alternatives. + /// + /// Note: This was called `path_filestat_get` in earlier versions of WASI. + stat-at: func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the file or directory to inspect. + path: string, + ) -> result; + + /// Adjust the timestamps of a file or directory. + /// + /// Note: This is similar to `utimensat` in POSIX. + /// + /// Note: This was called `path_filestat_set_times` in earlier versions of + /// WASI. + set-times-at: func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the file or directory to operate on. + path: string, + /// The desired values of the data access timestamp. + data-access-timestamp: new-timestamp, + /// The desired values of the data modification timestamp. + data-modification-timestamp: new-timestamp, + ) -> result<_, error-code>; + + /// Create a hard link. + /// + /// Note: This is similar to `linkat` in POSIX. + link-at: func( + /// Flags determining the method of how the path is resolved. + old-path-flags: path-flags, + /// The relative source path from which to link. + old-path: string, + /// The base directory for `new-path`. + new-descriptor: borrow, + /// The relative destination path at which to create the hard link. + new-path: string, + ) -> result<_, error-code>; + + /// Open a file or directory. + /// + /// The returned descriptor is not guaranteed to be the lowest-numbered + /// descriptor not currently open/ it is randomized to prevent applications + /// from depending on making assumptions about indexes, since this is + /// error-prone in multi-threaded contexts. The returned descriptor is + /// guaranteed to be less than 2**31. + /// + /// If `flags` contains `descriptor-flags::mutate-directory`, and the base + /// descriptor doesn't have `descriptor-flags::mutate-directory` set, + /// `open-at` fails with `error-code::read-only`. + /// + /// If `flags` contains `write` or `mutate-directory`, or `open-flags` + /// contains `truncate` or `create`, and the base descriptor doesn't have + /// `descriptor-flags::mutate-directory` set, `open-at` fails with + /// `error-code::read-only`. + /// + /// Note: This is similar to `openat` in POSIX. + open-at: func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the object to open. + path: string, + /// The method by which to open the file. + open-flags: open-flags, + /// Flags to use for the resulting descriptor. + %flags: descriptor-flags, + ) -> result; + + /// Read the contents of a symbolic link. + /// + /// If the contents contain an absolute or rooted path in the underlying + /// filesystem, this function fails with `error-code::not-permitted`. + /// + /// Note: This is similar to `readlinkat` in POSIX. + readlink-at: func( + /// The relative path of the symbolic link from which to read. + path: string, + ) -> result; + + /// Remove a directory. + /// + /// Return `error-code::not-empty` if the directory is not empty. + /// + /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. + remove-directory-at: func( + /// The relative path to a directory to remove. + path: string, + ) -> result<_, error-code>; + + /// Rename a filesystem object. + /// + /// Note: This is similar to `renameat` in POSIX. + rename-at: func( + /// The relative source path of the file or directory to rename. + old-path: string, + /// The base directory for `new-path`. + new-descriptor: borrow, + /// The relative destination path to which to rename the file or directory. + new-path: string, + ) -> result<_, error-code>; + + /// Create a symbolic link (also known as a "symlink"). + /// + /// If `old-path` starts with `/`, the function fails with + /// `error-code::not-permitted`. + /// + /// Note: This is similar to `symlinkat` in POSIX. + symlink-at: func( + /// The contents of the symbolic link. + old-path: string, + /// The relative destination path at which to create the symbolic link. + new-path: string, + ) -> result<_, error-code>; + + /// Unlink a filesystem object that is not a directory. + /// + /// Return `error-code::is-directory` if the path refers to a directory. + /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. + unlink-file-at: func( + /// The relative path to a file to unlink. + path: string, + ) -> result<_, error-code>; + + /// Test whether two descriptors refer to the same filesystem object. + /// + /// In POSIX, this corresponds to testing whether the two descriptors have the + /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. + /// wasi-filesystem does not expose device and inode numbers, so this function + /// may be used instead. + is-same-object: func(other: borrow) -> bool; + + /// Return a hash of the metadata associated with a filesystem object referred + /// to by a descriptor. + /// + /// This returns a hash of the last-modification timestamp and file size, and + /// may also include the inode number, device number, birth timestamp, and + /// other metadata fields that may change when the file is modified or + /// replaced. It may also include a secret value chosen by the + /// implementation and not otherwise exposed. + /// + /// Implementations are encourated to provide the following properties: + /// + /// - If the file is not modified or replaced, the computed hash value should + /// usually not change. + /// - If the object is modified or replaced, the computed hash value should + /// usually change. + /// - The inputs to the hash should not be easily computable from the + /// computed hash. + /// + /// However, none of these is required. + metadata-hash: func() -> result; + + /// Return a hash of the metadata associated with a filesystem object referred + /// to by a directory descriptor and a relative path. + /// + /// This performs the same hash computation as `metadata-hash`. + metadata-hash-at: func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the file or directory to inspect. + path: string, + ) -> result; + } + + /// A stream of directory entries. + resource directory-entry-stream { + /// Read a single directory entry from a `directory-entry-stream`. + read-directory-entry: func() -> result, error-code>; + } + + /// Attempts to extract a filesystem-related `error-code` from the stream + /// `error` provided. + /// + /// Stream operations which return `stream-error::last-operation-failed` + /// have a payload with more information about the operation that failed. + /// This payload can be passed through to this function to see if there's + /// filesystem-related information about the error to return. + /// + /// Note that this function is fallible because not all stream-related + /// errors are filesystem-related errors. + filesystem-error-code: func(err: borrow) -> option; +} diff --git a/tests/program/wit/deps/filesystem/world.wit b/tests/program/wit/deps/filesystem/world.wit new file mode 100644 index 0000000..663f579 --- /dev/null +++ b/tests/program/wit/deps/filesystem/world.wit @@ -0,0 +1,6 @@ +package wasi:filesystem@0.2.0; + +world imports { + import types; + import preopens; +} diff --git a/tests/program/wit/deps/io/error.wit b/tests/program/wit/deps/io/error.wit new file mode 100644 index 0000000..22e5b64 --- /dev/null +++ b/tests/program/wit/deps/io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.0; + + +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// provide functions to further "downcast" this error into more specific + /// error information. For example, `error`s returned in streams derived + /// from filesystem types to be described using the filesystem's own + /// error-code type, using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter + /// `borrow` and returns + /// `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + to-debug-string: func() -> string; + } +} diff --git a/tests/program/wit/deps/io/poll.wit b/tests/program/wit/deps/io/poll.wit new file mode 100644 index 0000000..ddc67f8 --- /dev/null +++ b/tests/program/wit/deps/io/poll.wit @@ -0,0 +1,41 @@ +package wasi:io@0.2.0; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// If the list contains more elements than can be indexed with a `u32` + /// value, this function traps. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being reaedy for I/O. + poll: func(in: list>) -> list; +} diff --git a/tests/program/wit/deps/io/streams.wit b/tests/program/wit/deps/io/streams.wit new file mode 100644 index 0000000..6d2f871 --- /dev/null +++ b/tests/program/wit/deps/io/streams.wit @@ -0,0 +1,262 @@ +package wasi:io@0.2.0; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +interface streams { + use error.{error}; + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occured. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivelant to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/tests/program/wit/deps/io/world.wit b/tests/program/wit/deps/io/world.wit new file mode 100644 index 0000000..5f0b43f --- /dev/null +++ b/tests/program/wit/deps/io/world.wit @@ -0,0 +1,6 @@ +package wasi:io@0.2.0; + +world imports { + import streams; + import poll; +} diff --git a/tests/program/wit/deps/random/insecure-seed.wit b/tests/program/wit/deps/random/insecure-seed.wit new file mode 100644 index 0000000..47210ac --- /dev/null +++ b/tests/program/wit/deps/random/insecure-seed.wit @@ -0,0 +1,25 @@ +package wasi:random@0.2.0; +/// The insecure-seed interface for seeding hash-map DoS resistance. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +interface insecure-seed { + /// Return a 128-bit value that may contain a pseudo-random value. + /// + /// The returned value is not required to be computed from a CSPRNG, and may + /// even be entirely deterministic. Host implementations are encouraged to + /// provide pseudo-random values to any program exposed to + /// attacker-controlled content, to enable DoS protection built into many + /// languages' hash-map implementations. + /// + /// This function is intended to only be called once, by a source language + /// to initialize Denial Of Service (DoS) protection in its hash-map + /// implementation. + /// + /// # Expected future evolution + /// + /// This will likely be changed to a value import, to prevent it from being + /// called multiple times and potentially used for purposes other than DoS + /// protection. + insecure-seed: func() -> tuple; +} diff --git a/tests/program/wit/deps/random/insecure.wit b/tests/program/wit/deps/random/insecure.wit new file mode 100644 index 0000000..c58f4ee --- /dev/null +++ b/tests/program/wit/deps/random/insecure.wit @@ -0,0 +1,22 @@ +package wasi:random@0.2.0; +/// The insecure interface for insecure pseudo-random numbers. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +interface insecure { + /// Return `len` insecure pseudo-random bytes. + /// + /// This function is not cryptographically secure. Do not use it for + /// anything related to security. + /// + /// There are no requirements on the values of the returned bytes, however + /// implementations are encouraged to return evenly distributed values with + /// a long period. + get-insecure-random-bytes: func(len: u64) -> list; + + /// Return an insecure pseudo-random `u64` value. + /// + /// This function returns the same type of pseudo-random data as + /// `get-insecure-random-bytes`, represented as a `u64`. + get-insecure-random-u64: func() -> u64; +} diff --git a/tests/program/wit/deps/random/random.wit b/tests/program/wit/deps/random/random.wit new file mode 100644 index 0000000..0c017f0 --- /dev/null +++ b/tests/program/wit/deps/random/random.wit @@ -0,0 +1,26 @@ +package wasi:random@0.2.0; +/// WASI Random is a random data API. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +interface random { + /// Return `len` cryptographically-secure random or pseudo-random bytes. + /// + /// This function must produce data at least as cryptographically secure and + /// fast as an adequately seeded cryptographically-secure pseudo-random + /// number generator (CSPRNG). It must not block, from the perspective of + /// the calling program, under any circumstances, including on the first + /// request and on requests for numbers of bytes. The returned data must + /// always be unpredictable. + /// + /// This function must always return fresh data. Deterministic environments + /// must omit this function, rather than implementing it with deterministic + /// data. + get-random-bytes: func(len: u64) -> list; + + /// Return a cryptographically-secure random or pseudo-random `u64` value. + /// + /// This function returns the same type of data as `get-random-bytes`, + /// represented as a `u64`. + get-random-u64: func() -> u64; +} diff --git a/tests/program/wit/deps/random/world.wit b/tests/program/wit/deps/random/world.wit new file mode 100644 index 0000000..3da3491 --- /dev/null +++ b/tests/program/wit/deps/random/world.wit @@ -0,0 +1,7 @@ +package wasi:random@0.2.0; + +world imports { + import random; + import insecure; + import insecure-seed; +} diff --git a/tests/program/wit/deps/sockets/instance-network.wit b/tests/program/wit/deps/sockets/instance-network.wit new file mode 100644 index 0000000..e455d0f --- /dev/null +++ b/tests/program/wit/deps/sockets/instance-network.wit @@ -0,0 +1,9 @@ + +/// This interface provides a value-export of the default network handle.. +interface instance-network { + use network.{network}; + + /// Get a handle to the default network. + instance-network: func() -> network; + +} diff --git a/tests/program/wit/deps/sockets/ip-name-lookup.wit b/tests/program/wit/deps/sockets/ip-name-lookup.wit new file mode 100644 index 0000000..8e639ec --- /dev/null +++ b/tests/program/wit/deps/sockets/ip-name-lookup.wit @@ -0,0 +1,51 @@ + +interface ip-name-lookup { + use wasi:io/poll@0.2.0.{pollable}; + use network.{network, error-code, ip-address}; + + + /// Resolve an internet host name to a list of IP addresses. + /// + /// Unicode domain names are automatically converted to ASCII using IDNA encoding. + /// If the input is an IP address string, the address is parsed and returned + /// as-is without making any external requests. + /// + /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. + /// + /// This function never blocks. It either immediately fails or immediately + /// returns successfully with a `resolve-address-stream` that can be used + /// to (asynchronously) fetch the results. + /// + /// # Typical errors + /// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address. + /// + /// # References: + /// - + /// - + /// - + /// - + resolve-addresses: func(network: borrow, name: string) -> result; + + resource resolve-address-stream { + /// Returns the next address from the resolver. + /// + /// This function should be called multiple times. On each call, it will + /// return the next address in connection order preference. If all + /// addresses have been exhausted, this function returns `none`. + /// + /// This function never returns IPv4-mapped IPv6 addresses. + /// + /// # Typical errors + /// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY) + /// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN) + /// - `permanent-resolver-failure`: A permanent failure in name resolution occurred. (EAI_FAIL) + /// - `would-block`: A result is not available yet. (EWOULDBLOCK, EAGAIN) + resolve-next-address: func() -> result, error-code>; + + /// Create a `pollable` which will resolve once the stream is ready for I/O. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + subscribe: func() -> pollable; + } +} diff --git a/tests/program/wit/deps/sockets/network.wit b/tests/program/wit/deps/sockets/network.wit new file mode 100644 index 0000000..9cadf06 --- /dev/null +++ b/tests/program/wit/deps/sockets/network.wit @@ -0,0 +1,145 @@ + +interface network { + /// An opaque resource that represents access to (a subset of) the network. + /// This enables context-based security for networking. + /// There is no need for this to map 1:1 to a physical network interface. + resource network; + + /// Error codes. + /// + /// In theory, every API can return any error code. + /// In practice, API's typically only return the errors documented per API + /// combined with a couple of errors that are always possible: + /// - `unknown` + /// - `access-denied` + /// - `not-supported` + /// - `out-of-memory` + /// - `concurrency-conflict` + /// + /// See each individual API for what the POSIX equivalents are. They sometimes differ per API. + enum error-code { + /// Unknown error + unknown, + + /// Access denied. + /// + /// POSIX equivalent: EACCES, EPERM + access-denied, + + /// The operation is not supported. + /// + /// POSIX equivalent: EOPNOTSUPP + not-supported, + + /// One of the arguments is invalid. + /// + /// POSIX equivalent: EINVAL + invalid-argument, + + /// Not enough memory to complete the operation. + /// + /// POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY + out-of-memory, + + /// The operation timed out before it could finish completely. + timeout, + + /// This operation is incompatible with another asynchronous operation that is already in progress. + /// + /// POSIX equivalent: EALREADY + concurrency-conflict, + + /// Trying to finish an asynchronous operation that: + /// - has not been started yet, or: + /// - was already finished by a previous `finish-*` call. + /// + /// Note: this is scheduled to be removed when `future`s are natively supported. + not-in-progress, + + /// The operation has been aborted because it could not be completed immediately. + /// + /// Note: this is scheduled to be removed when `future`s are natively supported. + would-block, + + + /// The operation is not valid in the socket's current state. + invalid-state, + + /// A new socket resource could not be created because of a system limit. + new-socket-limit, + + /// A bind operation failed because the provided address is not an address that the `network` can bind to. + address-not-bindable, + + /// A bind operation failed because the provided address is already in use or because there are no ephemeral ports available. + address-in-use, + + /// The remote address is not reachable + remote-unreachable, + + + /// The TCP connection was forcefully rejected + connection-refused, + + /// The TCP connection was reset. + connection-reset, + + /// A TCP connection was aborted. + connection-aborted, + + + /// The size of a datagram sent to a UDP socket exceeded the maximum + /// supported size. + datagram-too-large, + + + /// Name does not exist or has no suitable associated IP addresses. + name-unresolvable, + + /// A temporary failure in name resolution occurred. + temporary-resolver-failure, + + /// A permanent failure in name resolution occurred. + permanent-resolver-failure, + } + + enum ip-address-family { + /// Similar to `AF_INET` in POSIX. + ipv4, + + /// Similar to `AF_INET6` in POSIX. + ipv6, + } + + type ipv4-address = tuple; + type ipv6-address = tuple; + + variant ip-address { + ipv4(ipv4-address), + ipv6(ipv6-address), + } + + record ipv4-socket-address { + /// sin_port + port: u16, + /// sin_addr + address: ipv4-address, + } + + record ipv6-socket-address { + /// sin6_port + port: u16, + /// sin6_flowinfo + flow-info: u32, + /// sin6_addr + address: ipv6-address, + /// sin6_scope_id + scope-id: u32, + } + + variant ip-socket-address { + ipv4(ipv4-socket-address), + ipv6(ipv6-socket-address), + } + +} diff --git a/tests/program/wit/deps/sockets/tcp-create-socket.wit b/tests/program/wit/deps/sockets/tcp-create-socket.wit new file mode 100644 index 0000000..c7ddf1f --- /dev/null +++ b/tests/program/wit/deps/sockets/tcp-create-socket.wit @@ -0,0 +1,27 @@ + +interface tcp-create-socket { + use network.{network, error-code, ip-address-family}; + use tcp.{tcp-socket}; + + /// Create a new TCP socket. + /// + /// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX. + /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. + /// + /// This function does not require a network capability handle. This is considered to be safe because + /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect` + /// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world. + /// + /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. + /// + /// # Typical errors + /// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) + /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) + /// + /// # References + /// - + /// - + /// - + /// - + create-tcp-socket: func(address-family: ip-address-family) -> result; +} diff --git a/tests/program/wit/deps/sockets/tcp.wit b/tests/program/wit/deps/sockets/tcp.wit new file mode 100644 index 0000000..5902b9e --- /dev/null +++ b/tests/program/wit/deps/sockets/tcp.wit @@ -0,0 +1,353 @@ + +interface tcp { + use wasi:io/streams@0.2.0.{input-stream, output-stream}; + use wasi:io/poll@0.2.0.{pollable}; + use wasi:clocks/monotonic-clock@0.2.0.{duration}; + use network.{network, error-code, ip-socket-address, ip-address-family}; + + enum shutdown-type { + /// Similar to `SHUT_RD` in POSIX. + receive, + + /// Similar to `SHUT_WR` in POSIX. + send, + + /// Similar to `SHUT_RDWR` in POSIX. + both, + } + + /// A TCP socket resource. + /// + /// The socket can be in one of the following states: + /// - `unbound` + /// - `bind-in-progress` + /// - `bound` (See note below) + /// - `listen-in-progress` + /// - `listening` + /// - `connect-in-progress` + /// - `connected` + /// - `closed` + /// See + /// for a more information. + /// + /// Note: Except where explicitly mentioned, whenever this documentation uses + /// the term "bound" without backticks it actually means: in the `bound` state *or higher*. + /// (i.e. `bound`, `listen-in-progress`, `listening`, `connect-in-progress` or `connected`) + /// + /// In addition to the general error codes documented on the + /// `network::error-code` type, TCP socket methods may always return + /// `error(invalid-state)` when in the `closed` state. + resource tcp-socket { + /// Bind the socket to a specific network on the provided IP address and port. + /// + /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which + /// network interface(s) to bind to. + /// If the TCP/UDP port is zero, the socket will be bound to a random free port. + /// + /// Bind can be attempted multiple times on the same socket, even with + /// different arguments on each iteration. But never concurrently and + /// only as long as the previous bind failed. Once a bind succeeds, the + /// binding can't be changed anymore. + /// + /// # Typical errors + /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) + /// - `invalid-argument`: `local-address` is not a unicast address. (EINVAL) + /// - `invalid-argument`: `local-address` is an IPv4-mapped IPv6 address. (EINVAL) + /// - `invalid-state`: The socket is already bound. (EINVAL) + /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) + /// - `address-in-use`: Address is already in use. (EADDRINUSE) + /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) + /// - `not-in-progress`: A `bind` operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT + /// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR + /// socket option should be set implicitly on all platforms, except on Windows where this is the default behavior + /// and SO_REUSEADDR performs something different entirely. + /// + /// Unlike in POSIX, in WASI the bind operation is async. This enables + /// interactive WASI hosts to inject permission prompts. Runtimes that + /// don't want to make use of this ability can simply call the native + /// `bind` as part of either `start-bind` or `finish-bind`. + /// + /// # References + /// - + /// - + /// - + /// - + start-bind: func(network: borrow, local-address: ip-socket-address) -> result<_, error-code>; + finish-bind: func() -> result<_, error-code>; + + /// Connect to a remote endpoint. + /// + /// On success: + /// - the socket is transitioned into the `connection` state. + /// - a pair of streams is returned that can be used to read & write to the connection + /// + /// After a failed connection attempt, the socket will be in the `closed` + /// state and the only valid action left is to `drop` the socket. A single + /// socket can not be used to connect more than once. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: `remote-address` is not a unicast address. (EINVAL, ENETUNREACH on Linux, EAFNOSUPPORT on MacOS) + /// - `invalid-argument`: `remote-address` is an IPv4-mapped IPv6 address. (EINVAL, EADDRNOTAVAIL on Illumos) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EADDRNOTAVAIL on Windows) + /// - `invalid-argument`: The socket is already attached to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`. + /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN) + /// - `invalid-state`: The socket is already in the `listening` state. (EOPNOTSUPP, EINVAL on Windows) + /// - `timeout`: Connection timed out. (ETIMEDOUT) + /// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED) + /// - `connection-reset`: The connection was reset. (ECONNRESET) + /// - `connection-aborted`: The connection was aborted. (ECONNABORTED) + /// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) + /// - `not-in-progress`: A connect operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// The POSIX equivalent of `start-connect` is the regular `connect` syscall. + /// Because all WASI sockets are non-blocking this is expected to return + /// EINPROGRESS, which should be translated to `ok()` in WASI. + /// + /// The POSIX equivalent of `finish-connect` is a `poll` for event `POLLOUT` + /// with a timeout of 0 on the socket descriptor. Followed by a check for + /// the `SO_ERROR` socket option, in case the poll signaled readiness. + /// + /// # References + /// - + /// - + /// - + /// - + start-connect: func(network: borrow, remote-address: ip-socket-address) -> result<_, error-code>; + finish-connect: func() -> result, error-code>; + + /// Start listening for new connections. + /// + /// Transitions the socket into the `listening` state. + /// + /// Unlike POSIX, the socket must already be explicitly bound. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. (EDESTADDRREQ) + /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN, EINVAL on BSD) + /// - `invalid-state`: The socket is already in the `listening` state. + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE) + /// - `not-in-progress`: A listen operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// Unlike in POSIX, in WASI the listen operation is async. This enables + /// interactive WASI hosts to inject permission prompts. Runtimes that + /// don't want to make use of this ability can simply call the native + /// `listen` as part of either `start-listen` or `finish-listen`. + /// + /// # References + /// - + /// - + /// - + /// - + start-listen: func() -> result<_, error-code>; + finish-listen: func() -> result<_, error-code>; + + /// Accept a new client socket. + /// + /// The returned socket is bound and in the `connected` state. The following properties are inherited from the listener socket: + /// - `address-family` + /// - `keep-alive-enabled` + /// - `keep-alive-idle-time` + /// - `keep-alive-interval` + /// - `keep-alive-count` + /// - `hop-limit` + /// - `receive-buffer-size` + /// - `send-buffer-size` + /// + /// On success, this function returns the newly accepted client socket along with + /// a pair of streams that can be used to read & write to the connection. + /// + /// # Typical errors + /// - `invalid-state`: Socket is not in the `listening` state. (EINVAL) + /// - `would-block`: No pending connections at the moment. (EWOULDBLOCK, EAGAIN) + /// - `connection-aborted`: An incoming connection was pending, but was terminated by the client before this listener could accept it. (ECONNABORTED) + /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) + /// + /// # References + /// - + /// - + /// - + /// - + accept: func() -> result, error-code>; + + /// Get the bound local address. + /// + /// POSIX mentions: + /// > If the socket has not been bound to a local name, the value + /// > stored in the object pointed to by `address` is unspecified. + /// + /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. + /// + /// # References + /// - + /// - + /// - + /// - + local-address: func() -> result; + + /// Get the remote address. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not connected to a remote address. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + remote-address: func() -> result; + + /// Whether the socket is in the `listening` state. + /// + /// Equivalent to the SO_ACCEPTCONN socket option. + is-listening: func() -> bool; + + /// Whether this is a IPv4 or IPv6 socket. + /// + /// Equivalent to the SO_DOMAIN socket option. + address-family: func() -> ip-address-family; + + /// Hints the desired listen queue size. Implementations are free to ignore this. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// + /// # Typical errors + /// - `not-supported`: (set) The platform does not support changing the backlog size after the initial listen. + /// - `invalid-argument`: (set) The provided value was 0. + /// - `invalid-state`: (set) The socket is in the `connect-in-progress` or `connected` state. + set-listen-backlog-size: func(value: u64) -> result<_, error-code>; + + /// Enables or disables keepalive. + /// + /// The keepalive behavior can be adjusted using: + /// - `keep-alive-idle-time` + /// - `keep-alive-interval` + /// - `keep-alive-count` + /// These properties can be configured while `keep-alive-enabled` is false, but only come into effect when `keep-alive-enabled` is true. + /// + /// Equivalent to the SO_KEEPALIVE socket option. + keep-alive-enabled: func() -> result; + set-keep-alive-enabled: func(value: bool) -> result<_, error-code>; + + /// Amount of time the connection has to be idle before TCP starts sending keepalive packets. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPIDLE socket option. (TCP_KEEPALIVE on MacOS) + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + keep-alive-idle-time: func() -> result; + set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>; + + /// The time between keepalive packets. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPINTVL socket option. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + keep-alive-interval: func() -> result; + set-keep-alive-interval: func(value: duration) -> result<_, error-code>; + + /// The maximum amount of keepalive packets TCP should send before aborting the connection. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPCNT socket option. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + keep-alive-count: func() -> result; + set-keep-alive-count: func(value: u32) -> result<_, error-code>; + + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The TTL value must be 1 or higher. + hop-limit: func() -> result; + set-hop-limit: func(value: u8) -> result<_, error-code>; + + /// The kernel buffer space reserved for sends/receives on this socket. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + receive-buffer-size: func() -> result; + set-receive-buffer-size: func(value: u64) -> result<_, error-code>; + send-buffer-size: func() -> result; + set-send-buffer-size: func(value: u64) -> result<_, error-code>; + + /// Create a `pollable` which can be used to poll for, or block on, + /// completion of any of the asynchronous operations of this socket. + /// + /// When `finish-bind`, `finish-listen`, `finish-connect` or `accept` + /// return `error(would-block)`, this pollable can be used to wait for + /// their success or failure, after which the method can be retried. + /// + /// The pollable is not limited to the async operation that happens to be + /// in progress at the time of calling `subscribe` (if any). Theoretically, + /// `subscribe` only has to be called once per socket and can then be + /// (re)used for the remainder of the socket's lifetime. + /// + /// See + /// for a more information. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + subscribe: func() -> pollable; + + /// Initiate a graceful shutdown. + /// + /// - `receive`: The socket is not expecting to receive any data from + /// the peer. The `input-stream` associated with this socket will be + /// closed. Any data still in the receive queue at time of calling + /// this method will be discarded. + /// - `send`: The socket has no more data to send to the peer. The `output-stream` + /// associated with this socket will be closed and a FIN packet will be sent. + /// - `both`: Same effect as `receive` & `send` combined. + /// + /// This function is idempotent. Shutting a down a direction more than once + /// has no effect and returns `ok`. + /// + /// The shutdown function does not close (drop) the socket. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + shutdown: func(shutdown-type: shutdown-type) -> result<_, error-code>; + } +} diff --git a/tests/program/wit/deps/sockets/udp-create-socket.wit b/tests/program/wit/deps/sockets/udp-create-socket.wit new file mode 100644 index 0000000..0482d1f --- /dev/null +++ b/tests/program/wit/deps/sockets/udp-create-socket.wit @@ -0,0 +1,27 @@ + +interface udp-create-socket { + use network.{network, error-code, ip-address-family}; + use udp.{udp-socket}; + + /// Create a new UDP socket. + /// + /// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX. + /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. + /// + /// This function does not require a network capability handle. This is considered to be safe because + /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind` is called, + /// the socket is effectively an in-memory configuration object, unable to communicate with the outside world. + /// + /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. + /// + /// # Typical errors + /// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) + /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) + /// + /// # References: + /// - + /// - + /// - + /// - + create-udp-socket: func(address-family: ip-address-family) -> result; +} diff --git a/tests/program/wit/deps/sockets/udp.wit b/tests/program/wit/deps/sockets/udp.wit new file mode 100644 index 0000000..d987a0a --- /dev/null +++ b/tests/program/wit/deps/sockets/udp.wit @@ -0,0 +1,266 @@ + +interface udp { + use wasi:io/poll@0.2.0.{pollable}; + use network.{network, error-code, ip-socket-address, ip-address-family}; + + /// A received datagram. + record incoming-datagram { + /// The payload. + /// + /// Theoretical max size: ~64 KiB. In practice, typically less than 1500 bytes. + data: list, + + /// The source address. + /// + /// This field is guaranteed to match the remote address the stream was initialized with, if any. + /// + /// Equivalent to the `src_addr` out parameter of `recvfrom`. + remote-address: ip-socket-address, + } + + /// A datagram to be sent out. + record outgoing-datagram { + /// The payload. + data: list, + + /// The destination address. + /// + /// The requirements on this field depend on how the stream was initialized: + /// - with a remote address: this field must be None or match the stream's remote address exactly. + /// - without a remote address: this field is required. + /// + /// If this value is None, the send operation is equivalent to `send` in POSIX. Otherwise it is equivalent to `sendto`. + remote-address: option, + } + + + + /// A UDP socket handle. + resource udp-socket { + /// Bind the socket to a specific network on the provided IP address and port. + /// + /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which + /// network interface(s) to bind to. + /// If the port is zero, the socket will be bound to a random free port. + /// + /// # Typical errors + /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) + /// - `invalid-state`: The socket is already bound. (EINVAL) + /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) + /// - `address-in-use`: Address is already in use. (EADDRINUSE) + /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) + /// - `not-in-progress`: A `bind` operation is not in progress. + /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) + /// + /// # Implementors note + /// Unlike in POSIX, in WASI the bind operation is async. This enables + /// interactive WASI hosts to inject permission prompts. Runtimes that + /// don't want to make use of this ability can simply call the native + /// `bind` as part of either `start-bind` or `finish-bind`. + /// + /// # References + /// - + /// - + /// - + /// - + start-bind: func(network: borrow, local-address: ip-socket-address) -> result<_, error-code>; + finish-bind: func() -> result<_, error-code>; + + /// Set up inbound & outbound communication channels, optionally to a specific peer. + /// + /// This function only changes the local socket configuration and does not generate any network traffic. + /// On success, the `remote-address` of the socket is updated. The `local-address` may be updated as well, + /// based on the best network path to `remote-address`. + /// + /// When a `remote-address` is provided, the returned streams are limited to communicating with that specific peer: + /// - `send` can only be used to send to this destination. + /// - `receive` will only return datagrams sent from the provided `remote-address`. + /// + /// This method may be called multiple times on the same socket to change its association, but + /// only the most recently returned pair of streams will be operational. Implementations may trap if + /// the streams returned by a previous invocation haven't been dropped yet before calling `stream` again. + /// + /// The POSIX equivalent in pseudo-code is: + /// ```text + /// if (was previously connected) { + /// connect(s, AF_UNSPEC) + /// } + /// if (remote_address is Some) { + /// connect(s, remote_address) + /// } + /// ``` + /// + /// Unlike in POSIX, the socket must already be explicitly bound. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-state`: The socket is not bound. + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// + /// # References + /// - + /// - + /// - + /// - + %stream: func(remote-address: option) -> result, error-code>; + + /// Get the current bound address. + /// + /// POSIX mentions: + /// > If the socket has not been bound to a local name, the value + /// > stored in the object pointed to by `address` is unspecified. + /// + /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. + /// + /// # References + /// - + /// - + /// - + /// - + local-address: func() -> result; + + /// Get the address the socket is currently streaming to. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not streaming to a specific remote address. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + remote-address: func() -> result; + + /// Whether this is a IPv4 or IPv6 socket. + /// + /// Equivalent to the SO_DOMAIN socket option. + address-family: func() -> ip-address-family; + + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The TTL value must be 1 or higher. + unicast-hop-limit: func() -> result; + set-unicast-hop-limit: func(value: u8) -> result<_, error-code>; + + /// The kernel buffer space reserved for sends/receives on this socket. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + receive-buffer-size: func() -> result; + set-receive-buffer-size: func(value: u64) -> result<_, error-code>; + send-buffer-size: func() -> result; + set-send-buffer-size: func(value: u64) -> result<_, error-code>; + + /// Create a `pollable` which will resolve once the socket is ready for I/O. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + subscribe: func() -> pollable; + } + + resource incoming-datagram-stream { + /// Receive messages on the socket. + /// + /// This function attempts to receive up to `max-results` datagrams on the socket without blocking. + /// The returned list may contain fewer elements than requested, but never more. + /// + /// This function returns successfully with an empty list when either: + /// - `max-results` is 0, or: + /// - `max-results` is greater than 0, but no results are immediately available. + /// This function never returns `error(would-block)`. + /// + /// # Typical errors + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + /// - + receive: func(max-results: u64) -> result, error-code>; + + /// Create a `pollable` which will resolve once the stream is ready to receive again. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + subscribe: func() -> pollable; + } + + resource outgoing-datagram-stream { + /// Check readiness for sending. This function never blocks. + /// + /// Returns the number of datagrams permitted for the next call to `send`, + /// or an error. Calling `send` with more datagrams than this function has + /// permitted will trap. + /// + /// When this function returns ok(0), the `subscribe` pollable will + /// become ready when this function will report at least ok(1), or an + /// error. + /// + /// Never returns `would-block`. + check-send: func() -> result; + + /// Send messages on the socket. + /// + /// This function attempts to send all provided `datagrams` on the socket without blocking and + /// returns how many messages were actually sent (or queued for sending). This function never + /// returns `error(would-block)`. If none of the datagrams were able to be sent, `ok(0)` is returned. + /// + /// This function semantically behaves the same as iterating the `datagrams` list and sequentially + /// sending each individual datagram until either the end of the list has been reached or the first error occurred. + /// If at least one datagram has been sent successfully, this function never returns an error. + /// + /// If the input list is empty, the function returns `ok(0)`. + /// + /// Each call to `send` must be permitted by a preceding `check-send`. Implementations must trap if + /// either `check-send` was not called or `datagrams` contains more items than `check-send` permitted. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The socket is in "connected" mode and `remote-address` is `some` value that does not match the address passed to `stream`. (EISCONN) + /// - `invalid-argument`: The socket is not "connected" and no value for `remote-address` was provided. (EDESTADDRREQ) + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// - `datagram-too-large`: The datagram is too large. (EMSGSIZE) + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + /// - + send: func(datagrams: list) -> result; + + /// Create a `pollable` which will resolve once the stream is ready to send again. + /// + /// Note: this function is here for WASI Preview2 only. + /// It's planned to be removed when `future` is natively supported in Preview3. + subscribe: func() -> pollable; + } +} diff --git a/tests/program/wit/deps/sockets/world.wit b/tests/program/wit/deps/sockets/world.wit new file mode 100644 index 0000000..f8bb92a --- /dev/null +++ b/tests/program/wit/deps/sockets/world.wit @@ -0,0 +1,11 @@ +package wasi:sockets@0.2.0; + +world imports { + import instance-network; + import network; + import udp; + import udp-create-socket; + import tcp; + import tcp-create-socket; + import ip-name-lookup; +} diff --git a/tests/program/wit/world.wit b/tests/program/wit/world.wit new file mode 100644 index 0000000..24ac84d --- /dev/null +++ b/tests/program/wit/world.wit @@ -0,0 +1,5 @@ +package iawia002:wasi-http-client-test-program; + +world http-client { + include wasi:cli/command@0.2.0; +}