chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

1
vendor/wasip3/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"ff6bad2aacca7c90554087926de8a70a68a5897ef39da03fd008d8eb11e50a50","Cargo.lock":"d0f988b761977895354f9e00593327ddf2ac57693ac216bda9703c6e64344d83","Cargo.toml":"8c68ba791448b5727fb665a4faf8d344494f5dee1f099cd1df8300bd08f48b50","Cargo.toml.orig":"0973fcc15b1b53db1a578f9c8d9ea9fde788221802586e1391abfa0b14653354","README.md":"325b35fceb296aef996435dc7d68537af56fa1983012a9e170630ac78ce0334e","examples/cli-command.rs":"4cfc558ac50a5b2ed5338711951eedad072429170334fb9c52e8407c46b8c7fa","examples/http-proxy-compat.rs":"bb1669c8cb5b908767ff8d5441f3824e7c71db334cbac2ddd6ba57d976518a35","examples/http-proxy.rs":"3cb9cce68b2bd2850d106171b9e5cfe13b7ccea55982a877b5cb6d2839a65142","src/command.rs":"a5ab5e7df9c92224e4555c1b2ebd8c6aec205b97959b1f4437ac05af35bd06fc","src/http_compat/body_writer.rs":"43b8a0e8cf5d18498a18fbe5d4c6b12f313acecf18d25d82a82853b51e1520fb","src/http_compat/conversions.rs":"35a05ca5e1ed1d6973a8172a8a0baa570848ff425050505e99c6897cd4633b6a","src/http_compat/mod.rs":"5023685d2d7af07fdc76c46109a3fe1ed08689fd2c5b8a6afdca72225787c66d","src/imports.rs":"a68488755e6c6d2fc33a2b66c18f7eca3abdf5b85de7448062101a95a72779aa","src/lib.rs":"8735985613136c107427d5d3c198aaffdbadcb87f3bd1e04abf5ec8d7496fd4b","src/service.rs":"cd1bb6901be87821cac88c144e7244298305a0d05e1b6d5ffb38ac9a0f09d70e","wit/deps/cli.wit":"eb6b181f66a27bfaebbbea76997cc382d905088e4db85c0a4e8e5a285aac100c","wit/deps/clocks.wit":"f86539dbbf0846ce6054f81fd7440d2ddec5ba9531ce36c6537f5c3518ee4ea1","wit/deps/filesystem.wit":"c27a74d6a0d253bb4d73615c0405025ae378b91cd29d2e7b4c7969c51991c1f1","wit/deps/http.wit":"c325ca53102be2423b76d724620931a297fde983957ea469d1506f154bcf5255","wit/deps/random.wit":"46614ed77abff1255d50f1b37823c90e7168284877df3f74367db9df028ecbbe","wit/deps/sockets.wit":"3f64290847f4a97a073acc6669a3b415d8fbdb7dc9a212752989d5a4702d94db","wit/wasi-crate.wit":"561b9308e635f442fcfbe3c4e783d0b4f2110f4c7bdadc8775170e2e119f7453"},"package":"5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"}

6
vendor/wasip3/.cargo_vcs_info.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "06ce201370fcde0d1b0d47cac8ecb1b0b312c9f9"
},
"path_in_vcs": "crates/wasip3"
}

483
vendor/wasip3/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,483 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bytes"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
]
[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "http"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "indexmap"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
"hashbrown 0.16.1",
"serde",
"serde_core",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
dependencies = [
"proc-macro2",
]
[[package]]
name = "semver"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "slab"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "syn"
version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
dependencies = [
"bytes",
"futures",
"http",
"http-body",
"thiserror",
"wit-bindgen",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags",
"hashbrown 0.15.5",
"indexmap",
"semver",
]
[[package]]
name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"futures",
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap",
"prettyplease",
"syn",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "zmij"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"

96
vendor/wasip3/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,96 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.87.0"
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "WASIp3 API bindings for Rust"
documentation = "https://docs.rs/wasip3"
readme = "README.md"
keywords = [
"webassembly",
"wasm",
]
categories = [
"no-std",
"wasm",
]
license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
repository = "https://github.com/bytecodealliance/wasi-rs"
[features]
http-compat = [
"dep:bytes",
"dep:http-body",
"dep:http",
"dep:thiserror",
"wit-bindgen/async-spawn",
]
[lib]
name = "wasip3"
path = "src/lib.rs"
[[example]]
name = "cli-command"
crate-type = ["cdylib"]
path = "examples/cli-command.rs"
[[example]]
name = "http-proxy"
crate-type = ["cdylib"]
path = "examples/http-proxy.rs"
[[example]]
name = "http-proxy-compat"
crate-type = ["cdylib"]
path = "examples/http-proxy-compat.rs"
required-features = ["http-compat"]
[dependencies.bytes]
version = "1.10.1"
optional = true
[dependencies.http]
version = "1.3.1"
optional = true
[dependencies.http-body]
version = "1.0.1"
optional = true
[dependencies.thiserror]
version = "2.0.17"
optional = true
[dependencies.wit-bindgen]
version = "0.51.0"
features = ["async"]
default-features = false
[dev-dependencies.futures]
version = "0.3.31"
[dev-dependencies.http]
version = "1.3.1"
[dev-dependencies.wit-bindgen]
version = "0.51.0"
features = ["async-spawn"]
default-features = false

56
vendor/wasip3/README.md vendored Normal file
View File

@@ -0,0 +1,56 @@
<div align="center">
<h1><code>wasip3</code></h1>
<strong>A <a href="https://bytecodealliance.org/">Bytecode Alliance</a> project</strong>
<p>
<strong>WASIp2 API Bindings for Rust</strong>
</p>
<p>
<a href="https://crates.io/crates/wasip3"><img src="https://img.shields.io/crates/v/wasip3.svg?style=flat-square" alt="Crates.io version" /></a>
<a href="https://crates.io/crates/wasip3"><img src="https://img.shields.io/crates/d/wasip3.svg?style=flat-square" alt="Download" /></a>
<a href="https://docs.rs/wasip3/"><img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square" alt="docs.rs docs" /></a>
</p>
</div>
This crate contains bindings for [WASIp3](https://github.com/WebAssembly/WASI)
APIs for the worlds:
* [`wasi:cli/command`]
* [`wasi:http/proxy`]
This crate is procedurally generated from [WIT] files using [`wit-bindgen`].
[`wasi:cli/command`]: https://github.com/WebAssembly/wasi-cli
[`wasi:http/proxy`]: https://github.com/WebAssembly/wasi-http
[WIT]: https://component-model.bytecodealliance.org/design/wit.html
[`wit-bindgen`]: https://github.com/bytecodealliance/wit-bindgen
[components]: https://component-model.bytecodealliance.org/
[`wasm-tools`]: https://github.com/bytecodealliance/wasm-tools
# Usage
Depending on this crate can be done by adding it to your dependencies:
```sh
$ cargo add wasip3
```
Using this crate requires Rust 1.90.0. If you're using this before 2025-09-18
you'll want to use the beta channel of Rust. You'll also want to use this crate
with the `wasm32-wasip2` target (the Rust compiler does not currently have a
`wasm32-wasip3` target).
# Development
The bulk of the `wasip3` crate is generated by the [`wit-bindgen`] tool. The
`src/bindings.rs` file can be regenerated with:
```
$ ./ci/regenerate.sh
```
WASI definitions are located in the `wit` directory of this repository.
Currently they're copied from upstream repositories but are hoped to be better
managed in the future.

19
vendor/wasip3/examples/cli-command.rs vendored Normal file
View File

@@ -0,0 +1,19 @@
wasip3::cli::command::export!(Example);
struct Example;
impl wasip3::exports::cli::run::Guest for Example {
async fn run() -> Result<(), ()> {
let (mut tx, rx) = wasip3::wit_stream::new();
futures::join!(
async { wasip3::cli::stdout::write_via_stream(rx).await.unwrap() },
async {
let remaining = tx.write_all(b"Hello, WASI!".to_vec()).await;
assert!(remaining.is_empty());
drop(tx);
}
);
Ok(())
}
}

View File

@@ -0,0 +1,20 @@
use wasip3::http::types::{self, ErrorCode};
use wasip3::http_compat::{http_from_wasi_request, http_into_wasi_response, IncomingRequestBody};
wasip3::http::service::export!(Example);
struct Example;
impl wasip3::exports::http::handler::Guest for Example {
async fn handle(request: types::Request) -> Result<types::Response, ErrorCode> {
let request = http_from_wasi_request(request)?;
let response = serve(request).await?;
http_into_wasi_response(response)
}
}
async fn serve(
_request: http::Request<IncomingRequestBody>,
) -> Result<http::Response<String>, ErrorCode> {
Ok(http::Response::new("Hello, WASI!".to_string()))
}

22
vendor/wasip3/examples/http-proxy.rs vendored Normal file
View File

@@ -0,0 +1,22 @@
use wasip3::http::types::{ErrorCode, Fields, Request, Response};
use wasip3::{wit_bindgen, wit_future, wit_stream};
wasip3::http::service::export!(Example);
struct Example;
impl wasip3::exports::http::handler::Guest for Example {
async fn handle(_request: Request) -> Result<Response, ErrorCode> {
let (mut body_tx, body_rx) = wit_stream::new();
let (body_result_tx, body_result_rx) = wit_future::new(|| Ok(None));
let (response, _future_result) =
Response::new(Fields::new(), Some(body_rx), body_result_rx);
drop(body_result_tx);
wit_bindgen::spawn(async move {
let remaining = body_tx.write_all(b"Hello, WASI!".to_vec()).await;
assert!(remaining.is_empty());
});
Ok(response)
}
}

513
vendor/wasip3/src/command.rs vendored Normal file
View File

@@ -0,0 +1,513 @@
// Generated by `wit-bindgen` 0.51.0. DO NOT EDIT!
// Options used:
// * with "wasi:cli/environment@0.3.0-rc-2026-01-06" = "crate::cli::environment"
// * with "wasi:cli/exit@0.3.0-rc-2026-01-06" = "crate::cli::exit"
// * with "wasi:cli/stdin@0.3.0-rc-2026-01-06" = "crate::cli::stdin"
// * with "wasi:cli/stdout@0.3.0-rc-2026-01-06" = "crate::cli::stdout"
// * with "wasi:cli/stderr@0.3.0-rc-2026-01-06" = "crate::cli::stderr"
// * with "wasi:cli/types@0.3.0-rc-2026-01-06" = "crate::cli::types"
// * with "wasi:cli/terminal-input@0.3.0-rc-2026-01-06" = "crate::cli::terminal_input"
// * with "wasi:cli/terminal-output@0.3.0-rc-2026-01-06" = "crate::cli::terminal_output"
// * with "wasi:cli/terminal-stdin@0.3.0-rc-2026-01-06" = "crate::cli::terminal_stdin"
// * with "wasi:cli/terminal-stdout@0.3.0-rc-2026-01-06" = "crate::cli::terminal_stdout"
// * with "wasi:cli/terminal-stderr@0.3.0-rc-2026-01-06" = "crate::cli::terminal_stderr"
// * with "wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06" = "crate::clocks::monotonic_clock"
// * with "wasi:clocks/system-clock@0.3.0-rc-2026-01-06" = "crate::clocks::system_clock"
// * with "wasi:clocks/types@0.3.0-rc-2026-01-06" = "crate::clocks::types"
// * with "wasi:filesystem/types@0.3.0-rc-2026-01-06" = "crate::filesystem::types"
// * with "wasi:filesystem/preopens@0.3.0-rc-2026-01-06" = "crate::filesystem::preopens"
// * with "wasi:random/random@0.3.0-rc-2026-01-06" = "crate::random::random"
// * with "wasi:random/insecure@0.3.0-rc-2026-01-06" = "crate::random::insecure"
// * with "wasi:random/insecure-seed@0.3.0-rc-2026-01-06" = "crate::random::insecure_seed"
// * with "wasi:sockets/types@0.3.0-rc-2026-01-06" = "crate::sockets::types"
// * with "wasi:sockets/ip-name-lookup@0.3.0-rc-2026-01-06" = "crate::sockets::ip_name_lookup"
// * type_section_suffix: "rust-wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06-from-crates-io-command-world"
// * default-bindings-module: "$crate"
// * export-macro-name: _export_command
// * pub-export-macro
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::environment as __with_name0;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::exit as __with_name1;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::types as __with_name2;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::stdin as __with_name3;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::stdout as __with_name4;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::stderr as __with_name5;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::terminal_input as __with_name6;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::terminal_output as __with_name7;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::terminal_stdin as __with_name8;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::terminal_stdout as __with_name9;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::cli::terminal_stderr as __with_name10;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::clocks::types as __with_name11;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::clocks::monotonic_clock as __with_name12;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::clocks::system_clock as __with_name13;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::filesystem::types as __with_name14;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::filesystem::preopens as __with_name15;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::sockets::types as __with_name16;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::sockets::ip_name_lookup as __with_name17;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::random::random as __with_name18;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::random::insecure as __with_name19;
#[allow(unfulfilled_lint_expectations, unused_imports)]
use crate::random::insecure_seed as __with_name20;
#[rustfmt::skip]
#[allow(dead_code, clippy::all)]
pub mod exports {
pub mod wasi {
pub mod cli {
#[allow(dead_code, async_fn_in_trait, unused_imports, clippy::all)]
pub mod run {
#[used]
#[doc(hidden)]
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, unused_unsafe)]
pub unsafe fn _export_run_cabi<T: Guest>() -> i32 {
unsafe {
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
wit_bindgen::rt::async_support::start_task(async move {
let _task_cancel = wit_bindgen::rt::async_support::TaskCancelOnDrop::new();
let result0 = &{ T::run().await };
let result1 = match result0 {
Ok(_) => 0i32,
Err(_) => 1i32,
};
#[cfg(target_arch = "wasm32")]
#[link(
wasm_import_module = "[export]wasi:cli/run@0.3.0-rc-2026-01-06"
)]
unsafe extern "C" {
#[link_name = "[task-return]run"]
fn wit_import2(_: i32);
}
#[cfg(not(target_arch = "wasm32"))]
unsafe extern "C" fn wit_import2(_: i32) {
unreachable!()
}
_task_cancel.forget();
wit_import2(result1);
})
}
}
#[doc(hidden)]
#[allow(non_snake_case)]
pub unsafe fn __callback_run(
event0: u32,
event1: u32,
event2: u32,
) -> u32 {
unsafe {
wit_bindgen::rt::async_support::callback(event0, event1, event2)
}
}
pub trait Guest {
/// Run the program.
#[allow(async_fn_in_trait)]
async fn run() -> Result<(), ()>;
}
#[doc(hidden)]
#[macro_export]
macro_rules! __export_wasi_cli_run_0_3_0_rc_2026_01_06_cabi {
($ty:ident with_types_in $($path_to_types:tt)*) => {
const _ : () = { #[unsafe (export_name =
"[async-lift]wasi:cli/run@0.3.0-rc-2026-01-06#run")] unsafe
extern "C" fn export_run() -> i32 { unsafe { $($path_to_types)*::
_export_run_cabi::<$ty > () } } #[unsafe (export_name =
"[callback][async-lift]wasi:cli/run@0.3.0-rc-2026-01-06#run")]
unsafe extern "C" fn _callback_run(event0 : u32, event1 : u32,
event2 : u32) -> u32 { unsafe { $($path_to_types)*::
__callback_run(event0, event1, event2) } } };
};
}
#[doc(hidden)]
pub use __export_wasi_cli_run_0_3_0_rc_2026_01_06_cabi;
}
}
}
}
#[rustfmt::skip]
mod _rt {
#![allow(dead_code, unused_imports, clippy::all)]
#[cfg(target_arch = "wasm32")]
pub fn run_ctors_once() {
wit_bindgen::rt::run_ctors_once();
}
}
/// Generates `#[unsafe(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_command{ ($($t:tt)*) => (); }
/// # trait Guest {}
/// struct MyType;
///
/// impl Guest for MyType {
/// // ...
/// }
///
/// _export_command!(MyType);
/// ```
#[allow(unused_macros)]
#[doc(hidden)]
#[macro_export]
macro_rules! __export_command_impl {
($ty:ident) => {
$crate::_export_command!($ty with_types_in $crate);
};
($ty:ident with_types_in $($path_to_types_root:tt)*) => {
$($path_to_types_root)*::
exports::wasi::cli::run::__export_wasi_cli_run_0_3_0_rc_2026_01_06_cabi!($ty
with_types_in $($path_to_types_root)*:: exports::wasi::cli::run); const _ : () =
{ #[rustfmt::skip] #[cfg(target_arch = "wasm32")] #[unsafe (link_section =
"component-type:wit-bindgen:0.51.0:wasi:cli@0.3.0-rc-2026-01-06:command:imports and exportsrust-wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06-from-crates-io-command-world")]
#[doc(hidden)] #[allow(clippy::octal_escapes)] pub static
__WIT_BINDGEN_COMPONENT_TYPE : [u8; 8040] = *
b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xea=\x01A\x02\x01A3\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\x0fget-initial-\
cwd\x01\x06\x03\0(wasi:cli/environment@0.3.0-rc-2026-01-06\x05\0\x01B\x03\x01j\0\
\0\x01@\x01\x06status\0\x01\0\x04\0\x04exit\x01\x01\x03\0!wasi:cli/exit@0.3.0-rc\
-2026-01-06\x05\x01\x01B\x02\x01m\x03\x02io\x15illegal-byte-sequence\x04pipe\x04\
\0\x0aerror-code\x03\0\0\x03\0\"wasi:cli/types@0.3.0-rc-2026-01-06\x05\x02\x02\x03\
\0\x02\x0aerror-code\x01B\x08\x02\x03\x02\x01\x03\x04\0\x0aerror-code\x03\0\0\x01\
f\x01}\x01j\0\x01\x01\x01e\x01\x03\x01o\x02\x02\x04\x01@\0\0\x05\x04\0\x0fread-v\
ia-stream\x01\x06\x03\0\"wasi:cli/stdin@0.3.0-rc-2026-01-06\x05\x04\x01B\x06\x02\
\x03\x02\x01\x03\x04\0\x0aerror-code\x03\0\0\x01f\x01}\x01j\0\x01\x01\x01C\x01\x04\
data\x02\0\x03\x04\0\x10write-via-stream\x01\x04\x03\0#wasi:cli/stdout@0.3.0-rc-\
2026-01-06\x05\x05\x01B\x06\x02\x03\x02\x01\x03\x04\0\x0aerror-code\x03\0\0\x01f\
\x01}\x01j\0\x01\x01\x01C\x01\x04data\x02\0\x03\x04\0\x10write-via-stream\x01\x04\
\x03\0#wasi:cli/stderr@0.3.0-rc-2026-01-06\x05\x06\x01B\x01\x04\0\x0eterminal-in\
put\x03\x01\x03\0+wasi:cli/terminal-input@0.3.0-rc-2026-01-06\x05\x07\x01B\x01\x04\
\0\x0fterminal-output\x03\x01\x03\0,wasi:cli/terminal-output@0.3.0-rc-2026-01-06\
\x05\x08\x02\x03\0\x06\x0eterminal-input\x01B\x06\x02\x03\x02\x01\x09\x04\0\x0et\
erminal-input\x03\0\0\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x12get-terminal-stdin\
\x01\x04\x03\0+wasi:cli/terminal-stdin@0.3.0-rc-2026-01-06\x05\x0a\x02\x03\0\x07\
\x0fterminal-output\x01B\x06\x02\x03\x02\x01\x0b\x04\0\x0fterminal-output\x03\0\0\
\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x13get-terminal-stdout\x01\x04\x03\0,wasi:\
cli/terminal-stdout@0.3.0-rc-2026-01-06\x05\x0c\x01B\x06\x02\x03\x02\x01\x0b\x04\
\0\x0fterminal-output\x03\0\0\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x13get-termin\
al-stderr\x01\x04\x03\0,wasi:cli/terminal-stderr@0.3.0-rc-2026-01-06\x05\x0d\x01\
B\x02\x01w\x04\0\x08duration\x03\0\0\x03\0%wasi:clocks/types@0.3.0-rc-2026-01-06\
\x05\x0e\x02\x03\0\x0b\x08duration\x01B\x0c\x02\x03\x02\x01\x0f\x04\0\x08duratio\
n\x03\0\0\x01w\x04\0\x04mark\x03\0\x02\x01@\0\0\x03\x04\0\x03now\x01\x04\x01@\0\0\
\x01\x04\0\x0eget-resolution\x01\x05\x01C\x01\x04when\x03\x01\0\x04\0\x0await-un\
til\x01\x06\x01C\x01\x08how-long\x01\x01\0\x04\0\x08wait-for\x01\x07\x03\0/wasi:\
clocks/monotonic-clock@0.3.0-rc-2026-01-06\x05\x10\x01B\x08\x02\x03\x02\x01\x0f\x04\
\0\x08duration\x03\0\0\x01r\x02\x07secondsx\x0bnanosecondsy\x04\0\x07instant\x03\
\0\x02\x01@\0\0\x03\x04\0\x03now\x01\x04\x01@\0\0\x01\x04\0\x0eget-resolution\x01\
\x05\x03\0,wasi:clocks/system-clock@0.3.0-rc-2026-01-06\x05\x11\x02\x03\0\x0d\x07\
instant\x01BY\x02\x03\x02\x01\x12\x04\0\x07instant\x03\0\0\x01w\x04\0\x08filesiz\
e\x03\0\x02\x01m\x08\x07unknown\x0cblock-device\x10character-device\x09directory\
\x04fifo\x0dsymbolic-link\x0cregular-file\x06socket\x04\0\x0fdescriptor-type\x03\
\0\x04\x01n\x06\x04read\x05write\x13file-integrity-sync\x13data-integrity-sync\x14\
requested-write-sync\x10mutate-directory\x04\0\x10descriptor-flags\x03\0\x06\x01\
n\x01\x0esymlink-follow\x04\0\x0apath-flags\x03\0\x08\x01n\x04\x06create\x09dire\
ctory\x09exclusive\x08truncate\x04\0\x0aopen-flags\x03\0\x0a\x01w\x04\0\x0alink-\
count\x03\0\x0c\x01k\x01\x01r\x06\x04type\x05\x0alink-count\x0d\x04size\x03\x15d\
ata-access-timestamp\x0e\x1bdata-modification-timestamp\x0e\x17status-change-tim\
estamp\x0e\x04\0\x0fdescriptor-stat\x03\0\x0f\x01q\x03\x09no-change\0\0\x03now\0\
\0\x09timestamp\x01\x01\0\x04\0\x0dnew-timestamp\x03\0\x11\x01r\x02\x04type\x05\x04\
names\x04\0\x0fdirectory-entry\x03\0\x13\x01m$\x06access\x07already\x0ebad-descr\
iptor\x04busy\x08deadlock\x05quota\x05exist\x0efile-too-large\x15illegal-byte-se\
quence\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\x15\x01m\x06\x06normal\x0asequential\x06random\x09will-ne\
ed\x09dont-need\x08no-reuse\x04\0\x06advice\x03\0\x17\x01r\x02\x05lowerw\x05uppe\
rw\x04\0\x13metadata-hash-value\x03\0\x19\x04\0\x0adescriptor\x03\x01\x01h\x1b\x01\
f\x01}\x01j\0\x01\x16\x01e\x01\x1e\x01o\x02\x1d\x1f\x01@\x02\x04self\x1c\x06offs\
et\x03\0\x20\x04\0\"[method]descriptor.read-via-stream\x01!\x01C\x03\x04self\x1c\
\x04data\x1d\x06offset\x03\0\x1e\x04\0#[method]descriptor.write-via-stream\x01\"\
\x01C\x02\x04self\x1c\x04data\x1d\0\x1e\x04\0$[method]descriptor.append-via-stre\
am\x01#\x01C\x04\x04self\x1c\x06offset\x03\x06length\x03\x06advice\x18\0\x1e\x04\
\0\x19[method]descriptor.advise\x01$\x01C\x01\x04self\x1c\0\x1e\x04\0\x1c[method\
]descriptor.sync-data\x01%\x01j\x01\x07\x01\x16\x01C\x01\x04self\x1c\0&\x04\0\x1c\
[method]descriptor.get-flags\x01'\x01j\x01\x05\x01\x16\x01C\x01\x04self\x1c\0(\x04\
\0\x1b[method]descriptor.get-type\x01)\x01C\x02\x04self\x1c\x04size\x03\0\x1e\x04\
\0\x1b[method]descriptor.set-size\x01*\x01C\x03\x04self\x1c\x15data-access-times\
tamp\x12\x1bdata-modification-timestamp\x12\0\x1e\x04\0\x1c[method]descriptor.se\
t-times\x01+\x01f\x01\x14\x01o\x02,\x1f\x01C\x01\x04self\x1c\0-\x04\0![method]de\
scriptor.read-directory\x01.\x04\0\x17[method]descriptor.sync\x01%\x01C\x02\x04s\
elf\x1c\x04paths\0\x1e\x04\0&[method]descriptor.create-directory-at\x01/\x01j\x01\
\x10\x01\x16\x01C\x01\x04self\x1c\00\x04\0\x17[method]descriptor.stat\x011\x01C\x03\
\x04self\x1c\x0apath-flags\x09\x04paths\00\x04\0\x1a[method]descriptor.stat-at\x01\
2\x01C\x05\x04self\x1c\x0apath-flags\x09\x04paths\x15data-access-timestamp\x12\x1b\
data-modification-timestamp\x12\0\x1e\x04\0\x1f[method]descriptor.set-times-at\x01\
3\x01C\x05\x04self\x1c\x0eold-path-flags\x09\x08old-paths\x0enew-descriptor\x1c\x08\
new-paths\0\x1e\x04\0\x1a[method]descriptor.link-at\x014\x01i\x1b\x01j\x015\x01\x16\
\x01C\x05\x04self\x1c\x0apath-flags\x09\x04paths\x0aopen-flags\x0b\x05flags\x07\0\
6\x04\0\x1a[method]descriptor.open-at\x017\x01j\x01s\x01\x16\x01C\x02\x04self\x1c\
\x04paths\08\x04\0\x1e[method]descriptor.readlink-at\x019\x04\0&[method]descript\
or.remove-directory-at\x01/\x01C\x04\x04self\x1c\x08old-paths\x0enew-descriptor\x1c\
\x08new-paths\0\x1e\x04\0\x1c[method]descriptor.rename-at\x01:\x01C\x03\x04self\x1c\
\x08old-paths\x08new-paths\0\x1e\x04\0\x1d[method]descriptor.symlink-at\x01;\x04\
\0![method]descriptor.unlink-file-at\x01/\x01C\x02\x04self\x1c\x05other\x1c\0\x7f\
\x04\0![method]descriptor.is-same-object\x01<\x01j\x01\x1a\x01\x16\x01C\x01\x04s\
elf\x1c\0=\x04\0\x20[method]descriptor.metadata-hash\x01>\x01C\x03\x04self\x1c\x0a\
path-flags\x09\x04paths\0=\x04\0#[method]descriptor.metadata-hash-at\x01?\x03\0)\
wasi:filesystem/types@0.3.0-rc-2026-01-06\x05\x13\x02\x03\0\x0e\x0adescriptor\x01\
B\x07\x02\x03\x02\x01\x14\x04\0\x0adescriptor\x03\0\0\x01i\x01\x01o\x02\x02s\x01\
p\x03\x01@\0\0\x04\x04\0\x0fget-directories\x01\x05\x03\0,wasi:filesystem/preope\
ns@0.3.0-rc-2026-01-06\x05\x15\x01Bq\x02\x03\x02\x01\x0f\x04\0\x08duration\x03\0\
\0\x01m\x0e\x07unknown\x0daccess-denied\x0dnot-supported\x10invalid-argument\x0d\
out-of-memory\x07timeout\x0dinvalid-state\x14address-not-bindable\x0eaddress-in-\
use\x12remote-unreachable\x12connection-refused\x10connection-reset\x12connectio\
n-aborted\x12datagram-too-large\x04\0\x0aerror-code\x03\0\x02\x01m\x02\x04ipv4\x04\
ipv6\x04\0\x11ip-address-family\x03\0\x04\x01o\x04}}}}\x04\0\x0cipv4-address\x03\
\0\x06\x01o\x08{{{{{{{{\x04\0\x0cipv6-address\x03\0\x08\x01q\x02\x04ipv4\x01\x07\
\0\x04ipv6\x01\x09\0\x04\0\x0aip-address\x03\0\x0a\x01r\x02\x04port{\x07address\x07\
\x04\0\x13ipv4-socket-address\x03\0\x0c\x01r\x04\x04port{\x09flow-infoy\x07addre\
ss\x09\x08scope-idy\x04\0\x13ipv6-socket-address\x03\0\x0e\x01q\x02\x04ipv4\x01\x0d\
\0\x04ipv6\x01\x0f\0\x04\0\x11ip-socket-address\x03\0\x10\x04\0\x0atcp-socket\x03\
\x01\x04\0\x0audp-socket\x03\x01\x01i\x12\x01j\x01\x14\x01\x03\x01@\x01\x0eaddre\
ss-family\x05\0\x15\x04\0\x19[static]tcp-socket.create\x01\x16\x01h\x12\x01j\0\x01\
\x03\x01@\x02\x04self\x17\x0dlocal-address\x11\0\x18\x04\0\x17[method]tcp-socket\
.bind\x01\x19\x01C\x02\x04self\x17\x0eremote-address\x11\0\x18\x04\0\x1a[method]\
tcp-socket.connect\x01\x1a\x01f\x01\x14\x01j\x01\x1b\x01\x03\x01@\x01\x04self\x17\
\0\x1c\x04\0\x19[method]tcp-socket.listen\x01\x1d\x01f\x01}\x01C\x02\x04self\x17\
\x04data\x1e\0\x18\x04\0\x17[method]tcp-socket.send\x01\x1f\x01e\x01\x18\x01o\x02\
\x1e\x20\x01@\x01\x04self\x17\0!\x04\0\x1a[method]tcp-socket.receive\x01\"\x01j\x01\
\x11\x01\x03\x01@\x01\x04self\x17\0#\x04\0$[method]tcp-socket.get-local-address\x01\
$\x04\0%[method]tcp-socket.get-remote-address\x01$\x01@\x01\x04self\x17\0\x7f\x04\
\0#[method]tcp-socket.get-is-listening\x01%\x01@\x01\x04self\x17\0\x05\x04\0%[me\
thod]tcp-socket.get-address-family\x01&\x01@\x02\x04self\x17\x05valuew\0\x18\x04\
\0*[method]tcp-socket.set-listen-backlog-size\x01'\x01j\x01\x7f\x01\x03\x01@\x01\
\x04self\x17\0(\x04\0)[method]tcp-socket.get-keep-alive-enabled\x01)\x01@\x02\x04\
self\x17\x05value\x7f\0\x18\x04\0)[method]tcp-socket.set-keep-alive-enabled\x01*\
\x01j\x01\x01\x01\x03\x01@\x01\x04self\x17\0+\x04\0+[method]tcp-socket.get-keep-\
alive-idle-time\x01,\x01@\x02\x04self\x17\x05value\x01\0\x18\x04\0+[method]tcp-s\
ocket.set-keep-alive-idle-time\x01-\x04\0*[method]tcp-socket.get-keep-alive-inte\
rval\x01,\x04\0*[method]tcp-socket.set-keep-alive-interval\x01-\x01j\x01y\x01\x03\
\x01@\x01\x04self\x17\0.\x04\0'[method]tcp-socket.get-keep-alive-count\x01/\x01@\
\x02\x04self\x17\x05valuey\0\x18\x04\0'[method]tcp-socket.set-keep-alive-count\x01\
0\x01j\x01}\x01\x03\x01@\x01\x04self\x17\01\x04\0\x20[method]tcp-socket.get-hop-\
limit\x012\x01@\x02\x04self\x17\x05value}\0\x18\x04\0\x20[method]tcp-socket.set-\
hop-limit\x013\x01j\x01w\x01\x03\x01@\x01\x04self\x17\04\x04\0*[method]tcp-socke\
t.get-receive-buffer-size\x015\x04\0*[method]tcp-socket.set-receive-buffer-size\x01\
'\x04\0'[method]tcp-socket.get-send-buffer-size\x015\x04\0'[method]tcp-socket.se\
t-send-buffer-size\x01'\x01i\x13\x01j\x016\x01\x03\x01@\x01\x0eaddress-family\x05\
\07\x04\0\x19[static]udp-socket.create\x018\x01h\x13\x01@\x02\x04self9\x0dlocal-\
address\x11\0\x18\x04\0\x17[method]udp-socket.bind\x01:\x01@\x02\x04self9\x0erem\
ote-address\x11\0\x18\x04\0\x1a[method]udp-socket.connect\x01;\x01@\x01\x04self9\
\0\x18\x04\0\x1d[method]udp-socket.disconnect\x01<\x01p}\x01k\x11\x01C\x03\x04se\
lf9\x04data=\x0eremote-address>\0\x18\x04\0\x17[method]udp-socket.send\x01?\x01o\
\x02=\x11\x01j\x01\xc0\0\x01\x03\x01C\x01\x04self9\0\xc1\0\x04\0\x1a[method]udp-\
socket.receive\x01B\x01@\x01\x04self9\0#\x04\0$[method]udp-socket.get-local-addr\
ess\x01C\x04\0%[method]udp-socket.get-remote-address\x01C\x01@\x01\x04self9\0\x05\
\x04\0%[method]udp-socket.get-address-family\x01D\x01@\x01\x04self9\01\x04\0([me\
thod]udp-socket.get-unicast-hop-limit\x01E\x01@\x02\x04self9\x05value}\0\x18\x04\
\0([method]udp-socket.set-unicast-hop-limit\x01F\x01@\x01\x04self9\04\x04\0*[met\
hod]udp-socket.get-receive-buffer-size\x01G\x01@\x02\x04self9\x05valuew\0\x18\x04\
\0*[method]udp-socket.set-receive-buffer-size\x01H\x04\0'[method]udp-socket.get-\
send-buffer-size\x01G\x04\0'[method]udp-socket.set-send-buffer-size\x01H\x03\0&w\
asi:sockets/types@0.3.0-rc-2026-01-06\x05\x16\x02\x03\0\x10\x0aip-address\x01B\x08\
\x02\x03\x02\x01\x17\x04\0\x0aip-address\x03\0\0\x01m\x06\x07unknown\x0daccess-d\
enied\x10invalid-argument\x11name-unresolvable\x1atemporary-resolver-failure\x1a\
permanent-resolver-failure\x04\0\x0aerror-code\x03\0\x02\x01p\x01\x01j\x01\x04\x01\
\x03\x01C\x01\x04names\0\x05\x04\0\x11resolve-addresses\x01\x06\x03\0/wasi:socke\
ts/ip-name-lookup@0.3.0-rc-2026-01-06\x05\x18\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\
\0&wasi:random/random@0.3.0-rc-2026-01-06\x05\x19\x01B\x05\x01p}\x01@\x01\x03len\
w\0\0\x04\0\x19get-insecure-random-bytes\x01\x01\x01@\0\0w\x04\0\x17get-insecure\
-random-u64\x01\x02\x03\0(wasi:random/insecure@0.3.0-rc-2026-01-06\x05\x1a\x01B\x03\
\x01o\x02ww\x01@\0\0\0\x04\0\x11get-insecure-seed\x01\x01\x03\0-wasi:random/inse\
cure-seed@0.3.0-rc-2026-01-06\x05\x1b\x01B\x03\x01j\0\0\x01C\0\0\0\x04\0\x03run\x01\
\x01\x04\0\x20wasi:cli/run@0.3.0-rc-2026-01-06\x05\x1c\x04\0$wasi:cli/command@0.\
3.0-rc-2026-01-06\x04\0\x0b\x0d\x01\0\x07command\x03\0\0\0G\x09producers\x01\x0c\
processed-by\x02\x0dwit-component\x070.244.0\x10wit-bindgen-rust\x060.51.0";
};
};
}
#[doc(inline)]
pub use __export_command_impl as _export_command;
#[rustfmt::skip]
#[cfg(target_arch = "wasm32")]
#[unsafe(
link_section = "component-type:wit-bindgen:0.51.0:wasi:cli@0.3.0-rc-2026-01-06:command-with-all-of-its-exports-removed:encoded worldrust-wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06-from-crates-io-command-world"
)]
#[doc(hidden)]
#[allow(clippy::octal_escapes)]
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 8047] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xd1=\x01A\x02\x01A1\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\x0fget-initial-\
cwd\x01\x06\x03\0(wasi:cli/environment@0.3.0-rc-2026-01-06\x05\0\x01B\x03\x01j\0\
\0\x01@\x01\x06status\0\x01\0\x04\0\x04exit\x01\x01\x03\0!wasi:cli/exit@0.3.0-rc\
-2026-01-06\x05\x01\x01B\x02\x01m\x03\x02io\x15illegal-byte-sequence\x04pipe\x04\
\0\x0aerror-code\x03\0\0\x03\0\"wasi:cli/types@0.3.0-rc-2026-01-06\x05\x02\x02\x03\
\0\x02\x0aerror-code\x01B\x08\x02\x03\x02\x01\x03\x04\0\x0aerror-code\x03\0\0\x01\
f\x01}\x01j\0\x01\x01\x01e\x01\x03\x01o\x02\x02\x04\x01@\0\0\x05\x04\0\x0fread-v\
ia-stream\x01\x06\x03\0\"wasi:cli/stdin@0.3.0-rc-2026-01-06\x05\x04\x01B\x06\x02\
\x03\x02\x01\x03\x04\0\x0aerror-code\x03\0\0\x01f\x01}\x01j\0\x01\x01\x01C\x01\x04\
data\x02\0\x03\x04\0\x10write-via-stream\x01\x04\x03\0#wasi:cli/stdout@0.3.0-rc-\
2026-01-06\x05\x05\x01B\x06\x02\x03\x02\x01\x03\x04\0\x0aerror-code\x03\0\0\x01f\
\x01}\x01j\0\x01\x01\x01C\x01\x04data\x02\0\x03\x04\0\x10write-via-stream\x01\x04\
\x03\0#wasi:cli/stderr@0.3.0-rc-2026-01-06\x05\x06\x01B\x01\x04\0\x0eterminal-in\
put\x03\x01\x03\0+wasi:cli/terminal-input@0.3.0-rc-2026-01-06\x05\x07\x01B\x01\x04\
\0\x0fterminal-output\x03\x01\x03\0,wasi:cli/terminal-output@0.3.0-rc-2026-01-06\
\x05\x08\x02\x03\0\x06\x0eterminal-input\x01B\x06\x02\x03\x02\x01\x09\x04\0\x0et\
erminal-input\x03\0\0\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x12get-terminal-stdin\
\x01\x04\x03\0+wasi:cli/terminal-stdin@0.3.0-rc-2026-01-06\x05\x0a\x02\x03\0\x07\
\x0fterminal-output\x01B\x06\x02\x03\x02\x01\x0b\x04\0\x0fterminal-output\x03\0\0\
\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x13get-terminal-stdout\x01\x04\x03\0,wasi:\
cli/terminal-stdout@0.3.0-rc-2026-01-06\x05\x0c\x01B\x06\x02\x03\x02\x01\x0b\x04\
\0\x0fterminal-output\x03\0\0\x01i\x01\x01k\x02\x01@\0\0\x03\x04\0\x13get-termin\
al-stderr\x01\x04\x03\0,wasi:cli/terminal-stderr@0.3.0-rc-2026-01-06\x05\x0d\x01\
B\x02\x01w\x04\0\x08duration\x03\0\0\x03\0%wasi:clocks/types@0.3.0-rc-2026-01-06\
\x05\x0e\x02\x03\0\x0b\x08duration\x01B\x0c\x02\x03\x02\x01\x0f\x04\0\x08duratio\
n\x03\0\0\x01w\x04\0\x04mark\x03\0\x02\x01@\0\0\x03\x04\0\x03now\x01\x04\x01@\0\0\
\x01\x04\0\x0eget-resolution\x01\x05\x01C\x01\x04when\x03\x01\0\x04\0\x0await-un\
til\x01\x06\x01C\x01\x08how-long\x01\x01\0\x04\0\x08wait-for\x01\x07\x03\0/wasi:\
clocks/monotonic-clock@0.3.0-rc-2026-01-06\x05\x10\x01B\x08\x02\x03\x02\x01\x0f\x04\
\0\x08duration\x03\0\0\x01r\x02\x07secondsx\x0bnanosecondsy\x04\0\x07instant\x03\
\0\x02\x01@\0\0\x03\x04\0\x03now\x01\x04\x01@\0\0\x01\x04\0\x0eget-resolution\x01\
\x05\x03\0,wasi:clocks/system-clock@0.3.0-rc-2026-01-06\x05\x11\x02\x03\0\x0d\x07\
instant\x01BY\x02\x03\x02\x01\x12\x04\0\x07instant\x03\0\0\x01w\x04\0\x08filesiz\
e\x03\0\x02\x01m\x08\x07unknown\x0cblock-device\x10character-device\x09directory\
\x04fifo\x0dsymbolic-link\x0cregular-file\x06socket\x04\0\x0fdescriptor-type\x03\
\0\x04\x01n\x06\x04read\x05write\x13file-integrity-sync\x13data-integrity-sync\x14\
requested-write-sync\x10mutate-directory\x04\0\x10descriptor-flags\x03\0\x06\x01\
n\x01\x0esymlink-follow\x04\0\x0apath-flags\x03\0\x08\x01n\x04\x06create\x09dire\
ctory\x09exclusive\x08truncate\x04\0\x0aopen-flags\x03\0\x0a\x01w\x04\0\x0alink-\
count\x03\0\x0c\x01k\x01\x01r\x06\x04type\x05\x0alink-count\x0d\x04size\x03\x15d\
ata-access-timestamp\x0e\x1bdata-modification-timestamp\x0e\x17status-change-tim\
estamp\x0e\x04\0\x0fdescriptor-stat\x03\0\x0f\x01q\x03\x09no-change\0\0\x03now\0\
\0\x09timestamp\x01\x01\0\x04\0\x0dnew-timestamp\x03\0\x11\x01r\x02\x04type\x05\x04\
names\x04\0\x0fdirectory-entry\x03\0\x13\x01m$\x06access\x07already\x0ebad-descr\
iptor\x04busy\x08deadlock\x05quota\x05exist\x0efile-too-large\x15illegal-byte-se\
quence\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\x15\x01m\x06\x06normal\x0asequential\x06random\x09will-ne\
ed\x09dont-need\x08no-reuse\x04\0\x06advice\x03\0\x17\x01r\x02\x05lowerw\x05uppe\
rw\x04\0\x13metadata-hash-value\x03\0\x19\x04\0\x0adescriptor\x03\x01\x01h\x1b\x01\
f\x01}\x01j\0\x01\x16\x01e\x01\x1e\x01o\x02\x1d\x1f\x01@\x02\x04self\x1c\x06offs\
et\x03\0\x20\x04\0\"[method]descriptor.read-via-stream\x01!\x01C\x03\x04self\x1c\
\x04data\x1d\x06offset\x03\0\x1e\x04\0#[method]descriptor.write-via-stream\x01\"\
\x01C\x02\x04self\x1c\x04data\x1d\0\x1e\x04\0$[method]descriptor.append-via-stre\
am\x01#\x01C\x04\x04self\x1c\x06offset\x03\x06length\x03\x06advice\x18\0\x1e\x04\
\0\x19[method]descriptor.advise\x01$\x01C\x01\x04self\x1c\0\x1e\x04\0\x1c[method\
]descriptor.sync-data\x01%\x01j\x01\x07\x01\x16\x01C\x01\x04self\x1c\0&\x04\0\x1c\
[method]descriptor.get-flags\x01'\x01j\x01\x05\x01\x16\x01C\x01\x04self\x1c\0(\x04\
\0\x1b[method]descriptor.get-type\x01)\x01C\x02\x04self\x1c\x04size\x03\0\x1e\x04\
\0\x1b[method]descriptor.set-size\x01*\x01C\x03\x04self\x1c\x15data-access-times\
tamp\x12\x1bdata-modification-timestamp\x12\0\x1e\x04\0\x1c[method]descriptor.se\
t-times\x01+\x01f\x01\x14\x01o\x02,\x1f\x01C\x01\x04self\x1c\0-\x04\0![method]de\
scriptor.read-directory\x01.\x04\0\x17[method]descriptor.sync\x01%\x01C\x02\x04s\
elf\x1c\x04paths\0\x1e\x04\0&[method]descriptor.create-directory-at\x01/\x01j\x01\
\x10\x01\x16\x01C\x01\x04self\x1c\00\x04\0\x17[method]descriptor.stat\x011\x01C\x03\
\x04self\x1c\x0apath-flags\x09\x04paths\00\x04\0\x1a[method]descriptor.stat-at\x01\
2\x01C\x05\x04self\x1c\x0apath-flags\x09\x04paths\x15data-access-timestamp\x12\x1b\
data-modification-timestamp\x12\0\x1e\x04\0\x1f[method]descriptor.set-times-at\x01\
3\x01C\x05\x04self\x1c\x0eold-path-flags\x09\x08old-paths\x0enew-descriptor\x1c\x08\
new-paths\0\x1e\x04\0\x1a[method]descriptor.link-at\x014\x01i\x1b\x01j\x015\x01\x16\
\x01C\x05\x04self\x1c\x0apath-flags\x09\x04paths\x0aopen-flags\x0b\x05flags\x07\0\
6\x04\0\x1a[method]descriptor.open-at\x017\x01j\x01s\x01\x16\x01C\x02\x04self\x1c\
\x04paths\08\x04\0\x1e[method]descriptor.readlink-at\x019\x04\0&[method]descript\
or.remove-directory-at\x01/\x01C\x04\x04self\x1c\x08old-paths\x0enew-descriptor\x1c\
\x08new-paths\0\x1e\x04\0\x1c[method]descriptor.rename-at\x01:\x01C\x03\x04self\x1c\
\x08old-paths\x08new-paths\0\x1e\x04\0\x1d[method]descriptor.symlink-at\x01;\x04\
\0![method]descriptor.unlink-file-at\x01/\x01C\x02\x04self\x1c\x05other\x1c\0\x7f\
\x04\0![method]descriptor.is-same-object\x01<\x01j\x01\x1a\x01\x16\x01C\x01\x04s\
elf\x1c\0=\x04\0\x20[method]descriptor.metadata-hash\x01>\x01C\x03\x04self\x1c\x0a\
path-flags\x09\x04paths\0=\x04\0#[method]descriptor.metadata-hash-at\x01?\x03\0)\
wasi:filesystem/types@0.3.0-rc-2026-01-06\x05\x13\x02\x03\0\x0e\x0adescriptor\x01\
B\x07\x02\x03\x02\x01\x14\x04\0\x0adescriptor\x03\0\0\x01i\x01\x01o\x02\x02s\x01\
p\x03\x01@\0\0\x04\x04\0\x0fget-directories\x01\x05\x03\0,wasi:filesystem/preope\
ns@0.3.0-rc-2026-01-06\x05\x15\x01Bq\x02\x03\x02\x01\x0f\x04\0\x08duration\x03\0\
\0\x01m\x0e\x07unknown\x0daccess-denied\x0dnot-supported\x10invalid-argument\x0d\
out-of-memory\x07timeout\x0dinvalid-state\x14address-not-bindable\x0eaddress-in-\
use\x12remote-unreachable\x12connection-refused\x10connection-reset\x12connectio\
n-aborted\x12datagram-too-large\x04\0\x0aerror-code\x03\0\x02\x01m\x02\x04ipv4\x04\
ipv6\x04\0\x11ip-address-family\x03\0\x04\x01o\x04}}}}\x04\0\x0cipv4-address\x03\
\0\x06\x01o\x08{{{{{{{{\x04\0\x0cipv6-address\x03\0\x08\x01q\x02\x04ipv4\x01\x07\
\0\x04ipv6\x01\x09\0\x04\0\x0aip-address\x03\0\x0a\x01r\x02\x04port{\x07address\x07\
\x04\0\x13ipv4-socket-address\x03\0\x0c\x01r\x04\x04port{\x09flow-infoy\x07addre\
ss\x09\x08scope-idy\x04\0\x13ipv6-socket-address\x03\0\x0e\x01q\x02\x04ipv4\x01\x0d\
\0\x04ipv6\x01\x0f\0\x04\0\x11ip-socket-address\x03\0\x10\x04\0\x0atcp-socket\x03\
\x01\x04\0\x0audp-socket\x03\x01\x01i\x12\x01j\x01\x14\x01\x03\x01@\x01\x0eaddre\
ss-family\x05\0\x15\x04\0\x19[static]tcp-socket.create\x01\x16\x01h\x12\x01j\0\x01\
\x03\x01@\x02\x04self\x17\x0dlocal-address\x11\0\x18\x04\0\x17[method]tcp-socket\
.bind\x01\x19\x01C\x02\x04self\x17\x0eremote-address\x11\0\x18\x04\0\x1a[method]\
tcp-socket.connect\x01\x1a\x01f\x01\x14\x01j\x01\x1b\x01\x03\x01@\x01\x04self\x17\
\0\x1c\x04\0\x19[method]tcp-socket.listen\x01\x1d\x01f\x01}\x01C\x02\x04self\x17\
\x04data\x1e\0\x18\x04\0\x17[method]tcp-socket.send\x01\x1f\x01e\x01\x18\x01o\x02\
\x1e\x20\x01@\x01\x04self\x17\0!\x04\0\x1a[method]tcp-socket.receive\x01\"\x01j\x01\
\x11\x01\x03\x01@\x01\x04self\x17\0#\x04\0$[method]tcp-socket.get-local-address\x01\
$\x04\0%[method]tcp-socket.get-remote-address\x01$\x01@\x01\x04self\x17\0\x7f\x04\
\0#[method]tcp-socket.get-is-listening\x01%\x01@\x01\x04self\x17\0\x05\x04\0%[me\
thod]tcp-socket.get-address-family\x01&\x01@\x02\x04self\x17\x05valuew\0\x18\x04\
\0*[method]tcp-socket.set-listen-backlog-size\x01'\x01j\x01\x7f\x01\x03\x01@\x01\
\x04self\x17\0(\x04\0)[method]tcp-socket.get-keep-alive-enabled\x01)\x01@\x02\x04\
self\x17\x05value\x7f\0\x18\x04\0)[method]tcp-socket.set-keep-alive-enabled\x01*\
\x01j\x01\x01\x01\x03\x01@\x01\x04self\x17\0+\x04\0+[method]tcp-socket.get-keep-\
alive-idle-time\x01,\x01@\x02\x04self\x17\x05value\x01\0\x18\x04\0+[method]tcp-s\
ocket.set-keep-alive-idle-time\x01-\x04\0*[method]tcp-socket.get-keep-alive-inte\
rval\x01,\x04\0*[method]tcp-socket.set-keep-alive-interval\x01-\x01j\x01y\x01\x03\
\x01@\x01\x04self\x17\0.\x04\0'[method]tcp-socket.get-keep-alive-count\x01/\x01@\
\x02\x04self\x17\x05valuey\0\x18\x04\0'[method]tcp-socket.set-keep-alive-count\x01\
0\x01j\x01}\x01\x03\x01@\x01\x04self\x17\01\x04\0\x20[method]tcp-socket.get-hop-\
limit\x012\x01@\x02\x04self\x17\x05value}\0\x18\x04\0\x20[method]tcp-socket.set-\
hop-limit\x013\x01j\x01w\x01\x03\x01@\x01\x04self\x17\04\x04\0*[method]tcp-socke\
t.get-receive-buffer-size\x015\x04\0*[method]tcp-socket.set-receive-buffer-size\x01\
'\x04\0'[method]tcp-socket.get-send-buffer-size\x015\x04\0'[method]tcp-socket.se\
t-send-buffer-size\x01'\x01i\x13\x01j\x016\x01\x03\x01@\x01\x0eaddress-family\x05\
\07\x04\0\x19[static]udp-socket.create\x018\x01h\x13\x01@\x02\x04self9\x0dlocal-\
address\x11\0\x18\x04\0\x17[method]udp-socket.bind\x01:\x01@\x02\x04self9\x0erem\
ote-address\x11\0\x18\x04\0\x1a[method]udp-socket.connect\x01;\x01@\x01\x04self9\
\0\x18\x04\0\x1d[method]udp-socket.disconnect\x01<\x01p}\x01k\x11\x01C\x03\x04se\
lf9\x04data=\x0eremote-address>\0\x18\x04\0\x17[method]udp-socket.send\x01?\x01o\
\x02=\x11\x01j\x01\xc0\0\x01\x03\x01C\x01\x04self9\0\xc1\0\x04\0\x1a[method]udp-\
socket.receive\x01B\x01@\x01\x04self9\0#\x04\0$[method]udp-socket.get-local-addr\
ess\x01C\x04\0%[method]udp-socket.get-remote-address\x01C\x01@\x01\x04self9\0\x05\
\x04\0%[method]udp-socket.get-address-family\x01D\x01@\x01\x04self9\01\x04\0([me\
thod]udp-socket.get-unicast-hop-limit\x01E\x01@\x02\x04self9\x05value}\0\x18\x04\
\0([method]udp-socket.set-unicast-hop-limit\x01F\x01@\x01\x04self9\04\x04\0*[met\
hod]udp-socket.get-receive-buffer-size\x01G\x01@\x02\x04self9\x05valuew\0\x18\x04\
\0*[method]udp-socket.set-receive-buffer-size\x01H\x04\0'[method]udp-socket.get-\
send-buffer-size\x01G\x04\0'[method]udp-socket.set-send-buffer-size\x01H\x03\0&w\
asi:sockets/types@0.3.0-rc-2026-01-06\x05\x16\x02\x03\0\x10\x0aip-address\x01B\x08\
\x02\x03\x02\x01\x17\x04\0\x0aip-address\x03\0\0\x01m\x06\x07unknown\x0daccess-d\
enied\x10invalid-argument\x11name-unresolvable\x1atemporary-resolver-failure\x1a\
permanent-resolver-failure\x04\0\x0aerror-code\x03\0\x02\x01p\x01\x01j\x01\x04\x01\
\x03\x01C\x01\x04names\0\x05\x04\0\x11resolve-addresses\x01\x06\x03\0/wasi:socke\
ts/ip-name-lookup@0.3.0-rc-2026-01-06\x05\x18\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\
\0&wasi:random/random@0.3.0-rc-2026-01-06\x05\x19\x01B\x05\x01p}\x01@\x01\x03len\
w\0\0\x04\0\x19get-insecure-random-bytes\x01\x01\x01@\0\0w\x04\0\x17get-insecure\
-random-u64\x01\x02\x03\0(wasi:random/insecure@0.3.0-rc-2026-01-06\x05\x1a\x01B\x03\
\x01o\x02ww\x01@\0\0\0\x04\0\x11get-insecure-seed\x01\x01\x03\0-wasi:random/inse\
cure-seed@0.3.0-rc-2026-01-06\x05\x1b\x04\0Dwasi:cli/command-with-all-of-its-exp\
orts-removed@0.3.0-rc-2026-01-06\x04\0\x0b-\x01\0'command-with-all-of-its-export\
s-removed\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.\
244.0\x10wit-bindgen-rust\x060.51.0";
#[inline(never)]
#[doc(hidden)]
pub fn __link_custom_section_describing_imports() {
wit_bindgen::rt::maybe_link_cabi_realloc();
}

View File

@@ -0,0 +1,145 @@
use crate::{
http::types::{ErrorCode, HeaderError, Trailers},
wit_bindgen::{FutureReader, FutureWriter, StreamReader, StreamWriter},
wit_future, wit_stream,
};
use http::HeaderMap;
use http_body::{Body as _, Frame};
use std::future::poll_fn;
use std::{fmt::Debug, pin};
type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub type BodyResult = Result<Option<Trailers>, ErrorCode>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// The [`http_body::Body`] returned an error.
#[error("body error: {0}")]
HttpBody(#[source] BoxError),
/// Received trailers were rejected by [`Trailers::from_list`].
#[error("invalid trailers: {0}")]
InvalidTrailers(#[source] HeaderError),
/// The result future reader end was closed (dropped).
///
/// The result that couldn't be written is returned.
#[error("result future reader closed")]
ResultReaderClosed(BodyResult),
/// The stream reader end was closed (dropped).
///
/// The number of bytes written successfully is returned as `written` and
/// the bytes that couldn't be written are returned as `unwritten`.
#[error("stream reader closed")]
StreamReaderClosed { written: usize, unwritten: Vec<u8> },
}
/// BodyWriter coordinates a [`StreamWriter`] and [`FutureWriter`] associated
/// with the write end of a `wasi:http` `Request` or `Response` body.
pub struct BodyWriter {
pub stream_writer: StreamWriter<u8>,
pub result_writer: FutureWriter<BodyResult>,
pub trailers: HeaderMap,
}
impl BodyWriter {
/// Returns a new writer and the matching stream and result future readers,
/// which will typically be used to create a `wasi:http` `Request` or
/// `Response`.
pub fn new() -> (Self, StreamReader<u8>, FutureReader<BodyResult>) {
let (stream_writer, stream_reader) = wit_stream::new();
let (result_writer, result_reader) =
// TODO: is there a more appropriate ErrorCode?
wit_future::new(|| Err(ErrorCode::InternalError(Some("body writer dropped".into()))));
(
Self {
stream_writer,
result_writer,
trailers: Default::default(),
},
stream_reader,
result_reader,
)
}
/// Sends the given [`http_body::Body`] to this writer.
///
/// This copies all data frames from the body to this writer's stream and
/// then writes any trailers from the body to the result future. On success
/// the number of data bytes written to the stream (which does not including
/// trailers) is returned.
///
/// If there is an error it is written to the result future.
pub async fn send_http_body<T>(mut self, mut body: &mut T) -> Result<u64, Error>
where
T: http_body::Body + Unpin,
T::Data: Into<Vec<u8>>,
T::Error: Into<BoxError>,
{
let mut total_written = 0;
loop {
let frame = poll_fn(|cx| pin::Pin::new(&mut body).poll_frame(cx)).await;
match frame {
Some(Ok(frame)) => {
let written = self.send_frame(frame).await?;
total_written += written as u64;
}
Some(Err(err)) => {
let err = err.into();
// TODO: consider if there are better ErrorCode mappings
let error_code = ErrorCode::InternalError(Some(err.to_string()));
// TODO: log result_writer.write errors?
_ = self.result_writer.write(Err(error_code)).await;
return Err(Error::HttpBody(err));
}
None => break,
}
}
drop(self.stream_writer);
let maybe_trailers = if self.trailers.is_empty() {
None
} else {
Some(self.trailers.try_into().map_err(Error::InvalidTrailers)?)
};
match self.result_writer.write(Ok(maybe_trailers)).await {
Ok(()) => Ok(total_written),
Err(err) => Err(Error::ResultReaderClosed(err.value)),
}
}
/// Sends a [`http_body::Frame`].
///
/// - If the frame contains data, the data is written to this writer's
/// stream and the size of the written data is returned.
/// - If the frame contains trailers they are added to [`Self::trailers`]
/// and `Ok(0)` is returned.
pub async fn send_frame<T>(&mut self, frame: Frame<T>) -> Result<usize, Error>
where
T: Into<Vec<u8>>,
{
// Frame is a pseudo-enum which is either 'data' or 'trailers'
if frame.is_data() {
let data = frame.into_data().unwrap_or_else(|_| unreachable!()).into();
let data_len = data.len();
// write_all returns any unwritten data if the read end is dropped
let unwritten = self.stream_writer.write_all(data).await;
if !unwritten.is_empty() {
return Err(Error::StreamReaderClosed {
written: data_len - unwritten.len(),
unwritten,
});
}
Ok(data_len)
} else if frame.is_trailers() {
let trailers = frame.into_trailers().unwrap_or_else(|_| unreachable!());
self.trailers.extend(trailers);
Ok(0)
} else {
unreachable!("Frames are data or trailers");
}
}
}

View File

@@ -0,0 +1,307 @@
use super::{
to_internal_error_code,
RequestOptionsExtension,
IncomingRequestBody,
IncomingResponseBody,
Request as HttpRequest,
Response as HttpResponse,
body_writer::BodyWriter,
};
use crate::http::types::{
ErrorCode,
Fields,
HeaderError,
Headers,
Method,
Scheme,
Request as WasiHttpRequest,
Response as WasiHttpResponse,
};
use std::{
any::Any,
convert::TryFrom,
};
/// Converts a host-side HTTP response (`HttpResponse<T>`) into a WASI HTTP response (`WasiHttpResponse`).
///
/// This function bridges standard Rust `http` responses with the WASI HTTP model,
/// serializing status codes, headers, and body data into their WebAssembly-compatible
/// representations. It supports generic response body types and streams the response
/// asynchronously into the WASI environment.
///
/// # See Also
///
/// - [`http_from_wasi_response`] — converts a WASI response back into a host-side HTTP response.
/// - [`BodyWriter`] — for streaming body data into WASI.
/// - [`IncomingResponseBody`] — for handling pending or unstarted response states.
pub fn http_into_wasi_response<T>(mut resp: HttpResponse<T>) -> Result<WasiHttpResponse, ErrorCode>
where
T: http_body::Body + Any,
T::Data: Into<Vec<u8>>,
T::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>
{
if let Some(incoming_body) = (&mut resp as &mut dyn Any).downcast_mut::<IncomingResponseBody>()
{
if let Some(response) = incoming_body.take_unstarted() {
return Ok(response);
}
}
let headers = resp
.headers()
.clone()
.try_into()
.map_err(to_internal_error_code)?;
let (body_writer, body_rx, body_result_rx) = BodyWriter::new();
let (response, _future_result) =
WasiHttpResponse::new(headers, Some(body_rx), body_result_rx);
_ = response.set_status_code(resp.status().as_u16());
wit_bindgen::spawn(async move {
let mut body = std::pin::pin!(resp.into_body());
_ = body_writer.send_http_body(&mut body).await;
});
Ok(response)
}
/// Converts a WASI HTTP response (`WasiHttpResponse`) into a standard host-side
/// [`http::Response`] suitable for use with Rusts `http` ecosystem.
///
/// This function performs the reverse operation of [`http_into_wasi_response`], translating
/// the fields and body of a response from the WASI HTTP model into the conventional Rust
/// `http` crate representation.
///
/// # See Also
///
/// - [`http_into_wasi_response`] — the inverse conversion.
/// - [`IncomingResponseBody`] — for handling WASI-to-host body streams.
/// - [`ErrorCode`] — for standardized error reporting.
pub fn http_from_wasi_response(resp: WasiHttpResponse) -> Result<HttpResponse, ErrorCode> {
let mut builder = http::Response::builder().status(resp.get_status_code());
for (k, v) in resp.get_headers().copy_all() {
builder = builder.header(k, v);
}
let body = IncomingResponseBody::new(resp)?;
builder.body(body).map_err(to_internal_error_code) // TODO: downcast to more specific http error codes
}
/// Converts a host-side HTTP request (`HttpRequest<T>`) into a WASI HTTP request (`WasiHttpRequest`).
///
/// This function bridges between the standard Rust `http` crate request types and the WASI HTTP
/// request model used in WebAssembly components. It serializes headers, method, URI components,
/// and body streams into their WASI equivalents while preserving request metadata.
///
/// # See Also
///
/// - [`http_from_wasi_response`] — for converting WASI responses back into standard HTTP responses.
/// - [`http_into_wasi_response`] — for converting HTTP responses into WASI format.
/// - [`BodyWriter`] — for streaming request bodies to WASI.
/// - [`IncomingRequestBody`] — for managing unstarted or in-progress request states.
pub fn http_into_wasi_request<T>(mut req: HttpRequest<T>) -> Result<WasiHttpRequest, ErrorCode>
where
T: http_body::Body + Any,
T::Data: Into<Vec<u8>>,
T::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>
{
if let Some(incoming_body) = (&mut req as &mut dyn Any).downcast_mut::<IncomingRequestBody>()
{
if let Some(request) = incoming_body.take_unstarted() {
return Ok(request);
}
}
let (parts, body) = req.into_parts();
let options = parts
.extensions
.get::<RequestOptionsExtension>()
.cloned()
.map(|o| o.0);
let headers = parts
.headers
.try_into()
.map_err(to_internal_error_code)?;
let (body_writer, contents_rx, trailers_rx) = BodyWriter::new();
let (req, _result) = WasiHttpRequest::new(headers, Some(contents_rx), trailers_rx, options);
req.set_method(&parts.method.into())
.map_err(|()| ErrorCode::HttpRequestMethodInvalid)?;
let scheme = parts.uri.scheme().map(Into::into);
req.set_scheme(scheme.as_ref())
.map_err(|()| ErrorCode::HttpProtocolError)?;
req.set_authority(parts.uri.authority().map(|a| a.as_str()))
.map_err(|()| ErrorCode::HttpRequestUriInvalid)?;
req.set_path_with_query(parts.uri.path_and_query().map(|pq| pq.as_str()))
.map_err(|()| ErrorCode::HttpRequestUriInvalid)?;
wit_bindgen::spawn(async move {
let mut body = std::pin::pin!(body);
_ = body_writer.send_http_body(&mut body).await;
});
Ok(req)
}
/// Converts a WASI HTTP request (`WasiHttpRequest`) into a standard host-side
/// [`http::Request`].
///
/// This function performs the reverse of [`http_into_wasi_request`], translating a request
/// from the WASI HTTP model into a conventional Rust `http` request type. It reconstructs
/// the URI, method, headers, extensions, and body so that the request can be used directly
/// by host HTTP clients, servers, or middleware.
///
/// # See Also
///
/// - [`http_into_wasi_request`] — converts from host HTTP requests into WASI requests.
/// - [`http_from_wasi_request`] — converts from WASI responses into host responses.
/// - [`IncomingRequestBody`] — for streaming WASI request bodies into host code.
/// - [`RequestOptionsExtension`] — for carrying optional request metadata.
pub fn http_from_wasi_request(req: WasiHttpRequest) -> Result<HttpRequest, ErrorCode> {
let uri = {
let mut builder = http::Uri::builder();
if let Some(scheme) = req.get_scheme() {
builder = builder.scheme(scheme);
}
if let Some(authority) = req.get_authority() {
builder = builder.authority(authority);
}
if let Some(path_and_query) = req.get_path_with_query() {
builder = builder.path_and_query(path_and_query);
}
builder
.build()
.map_err(|_| ErrorCode::HttpRequestUriInvalid)?
};
let mut builder = http::Request::builder()
.method(req.get_method())
.uri(uri);
if let Some(options) = req.get_options().map(RequestOptionsExtension) {
builder = builder.extension(options);
}
for (k, v) in req.get_headers().copy_all() {
builder = builder.header(k, v);
}
let body = IncomingRequestBody::new(req)?;
builder.body(body).map_err(to_internal_error_code) // TODO: downcast to more specific http error codes
}
impl TryFrom<Scheme> for http::uri::Scheme {
type Error = http::uri::InvalidUri;
fn try_from(scheme: Scheme) -> Result<Self, Self::Error> {
match scheme {
Scheme::Http => Ok(http::uri::Scheme::HTTP),
Scheme::Https => Ok(http::uri::Scheme::HTTPS),
Scheme::Other(s) => s.parse(),
}
}
}
impl From<&http::uri::Scheme> for Scheme {
fn from(scheme: &http::uri::Scheme) -> Self {
match scheme {
s if s == &http::uri::Scheme::HTTP => Scheme::Http,
s if s == &http::uri::Scheme::HTTPS => Scheme::Https,
other => Scheme::Other(other.to_string()),
}
}
}
impl TryFrom<Method> for http::Method {
type Error = http::method::InvalidMethod;
fn try_from(method: Method) -> Result<Self, Self::Error> {
match method {
Method::Get => Ok(http::Method::GET),
Method::Post => Ok(http::Method::POST),
Method::Put => Ok(http::Method::PUT),
Method::Delete => Ok(http::Method::DELETE),
Method::Patch => Ok(http::Method::PATCH),
Method::Head => Ok(http::Method::HEAD),
Method::Options => Ok(http::Method::OPTIONS),
Method::Connect => Ok(http::Method::CONNECT),
Method::Trace => Ok(http::Method::TRACE),
Method::Other(o) => http::Method::from_bytes(o.as_bytes()),
}
}
}
impl From<&http::Method> for Method {
fn from(method: &http::Method) -> Self {
match method {
&http::Method::GET => Method::Get,
&http::Method::POST => Method::Post,
&http::Method::PUT => Method::Put,
&http::Method::DELETE => Method::Delete,
&http::Method::PATCH => Method::Patch,
&http::Method::HEAD => Method::Head,
&http::Method::OPTIONS => Method::Options,
&http::Method::CONNECT => Method::Connect,
&http::Method::TRACE => Method::Trace,
other => Method::Other(other.to_string()),
}
}
}
impl From<http::Method> for Method {
fn from(method: http::Method) -> Self {
(&method).into()
}
}
impl TryFrom<Headers> for http::HeaderMap {
type Error = ErrorCode;
fn try_from(headers: Headers) -> Result<Self, Self::Error> {
headers
.copy_all()
.into_iter()
.try_fold(http::HeaderMap::new(), |mut map, (k, v)| {
let v = http::HeaderValue::from_bytes(&v).map_err(to_internal_error_code)?;
let k: http::HeaderName = k.parse().map_err(to_internal_error_code)?;
map.append(k, v);
Ok(map)
})
}
}
impl TryFrom<http::HeaderMap> for Fields {
type Error = HeaderError;
fn try_from(map: http::HeaderMap) -> Result<Self, Self::Error> {
// https://docs.rs/http/1.3.1/http/header/struct.HeaderMap.html#method.into_iter-2
// For each yielded item that has None provided for the HeaderName, then
// the associated header name is the same as that of the previously
// yielded item. The first yielded item will have HeaderName set.
let mut last_name = None;
let iter = map.into_iter().map(move |(name, value)| {
if name.is_some() {
last_name = name;
}
let name = last_name
.as_ref()
.expect("HeaderMap::into_iter always returns Some(name) before None");
let value = bytes::Bytes::from_owner(value).to_vec();
(name.as_str().into(), value)
});
let entries = Vec::from_iter(iter);
Fields::from_list(&entries)
}
}

314
vendor/wasip3/src/http_compat/mod.rs vendored Normal file
View File

@@ -0,0 +1,314 @@
//! Extension types for wasip3::http
pub use body_writer::*;
mod body_writer;
pub use conversions::*;
mod conversions;
use crate::{
http::types::{self, ErrorCode},
wit_bindgen::{self, StreamResult},
wit_future,
};
use bytes::Bytes;
use http_body::SizeHint;
use std::{
pin::Pin,
task::{self, Poll},
};
const READ_FRAME_SIZE: usize = 16 * 1024;
/// The body type used for incoming HTTP requests.
///
/// This is a type alias for [`IncomingBody`] specialized with
/// [`types::Request`], representing the structured payload of an
/// inbound request as it is received and processed.
///
/// This type is typically used by components that consume HTTP
/// requests and need to read or stream the request body.
pub type IncomingRequestBody = IncomingBody<types::Request>;
/// The body type used for incoming HTTP responses.
///
/// This is a type alias for [`IncomingBody`] specialized with
/// [`types::Response`], representing the structured payload of an
/// inbound response as it is received and processed.
///
/// This type is typically used by components that handle HTTP
/// responses and need to read or stream the response body.
pub type IncomingResponseBody = IncomingBody<types::Response>;
/// A type alias for an HTTP request with a customizable body type.
///
/// This is a convenience wrapper around [`http::Request`], parameterized
/// by the body type `T`. By default, it uses [`IncomingRequestBody`],
/// which represents the standard incoming body used by this runtime.
///
/// # See also
/// - [`IncomingRequestBody`]: The body type for inbound HTTP requests.
/// - [`http::Request`]: The standard HTTP request type from the `http` crate.
pub type Request<T = IncomingRequestBody> = http::Request<T>;
/// A type alias for an HTTP response with a customizable body type.
///
/// This is a convenience wrapper around [`http::Response`], parameterized
/// by the body type `T`. By default, it uses [`IncomingResponseBody`],
/// which represents the standard incoming body type used by this runtime.
///
/// # See also
/// - [`IncomingResponseBody`]: The body type for inbound HTTP responses.
/// - [`http::Response`]: The standard HTTP response type from the `http` crate.
pub type Response<T = IncomingResponseBody> = http::Response<T>;
/// A wrapper around [`types::RequestOptions`] that implements [`Clone`]
pub struct RequestOptionsExtension(pub types::RequestOptions);
impl Clone for RequestOptionsExtension {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
/// Internal trait representing a readable inbound HTTP message.
///
/// Implemented by types that expose request or response headers
/// and provide mechanisms to consume the message body.
pub trait IncomingMessage: Unpin {
fn get_headers(&self) -> types::Headers;
fn consume_body(
self,
res: wit_bindgen::FutureReader<Result<(), ErrorCode>>,
) -> (
wit_bindgen::StreamReader<u8>,
wit_bindgen::FutureReader<Result<Option<types::Trailers>, ErrorCode>>,
);
}
impl IncomingMessage for types::Request {
fn get_headers(&self) -> types::Headers {
self.get_headers()
}
fn consume_body(
self,
res: wit_bindgen::FutureReader<Result<(), ErrorCode>>,
) -> (
wit_bindgen::StreamReader<u8>,
wit_bindgen::FutureReader<Result<Option<types::Trailers>, ErrorCode>>,
) {
Self::consume_body(self, res)
}
}
impl IncomingMessage for types::Response {
fn get_headers(&self) -> types::Headers {
self.get_headers()
}
fn consume_body(
self,
res: wit_bindgen::FutureReader<Result<(), ErrorCode>>,
) -> (
wit_bindgen::StreamReader<u8>,
wit_bindgen::FutureReader<Result<Option<types::Trailers>, ErrorCode>>,
) {
Self::consume_body(self, res)
}
}
/// A stream of Bytes, used when receiving bodies from the network.
pub struct IncomingBody<T> {
state: StartedState<T>,
content_length: Option<u64>,
}
enum StartedState<T> {
Unstarted(T),
Started {
#[allow(dead_code)]
result: wit_bindgen::FutureWriter<Result<(), ErrorCode>>,
state: IncomingState,
},
Empty,
}
impl<T: IncomingMessage> IncomingBody<T> {
/// Creates a new [`IncomingBody`] from the given incoming message.
///
/// This initializes the body in an *unstarted* state and extracts the
/// `Content-Length` header if present. The resulting instance can later
/// transition into a streaming or consumed state.
///
/// Returns an [`ErrorCode`] if the content length is invalid or cannot
/// be determined.
pub fn new(msg: T) -> Result<Self, ErrorCode> {
let content_length = get_content_length(msg.get_headers())?;
Ok(Self {
state: StartedState::Unstarted(msg),
content_length,
})
}
/// Takes ownership of the inner message if the body has not yet been started.
///
/// This method replaces the internal state with [`StartedState::Empty`]
/// and returns the contained message if it was still in the
/// *unstarted* state. Returns `None` otherwise.
pub fn take_unstarted(&mut self) -> Option<T> {
match self.state {
StartedState::Unstarted(_) => {
let StartedState::Unstarted(msg) =
std::mem::replace(&mut self.state, StartedState::Empty)
else {
unreachable!();
};
Some(msg)
}
_ => None,
}
}
fn ensure_started(&mut self) -> Result<&mut IncomingState, ErrorCode> {
if let StartedState::Unstarted(_) = self.state {
let msg = self.take_unstarted().unwrap();
let (result, reader) = wit_future::new(|| Ok(()));
let (stream, trailers) = msg.consume_body(reader);
self.state = StartedState::Started {
result,
state: IncomingState::Ready { stream, trailers },
};
};
match &mut self.state {
StartedState::Started { state, .. } => Ok(state),
StartedState::Unstarted(_) => unreachable!(),
StartedState::Empty => Err(to_internal_error_code(
"cannot use IncomingBody after call to take_unstarted",
)),
}
}
}
enum IncomingState {
Ready {
stream: wit_bindgen::StreamReader<u8>,
trailers: wit_bindgen::FutureReader<Result<Option<types::Trailers>, ErrorCode>>,
},
Reading(Pin<Box<dyn std::future::Future<Output = ReadResult> + 'static + Send>>),
Done,
}
enum ReadResult {
Trailers(Result<Option<types::Trailers>, ErrorCode>),
BodyChunk {
chunk: Vec<u8>,
stream: wit_bindgen::StreamReader<u8>,
trailers: wit_bindgen::FutureReader<Result<Option<types::Trailers>, ErrorCode>>,
},
}
impl<T: IncomingMessage> http_body::Body for IncomingBody<T> {
type Data = Bytes;
type Error = ErrorCode;
fn poll_frame(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
let state = self.ensure_started()?;
loop {
match state {
IncomingState::Ready { .. } => {
let IncomingState::Ready {
mut stream,
trailers,
} = std::mem::replace(state, IncomingState::Done)
else {
unreachable!();
};
*state = IncomingState::Reading(Box::pin(async move {
let (result, chunk) =
stream.read(Vec::with_capacity(READ_FRAME_SIZE)).await;
match result {
StreamResult::Complete(_n) => ReadResult::BodyChunk {
chunk,
stream,
trailers,
},
StreamResult::Cancelled => unreachable!(),
StreamResult::Dropped => ReadResult::Trailers(trailers.await),
}
}));
}
IncomingState::Reading(future) => {
match std::task::ready!(future.as_mut().poll(cx)) {
ReadResult::BodyChunk {
chunk,
stream,
trailers,
} => {
*state = IncomingState::Ready { stream, trailers };
break Poll::Ready(Some(Ok(http_body::Frame::data(chunk.into()))));
}
ReadResult::Trailers(trailers) => {
*state = IncomingState::Done;
match trailers {
Ok(Some(fields)) => {
let trailers = fields.try_into()?;
break Poll::Ready(Some(Ok(http_body::Frame::trailers(
trailers,
))));
}
Ok(None) => {}
Err(e) => {
break Poll::Ready(Some(Err(e)));
}
}
}
}
}
IncomingState::Done => break Poll::Ready(None),
}
}
}
fn is_end_stream(&self) -> bool {
matches!(
self.state,
StartedState::Started {
state: IncomingState::Done,
..
}
)
}
fn size_hint(&self) -> SizeHint {
let Some(n) = self.content_length else {
return SizeHint::default();
};
let mut size_hint = SizeHint::new();
size_hint.set_lower(0);
size_hint.set_upper(n);
size_hint
}
}
fn get_content_length(headers: types::Headers) -> Result<Option<u64>, ErrorCode> {
let values = headers.get(http::header::CONTENT_LENGTH.as_str());
if values.len() > 1 {
return Err(to_internal_error_code("multiple content-length values"));
}
let Some(value_bytes) = values.into_iter().next() else {
return Ok(None);
};
let value_str = std::str::from_utf8(&value_bytes).map_err(to_internal_error_code)?;
let value_i64: i64 = value_str.parse().map_err(to_internal_error_code)?;
let value = value_i64.try_into().map_err(to_internal_error_code)?;
Ok(Some(value))
}
fn to_internal_error_code(e: impl ::std::fmt::Display) -> ErrorCode {
ErrorCode::InternalError(Some(e.to_string()))
}

10543
vendor/wasip3/src/imports.rs vendored Normal file

File diff suppressed because it is too large Load Diff

280
vendor/wasip3/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,280 @@
//! Raw API bindings to the [WebAssembly System Interface p3 (WASIp3)][WASIp3]
//!
//! [WASIp3]: https://github.com/WebAssembly/WASI
//!
//! This crate provides Rust API bindings to the imports of [WASIp3] [worlds]
//! such as:
//!
//! * [`wasi:cli/command`]
//! * [`wasi:http/proxy`]
//!
//! This crate is procedurally generated with the [`wit-bindgen`] bindings
//! generator. Note that generated code is published to crates.io to slim this
//! crate down in terms of build dependencies and resources.
//!
//! # What is WASIp3?
//!
//! [WASIp3] is a set of APIs defined for the WebAssembly [Component Model] to
//! help components interact with the outside world. Core WebAssembly has no
//! intrinsic ability to access the host, for example `println!` don't work, but
//! [WASIp3] defines how to do so with the [`wasi:cli/stdio`] package.
//!
//! [WASIp3] is defined by an IDL called [WIT] using files that have the extension
//! `*.wit`. [WASIp3] and [WIT] are themselves then both defined in terms of the
//! [Component Model] in terms of types available and base semantics for APIs.
//!
//! [WASIp3] defines a number of standard "worlds" which are a description of a
//! what a WebAssembly component can import from an embedding and must export to
//! an embedding. An example world is [`wasi:cli/command`] which is a world for
//! running CLI applications. This world provides basic system utilities such as
//! clocks, a filesystem, CLI arguments, etc. The one required export is a main
//! function.
//!
//! The purpose of this crate is to provide pregenerated bindings to access
//! [WASIp3]-defined imports available to components.
//!
//! # What is a Component?
//!
//! An important aspect of [WASIp3] is that it is defined in terms of the
//! [Component Model]. The [Component Model] is a proposal for WebAssembly which
//! is a new format for wasm binaries, a component. A component contains "core"
//! WebAssembly modules (which are [standard WebAssembly modules]) but also has
//! the ability to do more:
//!
//! * A component can contain multiple core WebAssembly modules.
//! * Types used with component imports and exports are more comprehensive than
//! core WebAssembly. Core WebAssembly provides integers and floats, for
//! example, and components build on this and add strings, records (aka a Rust
//! `struct`), variants (aka a Rust `enum`), and resources (think a file
//! descriptor on Unix).
//! * A component provides procedural instructions of how to instantiate its
//! internal core WebAssembly modules with the imports it has.
//!
//! A full description of the component model is out of scope for this crate's
//! documentation but it suffices to say that [WASIp3], and this crate, are
//! intended to target components. Components use core WebAssembly modules as an
//! important technical detail, but the final output of this crate is intended
//! to be a component.
//!
//! # What are generated bindings?
//!
//! Above it was seen that [WASIp3] is defined with [WIT]. These programmatic
//! descriptions of [WASIp3] APIs are not suitable for use directly in Rust,
//! however these descriptions define how Rust can use them. Each [WIT] function
//! has a defined meaning in core WebAssembly via the [Canonical ABI]. This is a
//! lower level than most users want to operate at, however, so the generated
//! bindings in this crate serve as the bridge.
//!
//! More specifically the generated functions in this crate take the [Canonical
//! ABI] format of [WIT] functions and provide idiomatic Rust functions to call.
//! For example the [`wasi:cli/environment`] definition includes:
//!
//! ```wit
//! interface environment {
//! // ...
//! get-environment: func() -> list<tuple<string, string>>;
//! // ...
//! }
//! ```
//!
//! This corresponds to
//! [`wasi::cli::environment::get_environment`](crate::cli::environment::get_environment).
//!
//! Bindings are pre-generated in this crate with the [`wit-bindgen`] tool. You
//! can also generate your own bindings with [`wit-bindgen`] and [WASIp3] [WIT]
//! files too, but that's not covered by this crate.
//!
//! # WASIp3, WASIp2, and WASIp1
//!
//! The [WASIp3] version of the WASI standard is not yet complete nor stable. It
//! is under development and this crate represents a snapshot in time of what
//! the APIs may eventually look like.
//!
//! Users looking for stability should use WASIp2 (the `wasip2` crate) instead.
//! Users looking for core wasm, not components, should use the `wasip1` crate.
//!
//! # Crate Organization
//!
//! This crate is currently entirely generated by [`wit-bindgen`] which has the
//! following structure:
//!
//! * Each [WIT] package with bindings corresponds to a top-level module. For
//! example [`wasi:random`] can be found in the [`random`] module.
//! * Each [WIT] interface then corresponds to a submodule of its package's
//! module. For example [`wasi:random/insecure`] can be found in the
//! [`random::insecure`] module.
//! * Each [WIT] function has a Rust function with an idiomatic signature.
//! module. For example [`random::insecure::get_insecure_random_u64`].
//!
//! Note that [WIT] documentation is rendered as rustdoc documentation in these
//! APIs as well.
//!
//! # Using this Crate
//!
//! This crate is intended to be used with the `wasm32-wasip2` target to the
//! Rust compiler. You can compile your code as:
//!
//! ```sh
//! $ cargo build --target wasm32-wasip2
//! ```
//!
//! Eventually a `wasm32-wasip3` target will be added to the Rust compiler but
//! in the meantime the `wasm32-wasip2` target suffices. Using a WASIp2 target
//! means that the standard library will use WASIp2, but users of this crate
//! will use WASIp3.
//!
//! ## Export Macros
//!
//! In addition to providing bindings for imports this crate also provides
//! macros to export the `wasi:cli/run` and `wasi:http/proxy` worlds, see their
//! respective documentation for more information:
//!
//! - [`wasi::cli::command::export!`](crate::cli::command::export)
//! - [`wasi::http::proxy::export!`](crate::http::proxy::export)
//!
//! [worlds]: https://component-model.bytecodealliance.org/design/worlds.html
//! [`wasi:cli/command`]: https://github.com/WebAssembly/wasi-cli/
//! [`wasi:http/proxy`]: https://github.com/WebAssembly/wasi-http
//! [`wasi:cli/stdio`]: https://github.com/WebAssembly/wasi-cli/blob/main/wit-0.3.0-draft/stdio.wit
//! [`wit-bindgen`]: https://github.com/bytecodealliance/wit-bindgen/
//! [Component Model]: https://component-model.bytecodealliance.org/
//! [WIT]: https://component-model.bytecodealliance.org/design/wit.html
//! [standard WebAssembly modules]: https://webassembly.github.io/spec/
//! [Wasmtime]: https://github.com/bytecodealliance/wasmtime
//! [jco]: https://github.com/bytecodealliance/jco
//! [Canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md
//! [`wasi:cli/environment`]: https://github.com/WebAssembly/wasi-cli/blob/main/wit-0.3.0-draft/environment.wit
//! [`wasi:random`]: https://github.com/WebAssembly/wasi-random
//! [`wasi:random/insecure`]: https://github.com/WebAssembly/wasi-random/blob/main/wit-0.3.0-draft/insecure.wit
//! [`wasm-tools`]: https://github.com/bytecodealliance/wasm-tools
//! [adapters]: https://github.com/bytecodealliance/wasmtime/releases
// These modules are all auto-generated by `./ci/regenerate.sh`
#[allow(unused_imports)]
mod command;
mod imports;
#[allow(unused_imports)]
mod service;
// generated bindings start with the package namespace, which in this case is
// `wasi`, but the crate is already called wasi, so lift everything up one level
// to the root of this crate.
pub use imports::wasi::*;
pub use imports::{wit_future, wit_stream};
// Forward one `wit_future` impl for another as there's a few extra types in the
// `proxy::wit_future` type. This might need changes if wit-bindgen's internal
// implementation here changes.
impl<T> wit_future::FuturePayload for T
where
T: service::wit_future::FuturePayload,
{
const VTABLE: &'static wit_bindgen::rt::async_support::FutureVtable<Self> = T::VTABLE;
}
// Reexport wit-bindgen to downstream users don't have to depend on it.
pub use wit_bindgen;
// Expand the `cli` and `http` modules with `export!` macros for the
// command/proxy worlds, but also retain all the contents defined in the
// `bindings` module as well.
pub mod cli {
pub use super::imports::wasi::cli::*;
pub mod command {
/// Generate an exported instance of the `wasi:cli/command` world.
///
/// This macro generate the `#[no_mangle]` functions necessary to
/// export this interface. It takes an argument which is a type that
/// must implement the
/// [`exports::cli::run::Guest`](crate::exports::cli::run::Guest)
/// trait.
///
/// ```
/// struct MyCliRunner;
///
/// impl wasip3::exports::cli::run::Guest for MyCliRunner {
/// async fn run() -> Result<(), ()> {
/// // ...
/// # panic!();
/// }
/// }
///
/// wasip3::cli::command::export!(MyCliRunner);
/// ```
///
/// ## Incompatibility with `bin` target
///
/// This macro is not compatible with the Rust `bin` crate target
/// which instead use a `fn main()`. This macro can, however, be used
/// with the `cdylib` crate target.
///
/// <!--
/// The marker above hides the generated documentation by wit-bindgen for this
/// macro.
#[doc(inline)]
pub use crate::command::_export_command as export;
}
}
#[cfg(feature = "http-compat")]
pub mod http_compat;
pub mod http {
pub use super::service::wasi::http::*;
pub mod service {
/// Generate an exported instance of the `wasi:http/service` world.
///
/// This macro will generate `#[no_mangle]` functions as necessary to
/// export an implementation of the
/// [`exports::http::handler::Guest`](crate::exports::http::handler::Guest)
/// trait. This macro takes an argument which is a type that implements
/// this trait:
///
/// ```
/// use wasip3::http::types::{Request, Response, ErrorCode};
///
/// struct MyIncomingHandler;
///
/// impl wasip3::exports::http::handler::Guest for MyIncomingHandler {
/// async fn handle(request: Request) -> Result<Response, ErrorCode> {
/// // ...
/// # panic!();
/// }
/// }
///
/// wasip3::http::service::export!(MyIncomingHandler);
/// ```
///
/// <!--
/// The marker above hides the generated documentation by wit-bindgen
/// for this macro.
#[doc(inline)]
pub use crate::service::_export_service as export;
}
}
pub mod exports {
// This is required by the `export!` macros of this crate which assume that
// the types it's referring to show up as `exports::wasi::...`.
//
// This isn't part of the public interface, though, so hide this.
#[doc(hidden)]
pub mod wasi {
pub use crate::command::exports::wasi::*;
pub use crate::service::exports::wasi::*;
}
// These are the restructured public interface of this crate.
pub use crate::command::exports::wasi::cli;
pub use crate::service::exports::wasi::http;
}
// These macros are used by recursive invocations of the macro, but they're
// `#[doc(hidden)]` as it's not part of the public interface.
#[doc(hidden)]
pub use crate::command::_export_command;
#[doc(hidden)]
pub use crate::service::_export_service;

7274
vendor/wasip3/src/service.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1 @@
{"name":"wasip3","vers":"0.4.0+wasi-0.3.0-rc-2026-01-06","deps":[{"name":"bytes","req":"^1.10.1","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"http","req":"^1.3.1","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"http-body","req":"^1.0.1","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"thiserror","req":"^2.0.17","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"wit-bindgen","req":"^0.51.0","features":["async"],"optional":false,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"futures","req":"^0.3.31","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"http","req":"^1.3.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"wit-bindgen","req":"^0.51.0","features":["async-spawn"],"optional":false,"default_features":false,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false}],"features":{"http-compat":["dep:bytes","dep:http-body","dep:http","dep:thiserror","wit-bindgen/async-spawn"]},"features2":null,"cksum":"b4819e8613d63328a7d5e69408194778e266fa0405658ebd38f24f095561d2b6","yanked":null,"links":null,"rust_version":null,"v":2}

256
vendor/wasip3/wit/deps/cli.wit vendored Normal file
View File

@@ -0,0 +1,256 @@
package wasi:cli@0.3.0-rc-2026-01-06;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-environment: func() -> list<tuple<string, string>>;
/// Get the POSIX-style arguments to the program.
@since(version = 0.3.0-rc-2026-01-06)
get-arguments: func() -> list<string>;
/// Return a path that programs should use as their initial current working
/// directory, interpreting `.` as shorthand for this.
@since(version = 0.3.0-rc-2026-01-06)
get-initial-cwd: func() -> option<string>;
}
@since(version = 0.3.0-rc-2026-01-06)
interface exit {
/// Exit the current instance and any linked instances.
@since(version = 0.3.0-rc-2026-01-06)
exit: func(status: result);
/// Exit the current instance and any linked instances, reporting the
/// specified status code to the host.
///
/// The meaning of the code depends on the context, with 0 usually meaning
/// "success", and other values indicating various types of failure.
///
/// This function does not return; the effect is analogous to a trap, but
/// without the connotation that something bad has happened.
@unstable(feature = cli-exit-with-code)
exit-with-code: func(status-code: u8);
}
@since(version = 0.3.0-rc-2026-01-06)
interface run {
/// Run the program.
@since(version = 0.3.0-rc-2026-01-06)
run: async func() -> result;
}
@since(version = 0.3.0-rc-2026-01-06)
interface types {
@since(version = 0.3.0-rc-2026-01-06)
enum error-code {
/// Input/output error
io,
/// Invalid or incomplete multibyte or wide character
illegal-byte-sequence,
/// Broken pipe
pipe,
}
}
@since(version = 0.3.0-rc-2026-01-06)
interface stdin {
use types.{error-code};
/// Return a stream for reading from stdin.
///
/// This function returns a stream which provides data read from stdin,
/// and a future to signal read results.
///
/// If the stream's readable end is dropped the future will resolve to success.
///
/// If the stream's writable end is dropped the future will either resolve to
/// success if stdin was closed by the writer or to an error-code if reading
/// failed for some other reason.
///
/// Multiple streams may be active at the same time. The behavior of concurrent
/// reads is implementation-specific.
@since(version = 0.3.0-rc-2026-01-06)
read-via-stream: func() -> tuple<stream<u8>, future<result<_, error-code>>>;
}
@since(version = 0.3.0-rc-2026-01-06)
interface stdout {
use types.{error-code};
/// Write the given stream to stdout.
///
/// If the stream's writable end is dropped this function will either return
/// success once the entire contents of the stream have been written or an
/// error-code representing a failure.
///
/// Otherwise if there is an error the readable end of the stream will be
/// dropped and this function will return an error-code.
@since(version = 0.3.0-rc-2026-01-06)
write-via-stream: async func(data: stream<u8>) -> result<_, error-code>;
}
@since(version = 0.3.0-rc-2026-01-06)
interface stderr {
use types.{error-code};
/// Write the given stream to stderr.
///
/// If the stream's writable end is dropped this function will either return
/// success once the entire contents of the stream have been written or an
/// error-code representing a failure.
///
/// Otherwise if there is an error the readable end of the stream will be
/// dropped and this function will return an error-code.
@since(version = 0.3.0-rc-2026-01-06)
write-via-stream: async func(data: stream<u8>) -> result<_, error-code>;
}
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
interface terminal-input {
/// The input side of a terminal.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
interface terminal-output {
/// The output side of a terminal.
@since(version = 0.3.0-rc-2026-01-06)
resource terminal-output;
}
/// An interface providing an optional `terminal-input` for stdin as a
/// link-time authority.
@since(version = 0.3.0-rc-2026-01-06)
interface terminal-stdin {
@since(version = 0.3.0-rc-2026-01-06)
use terminal-input.{terminal-input};
/// If stdin is connected to a terminal, return a `terminal-input` handle
/// allowing further interaction with it.
@since(version = 0.3.0-rc-2026-01-06)
get-terminal-stdin: func() -> option<terminal-input>;
}
/// An interface providing an optional `terminal-output` for stdout as a
/// link-time authority.
@since(version = 0.3.0-rc-2026-01-06)
interface terminal-stdout {
@since(version = 0.3.0-rc-2026-01-06)
use terminal-output.{terminal-output};
/// If stdout is connected to a terminal, return a `terminal-output` handle
/// allowing further interaction with it.
@since(version = 0.3.0-rc-2026-01-06)
get-terminal-stdout: func() -> option<terminal-output>;
}
/// An interface providing an optional `terminal-output` for stderr as a
/// link-time authority.
@since(version = 0.3.0-rc-2026-01-06)
interface terminal-stderr {
@since(version = 0.3.0-rc-2026-01-06)
use terminal-output.{terminal-output};
/// If stderr is connected to a terminal, return a `terminal-output` handle
/// allowing further interaction with it.
@since(version = 0.3.0-rc-2026-01-06)
get-terminal-stderr: func() -> option<terminal-output>;
}
@since(version = 0.3.0-rc-2026-01-06)
world imports {
@since(version = 0.3.0-rc-2026-01-06)
import environment;
@since(version = 0.3.0-rc-2026-01-06)
import exit;
@since(version = 0.3.0-rc-2026-01-06)
import types;
@since(version = 0.3.0-rc-2026-01-06)
import stdin;
@since(version = 0.3.0-rc-2026-01-06)
import stdout;
@since(version = 0.3.0-rc-2026-01-06)
import stderr;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-input;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-output;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-stdin;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-stdout;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-stderr;
import wasi:clocks/types@0.3.0-rc-2026-01-06;
import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
@unstable(feature = clocks-timezone)
import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
import wasi:filesystem/types@0.3.0-rc-2026-01-06;
import wasi:filesystem/preopens@0.3.0-rc-2026-01-06;
import wasi:sockets/types@0.3.0-rc-2026-01-06;
import wasi:sockets/ip-name-lookup@0.3.0-rc-2026-01-06;
import wasi:random/random@0.3.0-rc-2026-01-06;
import wasi:random/insecure@0.3.0-rc-2026-01-06;
import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
}
@since(version = 0.3.0-rc-2026-01-06)
world command {
@since(version = 0.3.0-rc-2026-01-06)
import environment;
@since(version = 0.3.0-rc-2026-01-06)
import exit;
@since(version = 0.3.0-rc-2026-01-06)
import types;
@since(version = 0.3.0-rc-2026-01-06)
import stdin;
@since(version = 0.3.0-rc-2026-01-06)
import stdout;
@since(version = 0.3.0-rc-2026-01-06)
import stderr;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-input;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-output;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-stdin;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-stdout;
@since(version = 0.3.0-rc-2026-01-06)
import terminal-stderr;
import wasi:clocks/types@0.3.0-rc-2026-01-06;
import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
@unstable(feature = clocks-timezone)
import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
import wasi:filesystem/types@0.3.0-rc-2026-01-06;
import wasi:filesystem/preopens@0.3.0-rc-2026-01-06;
import wasi:sockets/types@0.3.0-rc-2026-01-06;
import wasi:sockets/ip-name-lookup@0.3.0-rc-2026-01-06;
import wasi:random/random@0.3.0-rc-2026-01-06;
import wasi:random/insecure@0.3.0-rc-2026-01-06;
import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
@since(version = 0.3.0-rc-2026-01-06)
export run;
}

161
vendor/wasip3/wit/deps/clocks.wit vendored Normal file
View File

@@ -0,0 +1,161 @@
package wasi:clocks@0.3.0-rc-2026-01-06;
/// This interface common types used throughout wasi:clocks.
@since(version = 0.3.0-rc-2026-01-06)
interface types {
/// A duration of time, in nanoseconds.
@since(version = 0.3.0-rc-2026-01-06)
type duration = u64;
}
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
interface monotonic-clock {
use types.{duration};
/// A mark on a monotonic clock is a number of nanoseconds since an
/// unspecified initial value, and can only be compared to instances from
/// the same monotonic-clock.
@since(version = 0.3.0-rc-2026-01-06)
type mark = 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.
///
/// For completeness, this function traps if it's not possible to represent
/// the value of the clock in a `mark`. Consequently, implementations
/// should ensure that the starting time is low enough to avoid the
/// possibility of overflow in practice.
@since(version = 0.3.0-rc-2026-01-06)
now: func() -> mark;
/// Query the resolution of the clock. Returns the duration of time
/// corresponding to a clock tick.
@since(version = 0.3.0-rc-2026-01-06)
get-resolution: func() -> duration;
/// Wait until the specified mark has occurred.
@since(version = 0.3.0-rc-2026-01-06)
wait-until: async func(when: mark);
/// Wait for the specified duration to elapse.
@since(version = 0.3.0-rc-2026-01-06)
wait-for: async func(how-long: duration);
}
/// WASI System Clock is a clock API intended to let users query the current
/// time. The clock is not necessarily monotonic as it may be reset.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
///
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
interface system-clock {
use types.{duration};
/// An "instant", or "exact time", is a point in time without regard to any
/// time zone: just the time since a particular external reference point,
/// often called an "epoch".
///
/// Here, the epoch is 1970-01-01T00:00:00Z, also known as
/// [POSIX's Seconds Since the Epoch], also known as [Unix Time].
///
/// Note that even if the seconds field is negative, incrementing
/// nanoseconds always represents moving forwards in time.
/// For example, `{ -1 seconds, 999999999 nanoseconds }` represents the
/// instant one nanosecond before the epoch.
/// For more on various different ways to represent time, see
/// https://tc39.es/proposal-temporal/docs/timezone.html
///
/// [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
@since(version = 0.3.0-rc-2026-01-06)
record instant {
seconds: s64,
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 nanoseconds field of the output is always less than 1000000000.
@since(version = 0.3.0-rc-2026-01-06)
now: func() -> instant;
/// Query the resolution of the clock. Returns the smallest duration of time
/// that the implementation permits distinguishing.
@since(version = 0.3.0-rc-2026-01-06)
get-resolution: func() -> duration;
}
@unstable(feature = clocks-timezone)
interface timezone {
@unstable(feature = clocks-timezone)
use system-clock.{instant};
/// Return the IANA identifier of the currently configured timezone. This
/// should be an identifier from the IANA Time Zone Database.
///
/// For displaying to a user, the identifier should be converted into a
/// localized name by means of an internationalization API.
///
/// If the implementation does not expose an actual timezone, or is unable
/// to provide mappings from times to deltas between the configured timezone
/// and UTC, or determining the current timezone fails, or the timezone does
/// not have an IANA identifier, this returns nothing.
@unstable(feature = clocks-timezone)
iana-id: func() -> option<string>;
/// The number of nanoseconds difference between UTC time and the local
/// time of the currently configured timezone, at the exact time of
/// `instant`.
///
/// The magnitude of the returned value will always be less than
/// 86,400,000,000,000 which is the number of nanoseconds in a day
/// (24*60*60*1e9).
///
/// If the implementation does not expose an actual timezone, or is unable
/// to provide mappings from times to deltas between the configured timezone
/// and UTC, or determining the current timezone fails, this returns
/// nothing.
@unstable(feature = clocks-timezone)
utc-offset: func(when: instant) -> option<s64>;
/// Returns a string that is suitable to assist humans in debugging whether
/// any timezone is available, and if so, which. This may be the same string
/// as `iana-id`, or a formatted representation of the UTC offset such as
/// `-04:00`, or something else.
///
/// 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.
@unstable(feature = clocks-timezone)
to-debug-string: func() -> string;
}
@since(version = 0.3.0-rc-2026-01-06)
world imports {
@since(version = 0.3.0-rc-2026-01-06)
import types;
@since(version = 0.3.0-rc-2026-01-06)
import monotonic-clock;
@since(version = 0.3.0-rc-2026-01-06)
import system-clock;
@unstable(feature = clocks-timezone)
import timezone;
}

553
vendor/wasip3/wit/deps/filesystem.wit vendored Normal file
View File

@@ -0,0 +1,553 @@
package wasi:filesystem@0.3.0-rc-2026-01-06;
/// 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
@since(version = 0.3.0-rc-2026-01-06)
interface types {
@since(version = 0.3.0-rc-2026-01-06)
use wasi:clocks/system-clock@0.3.0-rc-2026-01-06.{instant};
/// File size or length of a region within a file.
@since(version = 0.3.0-rc-2026-01-06)
type filesize = u64;
/// The type of a filesystem object referenced by a descriptor.
///
/// Note: This was called `filetype` in earlier versions of WASI.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
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 integrity
/// 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,
}
/// Flags determining the method of how paths are resolved.
@since(version = 0.3.0-rc-2026-01-06)
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`.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
type link-count = u64;
/// File attributes.
///
/// Note: This was called `filestat` in earlier versions of WASI.
@since(version = 0.3.0-rc-2026-01-06)
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<instant>,
/// Last data modification timestamp.
///
/// If the `option` is none, the platform doesn't maintain a
/// modification timestamp for this file.
data-modification-timestamp: option<instant>,
/// 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<instant>,
}
/// When setting a timestamp, this gives the value to set it to.
@since(version = 0.3.0-rc-2026-01-06)
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(instant),
}
/// 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,
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
resource descriptor {
/// Return a stream for reading from a file.
///
/// Multiple read, write, and append streams may be active on the same open
/// file and they do not interfere with each other.
///
/// This function returns a `stream` which provides the data received from the
/// file, and a `future` providing additional error information in case an
/// error is encountered.
///
/// If no error is encountered, `stream.read` on the `stream` will return
/// `read-status::closed` with no `error-context` and the future resolves to
/// the value `ok`. If an error is encountered, `stream.read` on the
/// `stream` returns `read-status::closed` with an `error-context` and the future
/// resolves to `err` with an `error-code`.
///
/// Note: This is similar to `pread` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
read-via-stream: func(offset: filesize) -> tuple<stream<u8>, future<result<_, error-code>>>;
/// Return a stream for writing to a file, if available.
///
/// May fail with an error-code describing why the file cannot be written.
///
/// 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.
///
/// This function returns once either full contents of the stream are
/// written or an error is encountered.
///
/// Note: This is similar to `pwrite` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
write-via-stream: async func(data: stream<u8>, offset: filesize) -> result<_, error-code>;
/// Return a stream for appending to a file, if available.
///
/// May fail with an error-code describing why the file cannot be appended.
///
/// This function returns once either full contents of the stream are
/// written or an error is encountered.
///
/// Note: This is similar to `write` with `O_APPEND` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
append-via-stream: async func(data: stream<u8>) -> result<_, error-code>;
/// Provide file advisory information on a descriptor.
///
/// This is similar to `posix_fadvise` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
advise: async func(offset: filesize, length: filesize, 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.
@since(version = 0.3.0-rc-2026-01-06)
sync-data: async 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.
@since(version = 0.3.0-rc-2026-01-06)
get-flags: async func() -> result<descriptor-flags, error-code>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
get-type: async func() -> result<descriptor-type, error-code>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
set-size: async 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.
@since(version = 0.3.0-rc-2026-01-06)
set-times: async func(data-access-timestamp: new-timestamp, data-modification-timestamp: new-timestamp) -> result<_, error-code>;
/// 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.
///
/// This function returns a future, which will resolve to an error code if
/// reading full contents of the directory fails.
@since(version = 0.3.0-rc-2026-01-06)
read-directory: async func() -> tuple<stream<directory-entry>, future<result<_, error-code>>>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
sync: async func() -> result<_, error-code>;
/// Create a directory.
///
/// Note: This is similar to `mkdirat` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
create-directory-at: async func(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.
@since(version = 0.3.0-rc-2026-01-06)
stat: async func() -> result<descriptor-stat, error-code>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
stat-at: async func(path-flags: path-flags, path: string) -> result<descriptor-stat, error-code>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
set-times-at: async func(path-flags: path-flags, path: string, data-access-timestamp: new-timestamp, data-modification-timestamp: new-timestamp) -> result<_, error-code>;
/// Create a hard link.
///
/// Fails with `error-code::no-entry` if the old path does not exist,
/// with `error-code::exist` if the new path already exists, and
/// `error-code::not-permitted` if the old path is not a file.
///
/// Note: This is similar to `linkat` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
link-at: async func(old-path-flags: path-flags, old-path: string, new-descriptor: borrow<descriptor>, new-path: string) -> result<_, error-code>;
/// Open a file or directory.
///
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
open-at: async func(path-flags: path-flags, path: string, open-flags: open-flags, %flags: descriptor-flags) -> result<descriptor, error-code>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
readlink-at: async func(path: string) -> result<string, error-code>;
/// 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.
@since(version = 0.3.0-rc-2026-01-06)
remove-directory-at: async func(path: string) -> result<_, error-code>;
/// Rename a filesystem object.
///
/// Note: This is similar to `renameat` in POSIX.
@since(version = 0.3.0-rc-2026-01-06)
rename-at: async func(old-path: string, new-descriptor: borrow<descriptor>, 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.
@since(version = 0.3.0-rc-2026-01-06)
symlink-at: async func(old-path: string, 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.
@since(version = 0.3.0-rc-2026-01-06)
unlink-file-at: async func(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.
@since(version = 0.3.0-rc-2026-01-06)
is-same-object: async func(other: borrow<descriptor>) -> 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 encouraged 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.
@since(version = 0.3.0-rc-2026-01-06)
metadata-hash: async func() -> result<metadata-hash-value, error-code>;
/// 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`.
@since(version = 0.3.0-rc-2026-01-06)
metadata-hash-at: async func(path-flags: path-flags, path: string) -> result<metadata-hash-value, error-code>;
}
}
@since(version = 0.3.0-rc-2026-01-06)
interface preopens {
@since(version = 0.3.0-rc-2026-01-06)
use types.{descriptor};
/// Return the set of preopened directories, and their paths.
@since(version = 0.3.0-rc-2026-01-06)
get-directories: func() -> list<tuple<descriptor, string>>;
}
@since(version = 0.3.0-rc-2026-01-06)
world imports {
@since(version = 0.3.0-rc-2026-01-06)
import wasi:clocks/types@0.3.0-rc-2026-01-06;
@since(version = 0.3.0-rc-2026-01-06)
import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
@since(version = 0.3.0-rc-2026-01-06)
import types;
@since(version = 0.3.0-rc-2026-01-06)
import preopens;
}

457
vendor/wasip3/wit/deps/http.wit vendored Normal file
View File

@@ -0,0 +1,457 @@
package wasi:http@0.3.0-rc-2026-01-06;
/// This interface defines all of the types and methods for implementing HTTP
/// Requests and Responses, as well as their headers, trailers, and bodies.
interface types {
use wasi:clocks/types@0.3.0-rc-2026-01-06.{duration};
/// This type corresponds to HTTP standard Methods.
variant method {
get,
head,
post,
put,
delete,
connect,
options,
trace,
patch,
other(string),
}
/// This type corresponds to HTTP standard Related Schemes.
variant scheme {
HTTP,
HTTPS,
other(string),
}
/// Defines the case payload type for `DNS-error` above:
record DNS-error-payload {
rcode: option<string>,
info-code: option<u16>,
}
/// Defines the case payload type for `TLS-alert-received` above:
record TLS-alert-received-payload {
alert-id: option<u8>,
alert-message: option<string>,
}
/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
record field-size-payload {
field-name: option<string>,
field-size: option<u32>,
}
/// These cases are inspired by the IANA HTTP Proxy Error Types:
/// <https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types>
variant error-code {
DNS-timeout,
DNS-error(DNS-error-payload),
destination-not-found,
destination-unavailable,
destination-IP-prohibited,
destination-IP-unroutable,
connection-refused,
connection-terminated,
connection-timeout,
connection-read-timeout,
connection-write-timeout,
connection-limit-reached,
TLS-protocol-error,
TLS-certificate-error,
TLS-alert-received(TLS-alert-received-payload),
HTTP-request-denied,
HTTP-request-length-required,
HTTP-request-body-size(option<u64>),
HTTP-request-method-invalid,
HTTP-request-URI-invalid,
HTTP-request-URI-too-long,
HTTP-request-header-section-size(option<u32>),
HTTP-request-header-size(option<field-size-payload>),
HTTP-request-trailer-section-size(option<u32>),
HTTP-request-trailer-size(field-size-payload),
HTTP-response-incomplete,
HTTP-response-header-section-size(option<u32>),
HTTP-response-header-size(field-size-payload),
HTTP-response-body-size(option<u64>),
HTTP-response-trailer-section-size(option<u32>),
HTTP-response-trailer-size(field-size-payload),
HTTP-response-transfer-coding(option<string>),
HTTP-response-content-coding(option<string>),
HTTP-response-timeout,
HTTP-upgrade-failed,
HTTP-protocol-error,
loop-detected,
configuration-error,
/// This is a catch-all error for anything that doesn't fit cleanly into a
/// more specific case. It also includes an optional string for an
/// unstructured description of the error. Users should not depend on the
/// string for diagnosing errors, as it's not required to be consistent
/// between implementations.
internal-error(option<string>),
}
/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
variant header-error {
/// This error indicates that a `field-name` or `field-value` was
/// syntactically invalid when used with an operation that sets headers in a
/// `fields`.
invalid-syntax,
/// This error indicates that a forbidden `field-name` was used when trying
/// to set a header in a `fields`.
forbidden,
/// This error indicates that the operation on the `fields` was not
/// permitted because the fields are immutable.
immutable,
}
/// This type enumerates the different kinds of errors that may occur when
/// setting fields of a `request-options` resource.
variant request-options-error {
/// Indicates the specified field is not supported by this implementation.
not-supported,
/// Indicates that the operation on the `request-options` was not permitted
/// because it is immutable.
immutable,
}
/// Field names are always strings.
///
/// Field names should always be treated as case insensitive by the `fields`
/// resource for the purposes of equality checking.
type field-name = string;
/// Field values should always be ASCII strings. However, in
/// reality, HTTP implementations often have to interpret malformed values,
/// so they are provided as a list of bytes.
type field-value = list<u8>;
/// This following block defines the `fields` resource which corresponds to
/// HTTP standard Fields. Fields are a common representation used for both
/// Headers and Trailers.
///
/// A `fields` may be mutable or immutable. A `fields` created using the
/// constructor, `from-list`, or `clone` will be mutable, but a `fields`
/// resource given by other means (including, but not limited to,
/// `request.headers`) might be be immutable. In an immutable fields, the
/// `set`, `append`, and `delete` operations will fail with
/// `header-error.immutable`.
///
/// A `fields` resource should store `field-name`s and `field-value`s in their
/// original casing used to construct or mutate the `fields` resource. The `fields`
/// resource should use that original casing when serializing the fields for
/// transport or when returning them from a method.
resource fields {
/// Construct an empty HTTP Fields.
///
/// The resulting `fields` is mutable.
constructor();
/// Construct an HTTP Fields.
///
/// The resulting `fields` is mutable.
///
/// The list represents each name-value pair in the Fields. Names
/// which have multiple values are represented by multiple entries in this
/// list with the same name.
///
/// The tuple is a pair of the field name, represented as a string, and
/// Value, represented as a list of bytes. In a valid Fields, all names
/// and values are valid UTF-8 strings. However, values are not always
/// well-formed, so they are represented as a raw list of bytes.
///
/// An error result will be returned if any header or value was
/// syntactically invalid, or if a header was forbidden.
from-list: static func(entries: list<tuple<field-name, field-value>>) -> result<fields, header-error>;
/// Get all of the values corresponding to a name. If the name is not present
/// in this `fields`, an empty list is returned. However, if the name is
/// present but empty, this is represented by a list with one or more
/// empty field-values present.
get: func(name: field-name) -> list<field-value>;
/// Returns `true` when the name is present in this `fields`. If the name is
/// syntactically invalid, `false` is returned.
has: func(name: field-name) -> bool;
/// Set all of the values for a name. Clears any existing values for that
/// name, if they have been set.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
set: func(name: field-name, value: list<field-value>) -> result<_, header-error>;
/// Delete all values for a name. Does nothing if no values for the name
/// exist.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
delete: func(name: field-name) -> result<_, header-error>;
/// Delete all values for a name. Does nothing if no values for the name
/// exist.
///
/// Returns all values previously corresponding to the name, if any.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
get-and-delete: func(name: field-name) -> result<list<field-value>, header-error>;
/// Append a value for a name. Does not change or delete any existing
/// values for that name.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
append: func(name: field-name, value: field-value) -> result<_, header-error>;
/// Retrieve the full set of names and values in the Fields. Like the
/// constructor, the list represents each name-value pair.
///
/// The outer list represents each name-value pair in the Fields. Names
/// which have multiple values are represented by multiple entries in this
/// list with the same name.
///
/// The names and values are always returned in the original casing and in
/// the order in which they will be serialized for transport.
copy-all: func() -> list<tuple<field-name, field-value>>;
/// Make a deep copy of the Fields. Equivalent in behavior to calling the
/// `fields` constructor on the return value of `copy-all`. The resulting
/// `fields` is mutable.
clone: func() -> fields;
}
/// Headers is an alias for Fields.
type headers = fields;
/// Trailers is an alias for Fields.
type trailers = fields;
/// Represents an HTTP Request.
resource request {
/// Construct a new `request` with a default `method` of `GET`, and
/// `none` values for `path-with-query`, `scheme`, and `authority`.
///
/// `headers` is the HTTP Headers for the Request.
///
/// `contents` is the optional body content stream with `none`
/// representing a zero-length content stream.
/// Once it is closed, `trailers` future must resolve to a result.
/// If `trailers` resolves to an error, underlying connection
/// will be closed immediately.
///
/// `options` is optional `request-options` resource to be used
/// if the request is sent over a network connection.
///
/// It is possible to construct, or manipulate with the accessor functions
/// below, a `request` with an invalid combination of `scheme`
/// and `authority`, or `headers` which are not permitted to be sent.
/// It is the obligation of the `handler.handle` implementation
/// to reject invalid constructions of `request`.
///
/// The returned future resolves to result of transmission of this request.
new: static func(headers: headers, contents: option<stream<u8>>, trailers: future<result<option<trailers>, error-code>>, options: option<request-options>) -> tuple<request, future<result<_, error-code>>>;
/// Get the Method for the Request.
get-method: func() -> method;
/// Set the Method for the Request. Fails if the string present in a
/// `method.other` argument is not a syntactically valid method.
set-method: func(method: method) -> result;
/// Get the combination of the HTTP Path and Query for the Request. When
/// `none`, this represents an empty Path and empty Query.
get-path-with-query: func() -> option<string>;
/// Set the combination of the HTTP Path and Query for the Request. When
/// `none`, this represents an empty Path and empty Query. Fails is the
/// string given is not a syntactically valid path and query uri component.
set-path-with-query: func(path-with-query: option<string>) -> result;
/// Get the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme.
get-scheme: func() -> option<scheme>;
/// Set the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme. Fails if the
/// string given is not a syntactically valid uri scheme.
set-scheme: func(scheme: option<scheme>) -> result;
/// Get the authority of the Request's target URI. A value of `none` may be used
/// with Related Schemes which do not require an authority. The HTTP and
/// HTTPS schemes always require an authority.
get-authority: func() -> option<string>;
/// Set the authority of the Request's target URI. A value of `none` may be used
/// with Related Schemes which do not require an authority. The HTTP and
/// HTTPS schemes always require an authority. Fails if the string given is
/// not a syntactically valid URI authority.
set-authority: func(authority: option<string>) -> result;
/// Get the `request-options` to be associated with this request
///
/// The returned `request-options` resource is immutable: `set-*` operations
/// will fail if invoked.
///
/// This `request-options` resource is a child: it must be dropped before
/// the parent `request` is dropped, or its ownership is transferred to
/// another component by e.g. `handler.handle`.
get-options: func() -> option<request-options>;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
get-headers: func() -> headers;
/// Get body of the Request.
///
/// Stream returned by this method represents the contents of the body.
/// Once the stream is reported as closed, callers should await the returned
/// future to determine whether the body was received successfully.
/// The future will only resolve after the stream is reported as closed.
///
/// This function takes a `res` future as a parameter, which can be used to
/// communicate an error in handling of the request.
///
/// Note that function will move the `request`, but references to headers or
/// request options acquired from it previously will remain valid.
consume-body: static func(this: request, res: future<result<_, error-code>>) -> tuple<stream<u8>, future<result<option<trailers>, error-code>>>;
}
/// Parameters for making an HTTP Request. Each of these parameters is
/// currently an optional timeout applicable to the transport layer of the
/// HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound an
/// asynchronous call.
resource request-options {
/// Construct a default `request-options` value.
constructor();
/// The timeout for the initial connect to the HTTP Server.
get-connect-timeout: func() -> option<duration>;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported or that this
/// handle is immutable.
set-connect-timeout: func(duration: option<duration>) -> result<_, request-options-error>;
/// The timeout for receiving the first byte of the Response body.
get-first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported or that
/// this handle is immutable.
set-first-byte-timeout: func(duration: option<duration>) -> result<_, request-options-error>;
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
get-between-bytes-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported or that this handle is immutable.
set-between-bytes-timeout: func(duration: option<duration>) -> result<_, request-options-error>;
/// Make a deep copy of the `request-options`.
/// The resulting `request-options` is mutable.
clone: func() -> request-options;
}
/// This type corresponds to the HTTP standard Status Code.
type status-code = u16;
/// Represents an HTTP Response.
resource response {
/// Construct a new `response`, with a default `status-code` of `200`.
/// If a different `status-code` is needed, it must be set via the
/// `set-status-code` method.
///
/// `headers` is the HTTP Headers for the Response.
///
/// `contents` is the optional body content stream with `none`
/// representing a zero-length content stream.
/// Once it is closed, `trailers` future must resolve to a result.
/// If `trailers` resolves to an error, underlying connection
/// will be closed immediately.
///
/// The returned future resolves to result of transmission of this response.
new: static func(headers: headers, contents: option<stream<u8>>, trailers: future<result<option<trailers>, error-code>>) -> tuple<response, future<result<_, error-code>>>;
/// Get the HTTP Status Code for the Response.
get-status-code: func() -> status-code;
/// Set the HTTP Status Code for the Response. Fails if the status-code
/// given is not a valid http status code.
set-status-code: func(status-code: status-code) -> result;
/// Get the headers associated with the Response.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
get-headers: func() -> headers;
/// Get body of the Response.
///
/// Stream returned by this method represents the contents of the body.
/// Once the stream is reported as closed, callers should await the returned
/// future to determine whether the body was received successfully.
/// The future will only resolve after the stream is reported as closed.
///
/// This function takes a `res` future as a parameter, which can be used to
/// communicate an error in handling of the response.
///
/// Note that function will move the `response`, but references to headers
/// acquired from it previously will remain valid.
consume-body: static func(this: response, res: future<result<_, error-code>>) -> tuple<stream<u8>, future<result<option<trailers>, error-code>>>;
}
}
/// This interface defines a handler of HTTP Requests.
///
/// In a `wasi:http/service` this interface is exported to respond to an
/// incoming HTTP Request with a Response.
///
/// In `wasi:http/middleware` this interface is both exported and imported as
/// the "downstream" and "upstream" directions of the middleware chain.
interface handler {
use types.{request, response, error-code};
/// This function may be called with either an incoming request read from the
/// network or a request synthesized or forwarded by another component.
handle: async func(request: request) -> result<response, error-code>;
}
/// This interface defines an HTTP client for sending "outgoing" requests.
///
/// Most components are expected to import this interface to provide the
/// capability to send HTTP requests to arbitrary destinations on a network.
///
/// The type signature of `client.send` is the same as `handler.handle`. This
/// duplication is currently necessary because some Component Model tooling
/// (including WIT itself) is unable to represent a component importing two
/// instances of the same interface. A `client.send` import may be linked
/// directly to a `handler.handle` export to bypass the network.
interface client {
use types.{request, response, error-code};
/// This function may be used to either send an outgoing request over the
/// network or to forward it to another component.
send: async func(request: request) -> result<response, error-code>;
}
/// The `wasi:http/service` world captures a broad category of HTTP services
/// including web applications, API servers, and proxies. It may be `include`d
/// in more specific worlds such as `wasi:http/middleware`.
world service {
import wasi:cli/types@0.3.0-rc-2026-01-06;
import wasi:cli/stdout@0.3.0-rc-2026-01-06;
import wasi:cli/stderr@0.3.0-rc-2026-01-06;
import wasi:cli/stdin@0.3.0-rc-2026-01-06;
import wasi:clocks/types@0.3.0-rc-2026-01-06;
import types;
import client;
import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
@unstable(feature = clocks-timezone)
import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
import wasi:random/random@0.3.0-rc-2026-01-06;
import wasi:random/insecure@0.3.0-rc-2026-01-06;
import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
export handler;
}
/// The `wasi:http/middleware` world captures HTTP services that forward HTTP
/// Requests to another handler.
///
/// Components may implement this world to allow them to participate in handler
/// "chains" where a `request` flows through handlers on its way to some terminal
/// `service` and corresponding `response` flows in the opposite direction.
world middleware {
import wasi:clocks/types@0.3.0-rc-2026-01-06;
import types;
import handler;
import wasi:cli/types@0.3.0-rc-2026-01-06;
import wasi:cli/stdout@0.3.0-rc-2026-01-06;
import wasi:cli/stderr@0.3.0-rc-2026-01-06;
import wasi:cli/stdin@0.3.0-rc-2026-01-06;
import client;
import wasi:clocks/monotonic-clock@0.3.0-rc-2026-01-06;
import wasi:clocks/system-clock@0.3.0-rc-2026-01-06;
@unstable(feature = clocks-timezone)
import wasi:clocks/timezone@0.3.0-rc-2026-01-06;
import wasi:random/random@0.3.0-rc-2026-01-06;
import wasi:random/insecure@0.3.0-rc-2026-01-06;
import wasi:random/insecure-seed@0.3.0-rc-2026-01-06;
export handler;
}

92
vendor/wasip3/wit/deps/random.wit vendored Normal file
View File

@@ -0,0 +1,92 @@
package wasi:random@0.3.0-rc-2026-01-06;
/// The insecure-seed interface for seeding hash-map DoS resistance.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-insecure-seed: func() -> tuple<u64, u64>;
}
/// The insecure interface for insecure pseudo-random numbers.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-insecure-random-bytes: func(len: u64) -> list<u8>;
/// 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`.
@since(version = 0.3.0-rc-2026-01-06)
get-insecure-random-u64: func() -> u64;
}
/// WASI Random is a random data API.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-random-bytes: func(len: u64) -> list<u8>;
/// 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`.
@since(version = 0.3.0-rc-2026-01-06)
get-random-u64: func() -> u64;
}
@since(version = 0.3.0-rc-2026-01-06)
world imports {
@since(version = 0.3.0-rc-2026-01-06)
import random;
@since(version = 0.3.0-rc-2026-01-06)
import insecure;
@since(version = 0.3.0-rc-2026-01-06)
import insecure-seed;
}

752
vendor/wasip3/wit/deps/sockets.wit vendored Normal file
View File

@@ -0,0 +1,752 @@
package wasi:sockets@0.3.0-rc-2026-01-06;
@since(version = 0.3.0-rc-2026-01-06)
interface types {
@since(version = 0.3.0-rc-2026-01-06)
use wasi:clocks/types@0.3.0-rc-2026-01-06.{duration};
/// 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`
///
/// See each individual API for what the POSIX equivalents are. They sometimes differ per API.
@since(version = 0.3.0-rc-2026-01-06)
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,
/// The operation is not valid in the socket's current state.
invalid-state,
/// 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,
}
@since(version = 0.3.0-rc-2026-01-06)
enum ip-address-family {
/// Similar to `AF_INET` in POSIX.
ipv4,
/// Similar to `AF_INET6` in POSIX.
ipv6,
}
@since(version = 0.3.0-rc-2026-01-06)
type ipv4-address = tuple<u8, u8, u8, u8>;
@since(version = 0.3.0-rc-2026-01-06)
type ipv6-address = tuple<u16, u16, u16, u16, u16, u16, u16, u16>;
@since(version = 0.3.0-rc-2026-01-06)
variant ip-address {
ipv4(ipv4-address),
ipv6(ipv6-address),
}
@since(version = 0.3.0-rc-2026-01-06)
record ipv4-socket-address {
/// sin_port
port: u16,
/// sin_addr
address: ipv4-address,
}
@since(version = 0.3.0-rc-2026-01-06)
record ipv6-socket-address {
/// sin6_port
port: u16,
/// sin6_flowinfo
flow-info: u32,
/// sin6_addr
address: ipv6-address,
/// sin6_scope_id
scope-id: u32,
}
@since(version = 0.3.0-rc-2026-01-06)
variant ip-socket-address {
ipv4(ipv4-socket-address),
ipv6(ipv6-socket-address),
}
/// A TCP socket resource.
///
/// The socket can be in one of the following states:
/// - `unbound`
/// - `bound` (See note below)
/// - `listening`
/// - `connecting`
/// - `connected`
/// - `closed`
/// See <https://github.com/WebAssembly/wasi-sockets/blob/main/TcpSocketOperationalSemantics-0.3.0-draft.md>
/// for 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`, `listening`, `connecting` or `connected`)
///
/// In addition to the general error codes documented on the
/// `types::error-code` type, TCP socket methods may always return
/// `error(invalid-state)` when in the `closed` state.
@since(version = 0.3.0-rc-2026-01-06)
resource 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.
///
/// Unlike POSIX, WASI sockets have no notion of a socket-level
/// `O_NONBLOCK` flag. Instead they fully rely on the Component Model's
/// async support.
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
/// - <https://man7.org/linux/man-pages/man2/socket.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw>
/// - <https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
create: static func(address-family: ip-address-family) -> result<tcp-socket, error-code>;
/// Bind the socket to 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 can be bound to. (EADDRNOTAVAIL)
///
/// # 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.
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
/// - <https://man7.org/linux/man-pages/man2/bind.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind>
/// - <https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2&format=html>
@since(version = 0.3.0-rc-2026-01-06)
bind: func(local-address: ip-socket-address) -> result<_, error-code>;
/// Connect to a remote endpoint.
///
/// On success, the socket is transitioned into the `connected` state and this function returns a connection resource.
///
/// 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-state`: The socket is already in the `connecting` state. (EALREADY)
/// - `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)
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect>
/// - <https://man.freebsd.org/cgi/man.cgi?connect>
@since(version = 0.3.0-rc-2026-01-06)
connect: async func(remote-address: ip-socket-address) -> result<_, error-code>;
/// Start listening and return a stream of new inbound connections.
///
/// Transitions the socket into the `listening` state. This can be called
/// at most once per socket.
///
/// If the socket is not already explicitly bound, this function will
/// implicitly bind the socket to a random free port.
///
/// Normally, the returned sockets are bound, in the `connected` state
/// and immediately ready for I/O. Though, depending on exact timing and
/// circumstances, a newly accepted connection may already be `closed`
/// by the time the server attempts to perform its first I/O on it. This
/// is true regardless of whether the WASI implementation uses
/// "synthesized" sockets or not (see Implementors Notes below).
///
/// 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`
///
/// # Typical errors
/// - `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)
///
/// # Implementors note
/// This method returns a single perpetual stream that should only close
/// on fatal errors (if any). Yet, the POSIX' `accept` function may also
/// return transient errors (e.g. ECONNABORTED). The exact details differ
/// per operation system. For example, the Linux manual mentions:
///
/// > Linux accept() passes already-pending network errors on the new
/// > socket as an error code from accept(). This behavior differs from
/// > other BSD socket implementations. For reliable operation the
/// > application should detect the network errors defined for the
/// > protocol after accept() and treat them like EAGAIN by retrying.
/// > In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT,
/// > EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH.
/// Source: https://man7.org/linux/man-pages/man2/accept.2.html
///
/// WASI implementations have two options to handle this:
/// - Optionally log it and then skip over non-fatal errors returned by
/// `accept`. Guest code never gets to see these failures. Or:
/// - Synthesize a `tcp-socket` resource that exposes the error when
/// attempting to send or receive on it. Guest code then sees these
/// failures as regular I/O errors.
///
/// In either case, the stream returned by this `listen` method remains
/// operational.
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html>
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html>
/// - <https://man7.org/linux/man-pages/man2/listen.2.html>
/// - <https://man7.org/linux/man-pages/man2/accept.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept>
/// - <https://man.freebsd.org/cgi/man.cgi?query=listen&sektion=2>
/// - <https://man.freebsd.org/cgi/man.cgi?query=accept&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
listen: func() -> result<stream<tcp-socket>, error-code>;
/// Transmit data to peer.
///
/// The caller should close the stream when it has no more data to send
/// to the peer. Under normal circumstances this will cause a FIN packet
/// to be sent out. Closing the stream is equivalent to calling
/// `shutdown(SHUT_WR)` in POSIX.
///
/// This function may be called at most once and returns once the full
/// contents of the stream are transmitted or an error is encountered.
///
/// # Typical errors
/// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN)
/// - `connection-reset`: The connection was reset. (ECONNRESET)
/// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html>
/// - <https://man7.org/linux/man-pages/man2/send.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send>
/// - <https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
send: async func(data: stream<u8>) -> result<_, error-code>;
/// Read data from peer.
///
/// This function returns a `stream` which provides the data received from the
/// socket, and a `future` providing additional error information in case the
/// socket is closed abnormally.
///
/// If the socket is closed normally, `stream.read` on the `stream` will return
/// `read-status::closed` with no `error-context` and the future resolves to
/// the value `ok`. If the socket is closed abnormally, `stream.read` on the
/// `stream` returns `read-status::closed` with an `error-context` and the future
/// resolves to `err` with an `error-code`.
///
/// `receive` is meant to be called only once per socket. If it is called more
/// than once, the subsequent calls return a new `stream` that fails as if it
/// were closed abnormally.
///
/// If the caller is not expecting to receive any data from the peer,
/// they may drop the stream. Any data still in the receive queue
/// will be discarded. This is equivalent to calling `shutdown(SHUT_RD)`
/// in POSIX.
///
/// # Typical errors
/// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN)
/// - `connection-reset`: The connection was reset. (ECONNRESET)
/// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html>
/// - <https://man7.org/linux/man-pages/man2/recv.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recv>
/// - <https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
receive: func() -> tuple<stream<u8>, future<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 `get-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
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>
/// - <https://man7.org/linux/man-pages/man2/getsockname.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockname>
/// - <https://man.freebsd.org/cgi/man.cgi?getsockname>
@since(version = 0.3.0-rc-2026-01-06)
get-local-address: func() -> result<ip-socket-address, error-code>;
/// Get the remote address.
///
/// # Typical errors
/// - `invalid-state`: The socket is not connected to a remote address. (ENOTCONN)
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html>
/// - <https://man7.org/linux/man-pages/man2/getpeername.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getpeername>
/// - <https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2&n=1>
@since(version = 0.3.0-rc-2026-01-06)
get-remote-address: func() -> result<ip-socket-address, error-code>;
/// Whether the socket is in the `listening` state.
///
/// Equivalent to the SO_ACCEPTCONN socket option.
@since(version = 0.3.0-rc-2026-01-06)
get-is-listening: func() -> bool;
/// Whether this is a IPv4 or IPv6 socket.
///
/// This is the value passed to the constructor.
///
/// Equivalent to the SO_DOMAIN socket option.
@since(version = 0.3.0-rc-2026-01-06)
get-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 `connecting` or `connected` state.
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-keep-alive-enabled: func() -> result<bool, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-keep-alive-idle-time: func() -> result<duration, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-keep-alive-interval: func() -> result<duration, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-keep-alive-count: func() -> result<u32, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-hop-limit: func() -> result<u8, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-receive-buffer-size: func() -> result<u64, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
get-send-buffer-size: func() -> result<u64, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
set-send-buffer-size: func(value: u64) -> result<_, error-code>;
}
/// A UDP socket handle.
@since(version = 0.3.0-rc-2026-01-06)
resource 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.
///
/// Unlike POSIX, WASI sockets have no notion of a socket-level
/// `O_NONBLOCK` flag. Instead they fully rely on the Component Model's
/// async support.
///
/// # References:
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
/// - <https://man7.org/linux/man-pages/man2/socket.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw>
/// - <https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
create: static func(address-family: ip-address-family) -> result<udp-socket, error-code>;
/// Bind the socket to 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 can be bound to. (EADDRNOTAVAIL)
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
/// - <https://man7.org/linux/man-pages/man2/bind.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind>
/// - <https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2&format=html>
@since(version = 0.3.0-rc-2026-01-06)
bind: func(local-address: ip-socket-address) -> result<_, error-code>;
/// Associate this socket with a specific peer address.
///
/// 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`. If the socket was not already explicitly
/// bound, this function will implicitly bind the socket to a random
/// free port.
///
/// When a UDP socket is "connected", the `send` and `receive` methods
/// are limited to communicating with that peer only:
/// - `send` can only be used to send to this destination.
/// - `receive` will only return datagrams sent from the provided `remote-address`.
///
/// The name "connect" was kept to align with the existing POSIX
/// terminology. Other than that, this function only changes the local
/// socket configuration and does not generate any network traffic.
/// The peer is not aware of this "connection".
///
/// This method may be called multiple times on the same socket to change
/// its association, but only the most recent one will be effective.
///
/// # 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)
/// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD)
///
/// # Implementors note
/// If the socket is already connected, some platforms (e.g. Linux)
/// require a disconnect before connecting to a different peer address.
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect>
/// - <https://man.freebsd.org/cgi/man.cgi?connect>
@since(version = 0.3.0-rc-2026-01-06)
connect: func(remote-address: ip-socket-address) -> result<_, error-code>;
/// Dissociate this socket from its peer address.
///
/// After calling this method, `send` & `receive` are free to communicate
/// with any address again.
///
/// The POSIX equivalent of this is calling `connect` with an `AF_UNSPEC` address.
///
/// # Typical errors
/// - `invalid-state`: The socket is not connected.
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect>
/// - <https://man.freebsd.org/cgi/man.cgi?connect>
@since(version = 0.3.0-rc-2026-01-06)
disconnect: func() -> result<_, error-code>;
/// Send a message on the socket to a particular peer.
///
/// If the socket is connected, the peer address may be left empty. In
/// that case this is equivalent to `send` in POSIX. Otherwise it is
/// equivalent to `sendto`.
///
/// Additionally, if the socket is connected, a `remote-address` argument
/// _may_ be provided but then it must be identical to the address
/// passed to `connect`.
///
/// Implementations may trap if the `data` length exceeds 64 KiB.
///
/// # 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 `connect`. (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
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html>
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html>
/// - <https://man7.org/linux/man-pages/man2/send.2.html>
/// - <https://man7.org/linux/man-pages/man2/sendmmsg.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasendmsg>
/// - <https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
send: async func(data: list<u8>, remote-address: option<ip-socket-address>) -> result<_, error-code>;
/// Receive a message on the socket.
///
/// On success, the return value contains a tuple of the received data
/// and the address of the sender. Theoretical maximum length of the
/// data is 64 KiB. Though in practice, it will typically be less than
/// 1500 bytes.
///
/// If the socket is connected, the sender address is guaranteed to
/// match the remote address passed to `connect`.
///
/// # Typical errors
/// - `invalid-state`: The socket has not been bound yet.
/// - `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
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html>
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html>
/// - <https://man7.org/linux/man-pages/man2/recv.2.html>
/// - <https://man7.org/linux/man-pages/man2/recvmmsg.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_wsarecvmsg>
/// - <https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2>
@since(version = 0.3.0-rc-2026-01-06)
receive: async func() -> result<tuple<list<u8>, ip-socket-address>, 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 `get-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
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>
/// - <https://man7.org/linux/man-pages/man2/getsockname.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockname>
/// - <https://man.freebsd.org/cgi/man.cgi?getsockname>
@since(version = 0.3.0-rc-2026-01-06)
get-local-address: func() -> result<ip-socket-address, error-code>;
/// Get the address the socket is currently "connected" to.
///
/// # Typical errors
/// - `invalid-state`: The socket is not "connected" to a specific remote address. (ENOTCONN)
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html>
/// - <https://man7.org/linux/man-pages/man2/getpeername.2.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getpeername>
/// - <https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2&n=1>
@since(version = 0.3.0-rc-2026-01-06)
get-remote-address: func() -> result<ip-socket-address, error-code>;
/// Whether this is a IPv4 or IPv6 socket.
///
/// This is the value passed to the constructor.
///
/// Equivalent to the SO_DOMAIN socket option.
@since(version = 0.3.0-rc-2026-01-06)
get-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.
@since(version = 0.3.0-rc-2026-01-06)
get-unicast-hop-limit: func() -> result<u8, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
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.
@since(version = 0.3.0-rc-2026-01-06)
get-receive-buffer-size: func() -> result<u64, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
get-send-buffer-size: func() -> result<u64, error-code>;
@since(version = 0.3.0-rc-2026-01-06)
set-send-buffer-size: func(value: u64) -> result<_, error-code>;
}
}
@since(version = 0.3.0-rc-2026-01-06)
interface ip-name-lookup {
@since(version = 0.3.0-rc-2026-01-06)
use types.{ip-address};
/// Lookup error codes.
@since(version = 0.3.0-rc-2026-01-06)
enum error-code {
/// Unknown error
unknown,
/// Access denied.
///
/// POSIX equivalent: EACCES, EPERM
access-denied,
/// `name` is a syntactically invalid domain name or IP address.
///
/// POSIX equivalent: EINVAL
invalid-argument,
/// Name does not exist or has no suitable associated IP addresses.
///
/// POSIX equivalent: EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY
name-unresolvable,
/// A temporary failure in name resolution occurred.
///
/// POSIX equivalent: EAI_AGAIN
temporary-resolver-failure,
/// A permanent failure in name resolution occurred.
///
/// POSIX equivalent: EAI_FAIL
permanent-resolver-failure,
}
/// 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.
///
/// The results are returned in connection order preference.
///
/// This function never succeeds with 0 results. It either fails or succeeds
/// with at least one address. Additionally, this function never returns
/// IPv4-mapped IPv6 addresses.
///
/// The returned future will resolve to an error code in case of failure.
/// It will resolve to success once the returned stream is exhausted.
///
/// # References:
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>
/// - <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>
/// - <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>
/// - <https://man.freebsd.org/cgi/man.cgi?query=getaddrinfo&sektion=3>
@since(version = 0.3.0-rc-2026-01-06)
resolve-addresses: async func(name: string) -> result<list<ip-address>, error-code>;
}
@since(version = 0.3.0-rc-2026-01-06)
world imports {
@since(version = 0.3.0-rc-2026-01-06)
import wasi:clocks/types@0.3.0-rc-2026-01-06;
@since(version = 0.3.0-rc-2026-01-06)
import types;
@since(version = 0.3.0-rc-2026-01-06)
import ip-name-lookup;
}

1
vendor/wasip3/wit/wasi-crate.wit vendored Normal file
View File

@@ -0,0 +1 @@
package rust:wasi;