├── .github ├── CODEOWNERS ├── actions │ ├── build-nix │ │ └── action.yml │ └── install-nix │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── nix.yml │ ├── scorecard.yml │ ├── update.yml │ └── wrpc.yml ├── .gitignore ├── .gitmodules ├── ADOPTERS.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── SPEC.md ├── benches ├── bench.rs ├── reactor │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── wit │ └── bench.wit ├── crates ├── cli │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── nats.rs │ │ └── tracing.rs ├── introspect │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pack │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── runtime-wasmtime │ ├── Cargo.toml │ ├── src │ │ ├── bindings.rs │ │ ├── codec.rs │ │ ├── lib.rs │ │ ├── polyfill.rs │ │ ├── rpc │ │ │ ├── host │ │ │ │ ├── context.rs │ │ │ │ ├── error.rs │ │ │ │ ├── invoker.rs │ │ │ │ ├── mod.rs │ │ │ │ └── transport.rs │ │ │ └── mod.rs │ │ └── serve.rs │ └── wit │ │ ├── deps.lock │ │ ├── deps.toml │ │ ├── deps │ │ ├── io │ │ │ ├── error.wit │ │ │ ├── poll.wit │ │ │ ├── streams.wit │ │ │ └── world.wit │ │ └── rpc │ │ │ └── rpc.wit │ │ └── world.wit ├── test-helpers │ ├── Cargo.toml │ ├── codegen-macro │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── src │ │ └── lib.rs ├── test │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── transport-nats │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── transport-quic │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── tests │ │ └── loopback.rs ├── transport-web │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── tests │ │ └── loopback.rs ├── transport │ ├── Cargo.toml │ └── src │ │ ├── frame │ │ ├── codec.rs │ │ ├── conn │ │ │ ├── accept.rs │ │ │ ├── client.rs │ │ │ ├── mod.rs │ │ │ └── server.rs │ │ ├── mod.rs │ │ ├── tcp │ │ │ ├── mod.rs │ │ │ ├── tokio.rs │ │ │ └── wasi.rs │ │ └── unix.rs │ │ ├── invoke.rs │ │ ├── lib.rs │ │ ├── serve.rs │ │ └── value.rs ├── wasi-keyvalue-mem │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── wasi-keyvalue-redis │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── wasi-keyvalue │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── wit │ │ ├── deps.lock │ │ ├── deps.toml │ │ ├── deps │ │ └── keyvalue │ │ │ ├── atomic.wit │ │ │ ├── batch.wit │ │ │ ├── store.wit │ │ │ ├── watch.wit │ │ │ └── world.wit │ │ └── world.wit ├── wasmtime-cli │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── nats.rs │ │ └── tcp.rs ├── wit-bindgen-go │ ├── Cargo.toml │ ├── src │ │ ├── interface.rs │ │ └── lib.rs │ └── tests │ │ └── codegen.rs ├── wit-bindgen-rust-macro │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── lib.rs ├── wit-bindgen-rust │ ├── Cargo.toml │ ├── build.rs │ ├── src │ │ ├── interface.rs │ │ └── lib.rs │ └── tests │ │ ├── codegen.rs │ │ └── wit │ │ ├── path1 │ │ └── world.wit │ │ └── path2 │ │ └── world.wit └── wit-bindgen │ ├── Cargo.toml │ ├── README.md │ ├── src │ ├── examples.rs │ ├── examples │ │ ├── _0_world_imports.rs │ │ ├── _1_interface_imports.rs │ │ ├── _2_imported_resources.rs │ │ ├── _3_world_exports.rs │ │ └── _4_exported_resources.rs │ └── lib.rs │ └── wasi-cli@0.2.0.wasm ├── examples ├── go │ ├── hello-client │ │ ├── app.go │ │ ├── bindings │ │ │ ├── client.wrpc.go │ │ │ └── wrpc_examples │ │ │ │ └── hello │ │ │ │ └── handler │ │ │ │ └── bindings.wrpc.go │ │ ├── cmd │ │ │ ├── hello-client-nats │ │ │ │ └── main.go │ │ │ └── hello-client-tcp │ │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-server │ │ ├── app.go │ │ ├── bindings │ │ │ ├── exports │ │ │ │ └── wrpc_examples │ │ │ │ │ └── hello │ │ │ │ │ └── handler │ │ │ │ │ └── bindings.wrpc.go │ │ │ └── server.wrpc.go │ │ ├── cmd │ │ │ ├── hello-server-nats │ │ │ │ └── main.go │ │ │ └── hello-server-tcp │ │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── resources-server │ │ ├── app.go │ │ ├── bindings │ │ │ ├── exports │ │ │ │ └── wrpc_examples │ │ │ │ │ └── resources │ │ │ │ │ └── resources │ │ │ │ │ └── bindings.wrpc.go │ │ │ └── server.wrpc.go │ │ ├── cmd │ │ │ └── resources-server-nats │ │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── resources │ │ │ │ └── resources.wit │ │ │ └── world.wit │ ├── streams-client │ │ ├── app.go │ │ ├── bindings │ │ │ ├── client.wrpc.go │ │ │ └── wrpc_examples │ │ │ │ └── streams │ │ │ │ └── handler │ │ │ │ └── bindings.wrpc.go │ │ ├── cmd │ │ │ ├── streams-client-nats │ │ │ │ └── main.go │ │ │ └── streams-client-tcp │ │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── streams │ │ │ │ └── streams.wit │ │ │ └── world.wit │ ├── streams-server │ │ ├── app.go │ │ ├── bindings │ │ │ ├── exports │ │ │ │ └── wrpc_examples │ │ │ │ │ └── streams │ │ │ │ │ └── handler │ │ │ │ │ └── bindings.wrpc.go │ │ │ └── server.wrpc.go │ │ ├── cmd │ │ │ ├── streams-server-nats │ │ │ │ └── main.go │ │ │ └── streams-server-tcp │ │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── streams │ │ │ │ └── streams.wit │ │ │ └── world.wit │ ├── wasi-keyvalue-client │ │ ├── app.go │ │ ├── bindings │ │ │ ├── client.wrpc.go │ │ │ └── wasi │ │ │ │ └── keyvalue │ │ │ │ └── store │ │ │ │ └── bindings.wrpc.go │ │ ├── cmd │ │ │ ├── wasi-keyvalue-nats-client │ │ │ │ └── main.go │ │ │ └── wasi-keyvalue-tcp-client │ │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── keyvalue │ │ │ │ ├── atomic.wit │ │ │ │ ├── batch.wit │ │ │ │ ├── store.wit │ │ │ │ ├── watch.wit │ │ │ │ └── world.wit │ │ │ └── world.wit │ └── wasi-keyvalue-server │ │ ├── app.go │ │ ├── bindings │ │ ├── exports │ │ │ └── wasi │ │ │ │ └── keyvalue │ │ │ │ └── store │ │ │ │ └── bindings.wrpc.go │ │ └── server.wrpc.go │ │ ├── cmd │ │ ├── wasi-keyvalue-nats-server │ │ │ └── main.go │ │ └── wasi-keyvalue-tcp-server │ │ │ └── main.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── wit │ │ ├── deps.lock │ │ ├── deps.toml │ │ ├── deps │ │ └── keyvalue │ │ │ ├── atomic.wit │ │ │ ├── batch.wit │ │ │ ├── store.wit │ │ │ ├── watch.wit │ │ │ └── world.wit │ │ └── world.wit ├── rust │ ├── hello-component-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-component-rpc-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ ├── hello │ │ │ │ └── hello.wit │ │ │ ├── io │ │ │ │ ├── error.wit │ │ │ │ ├── poll.wit │ │ │ │ ├── streams.wit │ │ │ │ └── world.wit │ │ │ └── rpc │ │ │ │ └── rpc.wit │ │ │ └── world.wit │ ├── hello-component-rpc-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ ├── hello │ │ │ │ └── hello.wit │ │ │ ├── io │ │ │ │ ├── error.wit │ │ │ │ ├── poll.wit │ │ │ │ ├── streams.wit │ │ │ │ └── world.wit │ │ │ └── rpc │ │ │ │ └── rpc.wit │ │ │ └── world.wit │ ├── hello-component-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-component-tcp-proxy │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-http-tcp-proxy │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-nats-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-nats-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-tcp-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-tcp-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-web-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── hello-web-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── hello │ │ │ │ └── hello.wit │ │ │ └── world.wit │ ├── resources-component-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── resources │ │ │ │ └── resources.wit │ │ │ └── world.wit │ ├── resources-component-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── resources │ │ │ │ └── resources.wit │ │ │ └── world.wit │ ├── streams-nats-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── streams │ │ │ │ └── streams.wit │ │ │ └── world.wit │ ├── streams-nats-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── streams │ │ │ │ └── streams.wit │ │ │ └── world.wit │ ├── wasi-keyvalue-component-client │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── main.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── keyvalue │ │ │ │ ├── atomic.wit │ │ │ │ ├── batch.wit │ │ │ │ ├── store.wit │ │ │ │ ├── watch.wit │ │ │ │ └── world.wit │ │ │ └── world.wit │ ├── wasi-keyvalue-component-server │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── wit │ │ │ ├── deps.lock │ │ │ ├── deps.toml │ │ │ ├── deps │ │ │ └── keyvalue │ │ │ │ ├── atomic.wit │ │ │ │ ├── batch.wit │ │ │ │ ├── store.wit │ │ │ │ ├── watch.wit │ │ │ │ └── world.wit │ │ │ └── world.wit │ ├── wasi-keyvalue-nats-client │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── wasi-keyvalue-nats-server │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── wasi-keyvalue-quic-server │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── wasi-keyvalue-tcp-client │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── wasi-keyvalue-tcp-server │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── wasi-keyvalue-unix-server │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── wasi-keyvalue-web-server │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── web │ ├── README.md │ ├── rust │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── ui │ │ └── index.html └── wit │ ├── hello-rpc │ ├── deps │ │ ├── io │ │ └── rpc │ └── hello.wit │ ├── hello │ └── hello.wit │ ├── resources │ └── resources.wit │ └── streams │ └── streams.wit ├── flake.lock ├── flake.nix ├── go.work ├── go.work.sum ├── go ├── frame.go ├── frame_invoker.go ├── frame_reader.go ├── frame_server.go ├── frame_writer.go ├── frame_writer_test.go ├── future.go ├── go.mod ├── go.sum ├── list.go ├── nats │ └── client.go ├── option.go ├── primitive.go ├── result.go ├── stream.go ├── tuple.go ├── wrpc.go └── x │ └── tcp │ ├── conn.go │ ├── invoker.go │ └── server.go ├── rust-toolchain.toml ├── src ├── bin │ ├── wit-bindgen-wrpc.rs │ └── wrpc-wasmtime.rs └── lib.rs └── tests ├── codegen ├── allow-unused.wit ├── async-client.wit ├── async-server.wit ├── char.wit ├── conventions.wit ├── empty.wit ├── enum-has-go-keyword.wit ├── flags.wit ├── floats.wit ├── fully-qualified-java-address.wit ├── go_params.wit ├── guest-name.wit ├── import-and-export-resource-alias.wit ├── import-and-export-resource.wit ├── import-func.wit ├── integers.wit ├── interface-has-go-keyword.wit ├── issue544.wit ├── issue551.wit ├── issue569 │ └── wit │ │ ├── deps │ │ ├── io │ │ │ └── streams.wit │ │ └── poll │ │ │ └── poll.wit │ │ └── issue569.wit ├── issue573.wit ├── issue607.wit ├── issue668.wit ├── issue929-no-export.wit ├── issue929-no-import.wit ├── issue929-only-methods.wit ├── issue929.wit ├── just-export.wit ├── keywords-in-interfaces-and-worlds.wit ├── keywords.wit ├── lift-lower-foreign.wit ├── lists.wit ├── many-arguments.wit ├── multi-return.wit ├── multiversion │ └── wit │ │ ├── deps │ │ ├── v1 │ │ │ └── root.wit │ │ └── v2 │ │ │ └── root.wit │ │ └── root.wit ├── option-result.wit ├── record-has-go-keyword-and-used-in-fn.wit ├── records.wit ├── rename-interface.wit ├── resource-alias.wit ├── resource-borrow-in-record-export.wit ├── resource-borrow-in-record.wit ├── resource-local-alias-borrow-import.wit ├── resource-local-alias-borrow.wit ├── resource-local-alias.wit ├── resource-own-in-other-interface.wit ├── resources-in-aggregates.wit ├── resources-with-lists.wit ├── resources.wit ├── result-empty.wit ├── ret-areas.wit ├── return-resource-from-export.wit ├── same-names1.wit ├── same-names2.wit ├── same-names3.wit ├── same-names4.wit ├── same-names5.wit ├── simple-enum.wit ├── simple-functions.wit ├── simple-http.wit ├── simple-lists.wit ├── simple-option.wit ├── small-anonymous.wit ├── smoke-default.wit ├── smoke-export.wit ├── smoke.wit ├── strings.wit ├── unused-import.wit ├── use-across-interfaces.wit ├── variants-unioning-types.wit ├── variants.wit ├── world-has-go-keyword.wit ├── worlds-with-types.wit └── zero-size-tuple.wit ├── common └── mod.rs ├── go.rs ├── go ├── .gitignore ├── async.go ├── async_test.go ├── cmd │ ├── async-server-nats │ │ └── main.go │ └── sync-server-nats │ │ └── main.go ├── go.mod ├── go.sum ├── internal │ └── internal.go ├── resources.go ├── resources_test.go ├── sync.go ├── sync_test.go └── types_test.go ├── rust.rs └── wit └── test.wit /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @rvolosatovs 2 | -------------------------------------------------------------------------------- /.github/actions/build-nix/action.yml: -------------------------------------------------------------------------------- 1 | name: build via Nix 2 | 3 | inputs: 4 | package: 5 | description: package specification to build 6 | required: true 7 | 8 | runs: 9 | using: composite 10 | steps: 11 | - run: nix build -L '.#${{ inputs.package }}' 12 | shell: bash 13 | - run: nix run -L --inputs-from . 'nixpkgs-unstable#coreutils' -- --coreutils-prog=cp -RLv ./result '${{ inputs.package }}' 14 | shell: bash 15 | - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 16 | with: 17 | name: ${{ inputs.package }} 18 | path: ${{ inputs.package }} 19 | -------------------------------------------------------------------------------- /.github/actions/install-nix/action.yml: -------------------------------------------------------------------------------- 1 | name: install Nix 2 | 3 | permissions: 4 | id-token: write 5 | contents: read 6 | 7 | inputs: 8 | cachixAuthToken: 9 | description: auth token for https://app.cachix.org/organization/wasmcloud/cache/bytecodealliance 10 | 11 | runs: 12 | using: composite 13 | steps: 14 | - uses: DeterminateSystems/determinate-nix-action@v3.6.1 15 | with: 16 | extra-conf: | 17 | accept-flake-config = true 18 | 19 | - uses: cachix/cachix-action@v16 20 | continue-on-error: true 21 | with: 22 | name: bytecodealliance 23 | authToken: '${{ inputs.cachixAuthToken }}' 24 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "gomod" 9 | directory: "/go" 10 | schedule: 11 | interval: "daily" 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "daily" 17 | - package-ecosystem: "github-actions" 18 | directory: "/.github/actions/build-nix" 19 | schedule: 20 | interval: "daily" 21 | - package-ecosystem: "github-actions" 22 | directory: "/.github/actions/install-nix" 23 | schedule: 24 | interval: "daily" 25 | 26 | - package-ecosystem: gomod 27 | directory: /examples/go/resources-server 28 | schedule: 29 | interval: daily 30 | 31 | - package-ecosystem: gomod 32 | directory: /examples/go/hello-client 33 | schedule: 34 | interval: daily 35 | 36 | - package-ecosystem: gomod 37 | directory: /examples/go/hello-server 38 | schedule: 39 | interval: daily 40 | 41 | - package-ecosystem: gomod 42 | directory: /tests/go 43 | schedule: 44 | interval: daily 45 | -------------------------------------------------------------------------------- /.github/workflows/nix.yml: -------------------------------------------------------------------------------- 1 | name: nix 2 | 3 | on: 4 | merge_group: 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | fmt: 16 | runs-on: ubuntu-24.04 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 19 | - uses: ./.github/actions/install-nix 20 | with: 21 | cachixAuthToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 22 | - run: nix fmt -L $(find . -type f -name '*.nix') 23 | 24 | shell: 25 | runs-on: ubuntu-24.04 26 | steps: 27 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | - uses: ./.github/actions/install-nix 29 | with: 30 | cachixAuthToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 31 | - run: | 32 | nix profile install 33 | wit-bindgen-wrpc --version 34 | wrpc-wasmtime --version 35 | 36 | develop: 37 | runs-on: ubuntu-24.04 38 | steps: 39 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 40 | - uses: ./.github/actions/install-nix 41 | with: 42 | cachixAuthToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 43 | - run: nix develop -L --ignore-environment -c cargo tree 44 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: nix-flake-update 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | nix-flake-update: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: rvolosatovs/nix-flake-update-action@7249aa67d87e2a195c376fe34c230af0862a9900 # v2.0.5 13 | with: 14 | app-id: ${{ secrets.BOT_APP_ID }} 15 | private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} 16 | assignees: rvolosatovs 17 | reviewers: rvolosatovs 18 | delete-branch: true 19 | signoff: true 20 | labels: dependencies 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | dump.rdb 3 | .DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tests/codegen/wasi-filesystem"] 2 | path = tests/codegen/wasi-filesystem 3 | url = https://github.com/WebAssembly/wasi-filesystem 4 | [submodule "tests/codegen/wasi-http"] 5 | path = tests/codegen/wasi-http 6 | url = https://github.com/WebAssembly/wasi-http 7 | [submodule "tests/codegen/wasi-cli"] 8 | path = tests/codegen/wasi-cli 9 | url = https://github.com/WebAssembly/wasi-cli 10 | [submodule "tests/codegen/wasi-io"] 11 | path = tests/codegen/wasi-io 12 | url = https://github.com/WebAssembly/wasi-io 13 | [submodule "tests/codegen/wasi-clocks"] 14 | path = tests/codegen/wasi-clocks 15 | url = https://github.com/WebAssembly/wasi-clocks 16 | -------------------------------------------------------------------------------- /ADOPTERS.md: -------------------------------------------------------------------------------- 1 | # wRPC adopters 2 | 3 | _If you are using wRPC in production at your organization, please add your company name to this list. 4 | The list is in alphabetical order._ 5 | 6 | | Organization | Contact | Status | Description of Use | 7 | | - | - | - | - | 8 | | [Cosmonic](https://www.cosmonic.com) | [@rvolosatovs](https://github.com/rvolosatovs) | ![production](https://img.shields.io/badge/-production-blue?style=flat) | Cosmonic is a distributed app platform built on CNCF wasmCloud for wasmCloud apps. | 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | wRPC is currently pre-1.0.0 and security vulnerabilities, although unlikely, are possible. 6 | Post-1.0.0 release the last 2 major versions will be supported with security patches. 7 | 8 | ## Reporting a Vulnerability 9 | 10 | For reporting a security vulnerability please either use GitHub Security Advisory reporting or email [rvolosatovs@riseup.net](mailto:rvolosatovs@riseup.net) 11 | -------------------------------------------------------------------------------- /benches/reactor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reactor" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | categories.workspace = true 6 | edition.workspace = true 7 | homepage.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [lib] 12 | crate-type = ["rlib", "cdylib"] 13 | 14 | [dependencies] 15 | wit-bindgen = { workspace = true, features = ["macros", "realloc"] } 16 | -------------------------------------------------------------------------------- /benches/reactor/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod bindings { 2 | use crate::Handler; 3 | 4 | wit_bindgen::generate!({ 5 | path: "../wit", 6 | world: "handler", 7 | with: { 8 | "wrpc-bench:bench/ping": generate, 9 | "wrpc-bench:bench/greet": generate, 10 | }, 11 | }); 12 | export!(Handler); 13 | } 14 | 15 | pub struct Handler; 16 | 17 | impl bindings::exports::wrpc_bench::bench::ping::Guest for Handler { 18 | fn ping() {} 19 | } 20 | 21 | impl bindings::exports::wrpc_bench::bench::greet::Guest for Handler { 22 | fn greet(name: String) -> String { 23 | format!("Hello, {name}") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /benches/wit/bench.wit: -------------------------------------------------------------------------------- 1 | package wrpc-bench:bench; 2 | 3 | interface ping { 4 | ping: func(); 5 | } 6 | 7 | interface greet { 8 | greet: func(name: string) -> string; 9 | } 10 | 11 | world ping-proxy { 12 | import ping; 13 | export ping; 14 | } 15 | 16 | world greet-proxy { 17 | import greet; 18 | export greet; 19 | } 20 | 21 | world handler { 22 | export ping; 23 | export greet; 24 | } 25 | -------------------------------------------------------------------------------- /crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-cli" 3 | version = "0.6.0" 4 | description = "wRPC CLI utilities" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [features] 14 | default = ["nats"] 15 | nats = ["async-nats/ring", "dep:async-nats", "dep:tokio", "tokio/sync"] 16 | 17 | [dependencies] 18 | anyhow = { workspace = true, features = ["std"] } 19 | async-nats = { workspace = true, optional = true } 20 | tokio = { workspace = true, optional = true } 21 | tracing-subscriber = { workspace = true, features = [ 22 | "ansi", 23 | "env-filter", 24 | "fmt", 25 | "smallvec", 26 | "tracing-log", 27 | ] } 28 | -------------------------------------------------------------------------------- /crates/cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "nats")] 2 | pub mod nats; 3 | pub mod tracing; 4 | -------------------------------------------------------------------------------- /crates/cli/src/nats.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context as _; 2 | use tokio::sync::mpsc; 3 | 4 | pub const DEFAULT_URL: &str = "nats://127.0.0.1:4222"; 5 | 6 | /// Connect to NATS.io server and ensure that the connection is fully established before 7 | /// returning the resulting [`async_nats::Client`] 8 | pub async fn connect(addrs: impl async_nats::ToServerAddrs) -> anyhow::Result { 9 | let (conn_tx, mut conn_rx) = mpsc::channel(1); 10 | let client = async_nats::connect_with_options( 11 | addrs, 12 | async_nats::ConnectOptions::new() 13 | .retry_on_initial_connect() 14 | .event_callback(move |event| { 15 | let conn_tx = conn_tx.clone(); 16 | async move { 17 | if let async_nats::Event::Connected = event { 18 | conn_tx 19 | .send(()) 20 | .await 21 | .expect("failed to send NATS.io server connection notification"); 22 | } 23 | } 24 | }), 25 | ) 26 | .await 27 | .context("failed to connect to NATS.io server")?; 28 | conn_rx 29 | .recv() 30 | .await 31 | .context("failed to await NATS.io server connection to be established")?; 32 | Ok(client) 33 | } 34 | -------------------------------------------------------------------------------- /crates/cli/src/tracing.rs: -------------------------------------------------------------------------------- 1 | use tracing_subscriber::layer::SubscriberExt as _; 2 | use tracing_subscriber::util::SubscriberInitExt as _; 3 | 4 | #[must_use] 5 | pub fn env_filter() -> tracing_subscriber::EnvFilter { 6 | tracing_subscriber::EnvFilter::try_from_default_env() 7 | .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")) 8 | } 9 | 10 | pub fn init() { 11 | tracing_subscriber::registry() 12 | .with(tracing_subscriber::fmt::layer().compact().without_time()) 13 | .with(env_filter()) 14 | .init(); 15 | } 16 | -------------------------------------------------------------------------------- /crates/introspect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-introspect" 3 | version = "0.7.0" 4 | description = "Component type introspection for wRPC" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | wit-parser = { workspace = true } 15 | -------------------------------------------------------------------------------- /crates/pack/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-pack" 3 | version = "0.3.1" 4 | description = "Temporary stopgap solution for encoding fully-synchronous wRPC values" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | anyhow = { workspace = true } 15 | bytes = { workspace = true } 16 | tokio = { workspace = true } 17 | tokio-util = { workspace = true } 18 | wrpc-transport = { workspace = true } 19 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-runtime-wasmtime" 3 | version = "0.29.0" 4 | description = "wRPC wasmtime integration" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | anyhow = { workspace = true, features = ["std"] } 15 | bytes = { workspace = true } 16 | futures = { workspace = true, features = ["alloc"] } 17 | tokio = { workspace = true, features = ["macros"] } 18 | tokio-util = { workspace = true, features = ["codec", "compat"] } 19 | tracing = { workspace = true, features = ["attributes"] } 20 | uuid = { workspace = true, features = ["std", "v7"] } 21 | wasm-tokio = { workspace = true } 22 | wasmtime = { workspace = true } 23 | wasmtime-wasi = { workspace = true } 24 | wit-parser = { workspace = true } 25 | wrpc-introspect = { workspace = true } 26 | wrpc-transport = { workspace = true } 27 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/src/bindings.rs: -------------------------------------------------------------------------------- 1 | mod generated { 2 | wasmtime::component::bindgen!({ 3 | world: "wrpc:rpc/imports", 4 | with: { 5 | "wasi": wasmtime_wasi::p2::bindings, 6 | "wrpc:rpc/context/context": with::Context, 7 | "wrpc:rpc/error/error": crate::rpc::Error, 8 | "wrpc:rpc/transport/incoming-channel": crate::rpc::IncomingChannel, 9 | "wrpc:rpc/transport/invocation": crate::rpc::Invocation, 10 | "wrpc:rpc/transport/outgoing-channel": crate::rpc::OutgoingChannel, 11 | }, 12 | async: { 13 | only_imports: [ 14 | "wrpc:rpc/transport@0.1.0#[static]invocation.finish", 15 | ], 16 | }, 17 | trappable_imports: true, 18 | require_store_data_send: true, 19 | }); 20 | 21 | pub mod with { 22 | use core::any::Any; 23 | 24 | #[repr(transparent)] 25 | pub struct Context(pub Box); 26 | } 27 | } 28 | 29 | pub use generated::wrpc::rpc; 30 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/src/rpc/host/context.rs: -------------------------------------------------------------------------------- 1 | use wasmtime::component::Resource; 2 | use wrpc_transport::Invoke; 3 | 4 | use crate::bindings::rpc::context::{Context, Host, HostContext}; 5 | use crate::rpc::WrpcRpcImpl; 6 | use crate::{WrpcView, WrpcViewExt as _}; 7 | 8 | impl Host for WrpcRpcImpl where ::Context: 'static {} 9 | 10 | impl HostContext for WrpcRpcImpl 11 | where 12 | ::Context: 'static, 13 | { 14 | fn default(&mut self) -> wasmtime::Result> { 15 | let cx = self.0.context(); 16 | self.0.push_context(cx) 17 | } 18 | 19 | fn drop(&mut self, cx: Resource) -> wasmtime::Result<()> { 20 | self.0.delete_context(cx)?; 21 | Ok(()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/src/rpc/host/error.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context as _; 2 | use wasmtime::component::Resource; 3 | use wasmtime_wasi::p2::bindings::io::error::Error as IoError; 4 | 5 | use crate::bindings::rpc::error::{Error, Host, HostError}; 6 | use crate::rpc::WrpcRpcImpl; 7 | use crate::{WrpcView, WrpcViewExt as _}; 8 | 9 | impl Host for WrpcRpcImpl {} 10 | 11 | impl HostError for WrpcRpcImpl { 12 | fn from_io_error( 13 | &mut self, 14 | error: Resource, 15 | ) -> wasmtime::Result, Resource>> { 16 | let table = self.0.table(); 17 | let error = table 18 | .delete::(error) 19 | .context("failed to delete `wasi:io/error.error` from table")?; 20 | match error.downcast() { 21 | Ok(error) => { 22 | let error = self.0.push_error(Error::Stream(error))?; 23 | Ok(Ok(error)) 24 | } 25 | Err(error) => { 26 | let error = table 27 | .push(error) 28 | .context("failed to push `wasi:io/error.error` to table")?; 29 | Ok(Err(error)) 30 | } 31 | } 32 | } 33 | 34 | fn to_debug_string(&mut self, error: Resource) -> wasmtime::Result { 35 | let error = self.0.get_error(&error)?; 36 | Ok(format!("{error:#}")) 37 | } 38 | 39 | fn drop(&mut self, error: Resource) -> wasmtime::Result<()> { 40 | self.0.delete_error(error)?; 41 | Ok(()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/src/rpc/host/invoker.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context as _; 2 | use tokio::io::AsyncWriteExt as _; 3 | use wasmtime::component::Resource; 4 | use wrpc_transport::Invoke; 5 | 6 | use crate::bindings::rpc::context::Context; 7 | use crate::bindings::rpc::invoker::Host; 8 | use crate::bindings::rpc::transport::Invocation; 9 | use crate::rpc::WrpcRpcImpl; 10 | use crate::{WrpcView, WrpcViewExt as _}; 11 | 12 | impl Host for WrpcRpcImpl 13 | where 14 | T::Invoke: Clone + 'static, 15 | ::Context: 'static, 16 | { 17 | fn invoke( 18 | &mut self, 19 | cx: Resource, 20 | instance: String, 21 | name: String, 22 | params: Vec, 23 | paths: Vec>>, 24 | ) -> wasmtime::Result> { 25 | let client = self.0.client().clone(); 26 | let cx = self.0.delete_context(cx)?; 27 | let paths = paths 28 | .into_iter() 29 | .map(|path| { 30 | path.into_iter() 31 | .map(|i| i.map(usize::try_from).transpose()) 32 | .collect::, _>>() 33 | }) 34 | .collect::, _>>() 35 | .context("failed to construct subscription paths")?; 36 | let invocation = async move { 37 | let (mut tx, rx) = client 38 | .invoke(cx, &instance, &name, params.into(), paths) 39 | .await?; 40 | tx.flush() 41 | .await 42 | .context("failed to flush outgoing stream")?; 43 | Ok((tx, rx)) 44 | }; 45 | self.0.push_invocation(invocation) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/src/rpc/host/mod.rs: -------------------------------------------------------------------------------- 1 | mod context; 2 | mod error; 3 | mod invoker; 4 | mod transport; 5 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [io] 2 | sha256 = "7210e5653539a15478f894d4da24cc69d61924cbcba21d2804d69314a88e5a4c" 3 | sha512 = "49184a1b0945a889abd52d25271172ed3dc2db6968fcdddb1bab7ee0081f4a3eeee0977ad2291126a37631c0d86eeea75d822fa8af224c422134500bf9f0f2bb" 4 | 5 | [rpc] 6 | url = "https://github.com/wrpc/rpc/archive/main.tar.gz" 7 | sha256 = "61f1545986917171d3e3dab7edf4286ca1769e73599ba83e1c3667de5ad955e8" 8 | sha512 = "64a16b8fbda6f9335cfd726eb80f9f77ae4551831c443dfad794cb76e2176135015fb1cbef8f50c5b90fd5fec6b2b6feeb8af74010f35c58ca922ad317e26ff7" 9 | deps = ["io"] 10 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/wit/deps.toml: -------------------------------------------------------------------------------- 1 | rpc = "https://github.com/wrpc/rpc/archive/main.tar.gz" 2 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/wit/deps/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | 4 | interface error { 5 | /// A resource which represents some error information. 6 | /// 7 | /// The only method provided by this resource is `to-debug-string`, 8 | /// which provides some human-readable information about the error. 9 | /// 10 | /// In the `wasi:io` package, this resource is returned through the 11 | /// `wasi:io/streams/stream-error` type. 12 | /// 13 | /// To provide more specific error information, other interfaces may 14 | /// provide functions to further "downcast" this error into more specific 15 | /// error information. For example, `error`s returned in streams derived 16 | /// from filesystem types to be described using the filesystem's own 17 | /// error-code type, using the function 18 | /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter 19 | /// `borrow` and returns 20 | /// `option`. 21 | /// 22 | /// The set of functions which can "downcast" an `error` into a more 23 | /// concrete type is open. 24 | resource error { 25 | /// Returns a string that is suitable to assist humans in debugging 26 | /// this error. 27 | /// 28 | /// WARNING: The returned string should not be consumed mechanically! 29 | /// It may change across platforms, hosts, or other implementation 30 | /// details. Parsing this string is a major platform-compatibility 31 | /// hazard. 32 | to-debug-string: func() -> string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/wit/deps/io/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | world imports { 4 | import streams; 5 | import poll; 6 | } 7 | -------------------------------------------------------------------------------- /crates/runtime-wasmtime/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc:runtime; 2 | -------------------------------------------------------------------------------- /crates/test-helpers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-helpers" 3 | edition.workspace = true 4 | publish = false 5 | 6 | [lib] 7 | doctest = false 8 | test = false 9 | 10 | [dependencies] 11 | codegen-macro = { path = 'codegen-macro' } 12 | wit-bindgen-core = { workspace = true } 13 | wit-parser = { workspace = true } 14 | -------------------------------------------------------------------------------- /crates/test-helpers/codegen-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codegen-macro" 3 | authors = ["Alex Crichton "] 4 | edition.workspace = true 5 | publish = false 6 | 7 | [lib] 8 | proc-macro = true 9 | doctest = false 10 | test = false 11 | 12 | [dependencies] 13 | heck = { workspace = true } 14 | quote = { workspace = true } 15 | -------------------------------------------------------------------------------- /crates/test-helpers/codegen-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | use heck::ToSnakeCase; 2 | use proc_macro::TokenStream; 3 | use std::env; 4 | 5 | /// This macro invokes a local macro called `codegen_test!` with the name 6 | /// of the test and the full path to the test to execute. The local 7 | /// `codegen_test!` macro then does what's necessary to actually run the test. 8 | #[proc_macro] 9 | pub fn codegen_tests(_input: TokenStream) -> TokenStream { 10 | let tests_dir = env::current_dir().unwrap().join("tests/codegen"); 11 | let tests = tests_dir 12 | .read_dir() 13 | .unwrap() 14 | .filter_map(|entry| { 15 | let entry = entry.ok()?; 16 | let path = entry.path(); 17 | let is_dir = entry.file_type().unwrap().is_dir(); 18 | if is_dir || path.extension().and_then(|s| s.to_str()) == Some("wit") { 19 | let test_path = if is_dir { 20 | path.join("wit") 21 | } else { 22 | path.clone() 23 | }; 24 | let name = path.file_stem().unwrap().to_str().unwrap(); 25 | let ident = quote::format_ident!("{}", name.to_snake_case()); 26 | let path = test_path.to_str().unwrap(); 27 | Some(quote::quote! { 28 | codegen_test!(#ident #name #path); 29 | }) 30 | } else { 31 | None 32 | } 33 | }) 34 | .collect::>(); 35 | 36 | (quote::quote!(#(#tests)*)).into() 37 | } 38 | -------------------------------------------------------------------------------- /crates/test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-test" 3 | version = "0.3.0" 4 | description = "wRPC test utilities" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [features] 14 | default = ["nats", "quic", "web-transport"] 15 | nats = ["dep:async-nats", "async-nats/ring", "wrpc-cli/nats"] 16 | quic = [ 17 | "dep:quinn", 18 | "quinn/log", 19 | "quinn/platform-verifier", 20 | "quinn/ring", 21 | "quinn/runtime-tokio", 22 | "quinn/rustls", 23 | ] 24 | web-transport = ["dep:wtransport", "wtransport/self-signed"] 25 | 26 | [dependencies] 27 | anyhow = { workspace = true } 28 | async-nats = { workspace = true, optional = true } 29 | quinn = { workspace = true, optional = true } 30 | rcgen = { workspace = true, features = ["crypto", "ring", "zeroize"] } 31 | rustls = { workspace = true, features = ["logging", "ring"] } 32 | tokio = { workspace = true, features = ["net", "process", "rt-multi-thread"] } 33 | tracing = { workspace = true } 34 | wrpc-cli = { workspace = true } 35 | wtransport = { workspace = true, features = ["ring"], optional = true } 36 | -------------------------------------------------------------------------------- /crates/transport-quic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-transport-quic" 3 | version = "0.5.0" 4 | description = "wRPC QUIC transport" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | quinn = { workspace = true, features = ["runtime-tokio"] } 16 | tracing = { workspace = true } 17 | wrpc-transport = { workspace = true } 18 | 19 | [dev-dependencies] 20 | futures = { workspace = true } 21 | test-log = { workspace = true, features = ["color", "log", "trace"] } 22 | tokio = { workspace = true, features = ["rt-multi-thread"] } 23 | wrpc-test = { workspace = true, features = ["quic"] } 24 | -------------------------------------------------------------------------------- /crates/transport-web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-transport-web" 3 | version = "0.2.0" 4 | description = "wRPC WebTransport transport" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | quinn = { workspace = true } 16 | tracing = { workspace = true } 17 | wrpc-transport = { workspace = true } 18 | wtransport = { workspace = true, features = ["quinn", "ring"] } 19 | 20 | [dev-dependencies] 21 | futures = { workspace = true } 22 | test-log = { workspace = true, features = ["color", "log", "trace"] } 23 | tokio = { workspace = true, features = ["rt-multi-thread"] } 24 | wrpc-test = { workspace = true, features = ["web-transport"] } 25 | -------------------------------------------------------------------------------- /crates/transport/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-transport" 3 | version = "0.28.4" 4 | description = "wRPC core transport functionality" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [features] 13 | default = ["fs", "net", "io-std"] 14 | fs = ["tokio/fs"] 15 | net = ["tokio/net"] 16 | io-std = ["tokio/io-std"] 17 | 18 | [dependencies] 19 | anyhow = { workspace = true, features = ["std"] } 20 | bytes = { workspace = true } 21 | futures = { workspace = true, features = ["std"] } 22 | pin-project-lite = { workspace = true } 23 | send-future = { workspace = true } 24 | tokio = { workspace = true, features = ["macros", "rt", "time"] } 25 | tokio-stream = { workspace = true } 26 | tokio-util = { workspace = true, features = ["codec", "io"] } 27 | tracing = { workspace = true, features = ["attributes"] } 28 | wasm-tokio = { workspace = true, features = ["tracing"] } 29 | 30 | [target.'cfg(target_family = "wasm")'.dependencies] 31 | wasi = { workspace = true, features = ["std"] } 32 | 33 | [dev-dependencies] 34 | test-log = { workspace = true, features = ["color", "log", "trace"] } 35 | tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } 36 | -------------------------------------------------------------------------------- /crates/transport/src/frame/mod.rs: -------------------------------------------------------------------------------- 1 | //! wRPC transport stream framing 2 | 3 | use std::sync::Arc; 4 | 5 | use bytes::Bytes; 6 | 7 | mod codec; 8 | mod conn; 9 | 10 | #[cfg(any(target_family = "wasm", feature = "net"))] 11 | pub mod tcp; 12 | 13 | #[cfg(all(unix, feature = "net"))] 14 | pub mod unix; 15 | 16 | pub use codec::*; 17 | pub use conn::*; 18 | 19 | /// Framing protocol version 20 | pub const PROTOCOL: u8 = 0; 21 | 22 | /// Owned wRPC frame 23 | #[derive(Clone, Debug, Eq, PartialEq)] 24 | pub struct Frame { 25 | /// Frame path 26 | pub path: Arc<[usize]>, 27 | /// Frame data 28 | pub data: Bytes, 29 | } 30 | 31 | /// wRPC frame reference 32 | #[derive(Clone, Debug, Eq, PartialEq)] 33 | pub struct FrameRef<'a> { 34 | /// Frame path 35 | pub path: &'a [usize], 36 | /// Frame data 37 | pub data: &'a [u8], 38 | } 39 | 40 | impl<'a> From<&'a Frame> for FrameRef<'a> { 41 | fn from(Frame { path, data }: &'a Frame) -> Self { 42 | Self { 43 | path: path.as_ref(), 44 | data: data.as_ref(), 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /crates/transport/src/frame/tcp/mod.rs: -------------------------------------------------------------------------------- 1 | //! wRPC TCP transport 2 | 3 | #[cfg(feature = "net")] 4 | pub mod tokio; 5 | #[cfg(feature = "net")] 6 | pub use tokio::*; 7 | 8 | #[cfg(target_family = "wasm")] 9 | pub mod wasi; 10 | #[cfg(all(target_family = "wasm", not(feature = "net")))] 11 | pub use wasi::*; 12 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue-mem/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-wasi-keyvalue-mem" 3 | version = "0.1.0" 4 | description = "In-memory implementation of wRPC `wasi:keyvalue` handler" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | anyhow = { workspace = true, features = ["std"] } 15 | bytes = { workspace = true } 16 | futures = { workspace = true } 17 | tokio = { workspace = true } 18 | tracing = { workspace = true } 19 | wrpc-transport = { workspace = true } 20 | wrpc-wasi-keyvalue = { workspace = true } 21 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue-redis/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-wasi-keyvalue-redis" 3 | version = "0.1.0" 4 | description = "Redis implementation of wRPC `wasi:keyvalue` handler" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | anyhow = { workspace = true, features = ["std"] } 15 | bytes = { workspace = true } 16 | futures = { workspace = true } 17 | redis = { workspace = true, features = [ 18 | "aio", 19 | "bytes", 20 | "connection-manager", 21 | "tokio-comp", 22 | ] } 23 | tokio = { workspace = true } 24 | tracing = { workspace = true } 25 | uuid = { workspace = true, features = ["std", "v7"] } 26 | wrpc-transport = { workspace = true } 27 | wrpc-wasi-keyvalue = { workspace = true } 28 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrpc-wasi-keyvalue" 3 | version = "0.1.1" 4 | description = "`wasi:keyvalue` bindings for wRPC" 5 | 6 | authors.workspace = true 7 | categories.workspace = true 8 | edition.workspace = true 9 | homepage.workspace = true 10 | license.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | wit-bindgen-wrpc = { workspace = true } 15 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue/src/lib.rs: -------------------------------------------------------------------------------- 1 | wit_bindgen_wrpc::generate!({ 2 | world: "proxy", 3 | generate_all, 4 | }); 5 | 6 | // TODO: Generate a single type for both imports and exports 7 | 8 | impl From for exports::wasi::keyvalue::store::Error { 9 | fn from(v: wasi::keyvalue::store::Error) -> Self { 10 | match v { 11 | wasi::keyvalue::store::Error::NoSuchStore => Self::NoSuchStore, 12 | wasi::keyvalue::store::Error::AccessDenied => Self::AccessDenied, 13 | wasi::keyvalue::store::Error::Other(err) => Self::Other(err), 14 | } 15 | } 16 | } 17 | 18 | impl From for wasi::keyvalue::store::Error { 19 | fn from(v: exports::wasi::keyvalue::store::Error) -> Self { 20 | match v { 21 | exports::wasi::keyvalue::store::Error::NoSuchStore => Self::NoSuchStore, 22 | exports::wasi::keyvalue::store::Error::AccessDenied => Self::AccessDenied, 23 | exports::wasi::keyvalue::store::Error::Other(err) => Self::Other(err), 24 | } 25 | } 26 | } 27 | 28 | impl From for exports::wasi::keyvalue::store::KeyResponse { 29 | fn from( 30 | wasi::keyvalue::store::KeyResponse { keys, cursor }: wasi::keyvalue::store::KeyResponse, 31 | ) -> Self { 32 | Self { keys, cursor } 33 | } 34 | } 35 | 36 | impl From for wasi::keyvalue::store::KeyResponse { 37 | fn from( 38 | exports::wasi::keyvalue::store::KeyResponse { keys, cursor }: exports::wasi::keyvalue::store::KeyResponse, 39 | ) -> Self { 40 | Self { keys, cursor } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [keyvalue] 2 | url = "https://github.com/WebAssembly/wasi-keyvalue/archive/da58d54ff969b04e9797dfb986288429cef25e19.tar.gz" 3 | sha256 = "7eaf2e10af6e2de6d5a168893e2656c6685de2009bd37fdc944859f5a6753e55" 4 | sha512 = "ecf0dd2e0b6e5f62c2e10673cc8c2aab86c532f8b19c984fe2ecd9306e9a5c2783183143274477cc4fb3b037b2db2817f248a6bf84b3279180ca4dba832bf5dc" 5 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue/wit/deps.toml: -------------------------------------------------------------------------------- 1 | keyvalue = "https://github.com/WebAssembly/wasi-keyvalue/archive/da58d54ff969b04e9797dfb986288429cef25e19.tar.gz" 2 | -------------------------------------------------------------------------------- /crates/wasi-keyvalue/wit/deps/keyvalue/watch.wit: -------------------------------------------------------------------------------- 1 | /// A keyvalue interface that provides watch operations. 2 | /// 3 | /// This interface is used to provide event-driven mechanisms to handle 4 | /// keyvalue changes. 5 | interface watcher { 6 | /// A keyvalue interface that provides handle-watch operations. 7 | use store.{bucket}; 8 | 9 | /// Handle the `set` event for the given bucket and key. It includes a reference to the `bucket` 10 | /// that can be used to interact with the store. 11 | on-set: func(bucket: bucket, key: string, value: list); 12 | 13 | /// Handle the `delete` event for the given bucket and key. It includes a reference to the 14 | /// `bucket` that can be used to interact with the store. 15 | on-delete: func(bucket: bucket, key: string); 16 | } -------------------------------------------------------------------------------- /crates/wasi-keyvalue/wit/deps/keyvalue/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:keyvalue@0.2.0-draft2; 2 | 3 | /// The `wasi:keyvalue/imports` world provides common APIs for interacting with key-value stores. 4 | /// Components targeting this world will be able to do: 5 | /// 6 | /// 1. CRUD (create, read, update, delete) operations on key-value stores. 7 | /// 2. Atomic `increment` and CAS (compare-and-swap) operations. 8 | /// 3. Batch operations that can reduce the number of round trips to the network. 9 | world imports { 10 | /// The `store` capability allows the component to perform eventually consistent operations on 11 | /// the key-value store. 12 | import store; 13 | 14 | /// The `atomic` capability allows the component to perform atomic / `increment` and CAS 15 | /// (compare-and-swap) operations. 16 | import atomics; 17 | 18 | /// The `batch` capability allows the component to perform eventually consistent batch 19 | /// operations that can reduce the number of round trips to the network. 20 | import batch; 21 | } 22 | 23 | world watch-service { 24 | include imports; 25 | export watcher; 26 | } -------------------------------------------------------------------------------- /crates/wasi-keyvalue/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc:wasi-keyvalue; 2 | 3 | world proxy { 4 | include wasi:keyvalue/imports@0.2.0-draft2; 5 | 6 | export wasi:keyvalue/atomics@0.2.0-draft2; 7 | export wasi:keyvalue/batch@0.2.0-draft2; 8 | export wasi:keyvalue/store@0.2.0-draft2; 9 | } 10 | -------------------------------------------------------------------------------- /crates/wit-bindgen-go/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wit-bindgen-wrpc-go" 3 | version = "0.12.0" 4 | description = """ 5 | Go bindings generator for wRPC 6 | """ 7 | 8 | authors.workspace = true 9 | categories.workspace = true 10 | edition.workspace = true 11 | homepage.workspace = true 12 | license.workspace = true 13 | repository.workspace = true 14 | 15 | [lib] 16 | test = false 17 | doctest = false 18 | 19 | [dependencies] 20 | anyhow = { workspace = true } 21 | clap = { workspace = true, features = ["derive"], optional = true } 22 | heck = { workspace = true } 23 | wit-bindgen-core = { workspace = true } 24 | wrpc-introspect = { workspace = true } 25 | 26 | [dev-dependencies] 27 | test-helpers = { workspace = true } 28 | -------------------------------------------------------------------------------- /crates/wit-bindgen-rust-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wit-bindgen-wrpc-rust-macro" 3 | version = "0.10.0" 4 | description = """ 5 | Procedural macro paired with the `wit-bindgen-wrpc` crate. 6 | """ 7 | authors = [ 8 | "Roman Volosatovs ", 9 | "Alex Crichton ", 10 | ] 11 | 12 | categories.workspace = true 13 | edition.workspace = true 14 | homepage.workspace = true 15 | license.workspace = true 16 | repository.workspace = true 17 | 18 | [lib] 19 | proc-macro = true 20 | doctest = false 21 | test = false 22 | 23 | [dependencies] 24 | anyhow = { workspace = true } 25 | prettyplease = { workspace = true } 26 | proc-macro2 = { workspace = true } 27 | quote = { workspace = true } 28 | syn = { workspace = true, features = ["printing"] } 29 | wit-bindgen-core = { workspace = true } 30 | wit-bindgen-wrpc-rust = { workspace = true } 31 | -------------------------------------------------------------------------------- /crates/wit-bindgen-rust-macro/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rerun-if-changed=build.rs"); 3 | let out_dir = std::env::var("OUT_DIR").unwrap(); 4 | println!("cargo:rustc-env=DEBUG_OUTPUT_DIR={out_dir}"); 5 | } 6 | -------------------------------------------------------------------------------- /crates/wit-bindgen-rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wit-bindgen-wrpc-rust" 3 | version = "0.10.0" 4 | description = """ 5 | Rust bindings generator for wRPC, typically used through 6 | the `wit-bindgen-wrpc` crate's `generate!` macro. 7 | """ 8 | 9 | authors.workspace = true 10 | categories.workspace = true 11 | edition.workspace = true 12 | homepage.workspace = true 13 | license.workspace = true 14 | repository.workspace = true 15 | 16 | [lib] 17 | test = false 18 | doctest = false 19 | 20 | [dependencies] 21 | anyhow = { workspace = true } 22 | clap = { workspace = true, features = ["derive", "std"], optional = true } 23 | heck = { workspace = true } 24 | prettyplease = { workspace = true } 25 | syn = { workspace = true, features = ["parsing"] } 26 | wit-bindgen-core = { workspace = true } 27 | wrpc-introspect = { workspace = true } 28 | 29 | [dev-dependencies] 30 | bytes = { workspace = true } 31 | futures = { workspace = true } 32 | serde = { workspace = true, features = ["derive"] } 33 | serde_json = { workspace = true } 34 | test-helpers = { workspace = true } 35 | tokio = { workspace = true } 36 | wit-bindgen-wrpc = { path = "../wit-bindgen" } 37 | wrpc-transport = { workspace = true } 38 | -------------------------------------------------------------------------------- /crates/wit-bindgen-rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rerun-if-changed=build.rs"); 3 | // this build script is currently only here so OUT_DIR is set for testing. 4 | } 5 | -------------------------------------------------------------------------------- /crates/wit-bindgen-rust/tests/wit/path1/world.wit: -------------------------------------------------------------------------------- 1 | package paths:path1; 2 | 3 | interface test {} 4 | -------------------------------------------------------------------------------- /crates/wit-bindgen-rust/tests/wit/path2/world.wit: -------------------------------------------------------------------------------- 1 | package paths:path2; 2 | 3 | interface test {} 4 | -------------------------------------------------------------------------------- /crates/wit-bindgen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wit-bindgen-wrpc" 3 | version = "0.10.0" 4 | description = """ 5 | Rust bindings generator for wRPC. 6 | """ 7 | authors = [ 8 | "Roman Volosatovs ", 9 | "Alex Crichton ", 10 | ] 11 | 12 | categories.workspace = true 13 | edition.workspace = true 14 | homepage.workspace = true 15 | license.workspace = true 16 | repository.workspace = true 17 | 18 | [dependencies] 19 | anyhow = { workspace = true, features = ["std"] } 20 | bitflags = { workspace = true } 21 | bytes = { workspace = true } 22 | futures = { workspace = true } 23 | tokio = { workspace = true, features = ["macros", "rt"] } 24 | tokio-util = { workspace = true, features = ["codec"] } 25 | tracing = { workspace = true } 26 | wasm-tokio = { workspace = true } 27 | wit-bindgen-wrpc-rust-macro = { workspace = true } 28 | wrpc-transport = { workspace = true } 29 | -------------------------------------------------------------------------------- /crates/wit-bindgen/src/examples/_0_world_imports.rs: -------------------------------------------------------------------------------- 1 | crate::generate!({ 2 | inline: r#" 3 | package example:world-imports; 4 | 5 | world with-imports { 6 | /// Fetch a greeting to present. 7 | import greet: func() -> string; 8 | 9 | /// Log a message to the host. 10 | import log: func(msg: string); 11 | 12 | import my-custom-host: interface { 13 | tick: func(); 14 | } 15 | } 16 | "#, 17 | 18 | // provided to satisfy imports, since `wit_bindgen_wrpc` crate is not imported here. 19 | // not required for external use. 20 | anyhow_path: "anyhow", 21 | wrpc_transport_path: "wrpc_transport", 22 | }); 23 | -------------------------------------------------------------------------------- /crates/wit-bindgen/src/examples/_1_interface_imports.rs: -------------------------------------------------------------------------------- 1 | crate::generate!({ 2 | inline: r#" 3 | package example:interface-imports; 4 | 5 | interface logging { 6 | enum level { 7 | debug, 8 | info, 9 | warn, 10 | error, 11 | } 12 | 13 | log: func(level: level, msg: string); 14 | } 15 | 16 | world with-imports { 17 | // Local interfaces can be imported. 18 | import logging; 19 | 20 | // Dependencies can also be referenced, and they're loaded from the 21 | // `path` directive specified below. 22 | import wasi:cli/environment@0.2.0; 23 | } 24 | "#, 25 | 26 | // provided to satisfy imports, since `wit_bindgen_wrpc` crate is not imported here. 27 | // not required for external use. 28 | anyhow_path: "anyhow", 29 | bytes_path: "bytes", 30 | futures_path: "futures", 31 | tokio_util_path: "tokio_util", 32 | wasm_tokio_path: "wasm_tokio", 33 | wrpc_transport_path: "wrpc_transport", 34 | 35 | path: "wasi-cli@0.2.0.wasm", 36 | 37 | // specify that this interface dependency should be generated as well. 38 | with: { 39 | "wasi:cli/environment@0.2.0": generate, 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /crates/wit-bindgen/src/examples/_2_imported_resources.rs: -------------------------------------------------------------------------------- 1 | crate::generate!({ 2 | inline: r#" 3 | package example:imported-resources; 4 | 5 | world import-some-resources { 6 | enum level { 7 | debug, 8 | info, 9 | warn, 10 | error, 11 | } 12 | resource logger { 13 | constructor(max-level: level); 14 | 15 | get-max-level: func() -> level; 16 | set-max-level: func(level: level); 17 | 18 | log: func(level: level, msg: string); 19 | } 20 | } 21 | "#, 22 | 23 | // provided to satisfy imports, since `wit_bindgen_wrpc` crate is not imported here. 24 | // not required for external use. 25 | anyhow_path: "anyhow", 26 | bytes_path: "bytes", 27 | futures_path: "futures", 28 | tokio_util_path: "tokio_util", 29 | wasm_tokio_path: "wasm_tokio", 30 | wrpc_transport_path: "wrpc_transport", 31 | }); 32 | -------------------------------------------------------------------------------- /crates/wit-bindgen/src/examples/_4_exported_resources.rs: -------------------------------------------------------------------------------- 1 | crate::generate!({ 2 | inline: r#" 3 | package example:exported-resources; 4 | 5 | world import-some-resources { 6 | export logging; 7 | } 8 | 9 | interface logging { 10 | enum level { 11 | debug, 12 | info, 13 | warn, 14 | error, 15 | } 16 | resource logger { 17 | constructor(max-level: level); 18 | 19 | get-max-level: func() -> level; 20 | set-max-level: func(level: level); 21 | 22 | log: func(level: level, msg: string); 23 | } 24 | } 25 | "#, 26 | 27 | // provided to satisfy imports, since `wit_bindgen_wrpc` crate is not imported here, 28 | // not required for external use. 29 | anyhow_path: "anyhow", 30 | bytes_path: "bytes", 31 | futures_path: "futures", 32 | tokio_path: "tokio", 33 | tokio_util_path: "tokio_util", 34 | tracing_path: "tracing", 35 | wasm_tokio_path: "wasm_tokio", 36 | wrpc_transport_path: "wrpc_transport", 37 | }); 38 | -------------------------------------------------------------------------------- /crates/wit-bindgen/wasi-cli@0.2.0.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytecodealliance/wrpc/53e8850788fdd0c8e9d029ba5a41b428169c806e/crates/wit-bindgen/wasi-cli@0.2.0.wasm -------------------------------------------------------------------------------- /examples/go/hello-client/app.go: -------------------------------------------------------------------------------- 1 | //go:generate cargo run --bin wit-bindgen-wrpc go --out-dir bindings --package wrpc.io/examples/go/hello-client/bindings wit 2 | 3 | package app 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "log/slog" 9 | "os" 10 | 11 | "wrpc.io/examples/go/hello-client/bindings/wrpc_examples/hello/handler" 12 | wrpc "wrpc.io/go" 13 | ) 14 | 15 | func init() { 16 | slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ 17 | Level: slog.LevelInfo, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { 18 | if a.Key == slog.TimeKey { 19 | return slog.Attr{} 20 | } 21 | return a 22 | }, 23 | }))) 24 | } 25 | 26 | func Run(target string, client wrpc.Invoker) error { 27 | greeting, err := handler.Hello(context.Background(), client) 28 | if err != nil { 29 | return fmt.Errorf("failed to call `wrpc-examples:hello/handler.hello`: %w", err) 30 | } 31 | fmt.Printf("%s: %s\n", target, greeting) 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /examples/go/hello-client/bindings/client.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // client package contains wRPC bindings for `client` world 3 | package client 4 | -------------------------------------------------------------------------------- /examples/go/hello-client/cmd/hello-client-nats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | 9 | "github.com/nats-io/nats.go" 10 | app "wrpc.io/examples/go/hello-client" 11 | wrpcnats "wrpc.io/go/nats" 12 | ) 13 | 14 | func run() (err error) { 15 | nc, err := nats.Connect(nats.DefaultURL) 16 | if err != nil { 17 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 18 | } 19 | defer nc.Close() 20 | defer func() { 21 | if dErr := nc.Drain(); dErr != nil { 22 | if err == nil { 23 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 24 | } else { 25 | slog.Error("failed to drain NATS.io connection", "err", dErr) 26 | } 27 | } 28 | }() 29 | prefixes := os.Args[1:] 30 | if len(prefixes) == 0 { 31 | prefixes = []string{"go"} 32 | } 33 | for _, prefix := range prefixes { 34 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix(prefix)) 35 | if err := app.Run(prefix, client); err != nil { 36 | return err 37 | } 38 | } 39 | return nil 40 | } 41 | 42 | func main() { 43 | if err := run(); err != nil { 44 | log.Fatal(err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/go/hello-client/cmd/hello-client-tcp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | app "wrpc.io/examples/go/hello-client" 7 | wrpctcp "wrpc.io/go/x/tcp" 8 | ) 9 | 10 | func run() error { 11 | addr := "[::1]:7761" 12 | return app.Run(addr, wrpctcp.NewInvoker(addr)) 13 | } 14 | 15 | func main() { 16 | if err := run(); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/go/hello-client/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/hello-client 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/nats-io/nats.go v1.42.0 9 | wrpc.io/go v0.2.0 10 | ) 11 | 12 | require ( 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/nats-io/nkeys v0.4.11 // indirect 15 | github.com/nats-io/nuid v1.0.1 // indirect 16 | golang.org/x/crypto v0.37.0 // indirect 17 | golang.org/x/sys v0.32.0 // indirect 18 | ) 19 | 20 | replace wrpc.io/go v0.2.0 => ../../../go 21 | -------------------------------------------------------------------------------- /examples/go/hello-client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /examples/go/hello-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/go/hello-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/go/hello-client/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/go/hello-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-go-client; 2 | 3 | world client { 4 | include wrpc-examples:hello/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/go/hello-server/app.go: -------------------------------------------------------------------------------- 1 | //go:generate cargo run --bin wit-bindgen-wrpc go --out-dir bindings --package wrpc.io/examples/go/hello-server/bindings wit 2 | 3 | package app 4 | 5 | import ( 6 | "context" 7 | "log/slog" 8 | "os" 9 | ) 10 | 11 | func init() { 12 | slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ 13 | Level: slog.LevelInfo, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { 14 | if a.Key == slog.TimeKey { 15 | return slog.Attr{} 16 | } 17 | return a 18 | }, 19 | }))) 20 | } 21 | 22 | type Handler struct{} 23 | 24 | func (Handler) Hello(ctx context.Context) (string, error) { 25 | slog.InfoContext(ctx, "handling `wrpc-examples:hello/handler.hello`") 26 | return "hello from Go", nil 27 | } 28 | -------------------------------------------------------------------------------- /examples/go/hello-server/bindings/server.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // server package contains wRPC bindings for `server` world 3 | package server 4 | 5 | import ( 6 | exports__wrpc_examples__hello__handler "wrpc.io/examples/go/hello-server/bindings/exports/wrpc_examples/hello/handler" 7 | wrpc "wrpc.io/go" 8 | ) 9 | 10 | func Serve(s wrpc.Server, h0 exports__wrpc_examples__hello__handler.Handler) (stop func() error, err error) { 11 | stops := make([]func() error, 0, 1) 12 | stop = func() error { 13 | for _, stop := range stops { 14 | if err := stop(); err != nil { 15 | return err 16 | } 17 | } 18 | return nil 19 | } 20 | stop0, err := exports__wrpc_examples__hello__handler.ServeInterface(s, h0) 21 | if err != nil { 22 | return 23 | } 24 | stops = append(stops, stop0) 25 | stop = func() error { 26 | if err := stop0(); err != nil { 27 | return err 28 | } 29 | return nil 30 | } 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /examples/go/hello-server/cmd/hello-server-nats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/nats-io/nats.go" 12 | app "wrpc.io/examples/go/hello-server" 13 | server "wrpc.io/examples/go/hello-server/bindings" 14 | wrpcnats "wrpc.io/go/nats" 15 | ) 16 | 17 | func run() (err error) { 18 | nc, err := nats.Connect(nats.DefaultURL) 19 | if err != nil { 20 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 21 | } 22 | defer nc.Close() 23 | defer func() { 24 | if dErr := nc.Drain(); dErr != nil { 25 | if err == nil { 26 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 27 | } else { 28 | slog.Error("failed to drain NATS.io connection", "err", dErr) 29 | } 30 | } 31 | }() 32 | 33 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix("go")) 34 | stop, err := server.Serve(client, app.Handler{}) 35 | if err != nil { 36 | return fmt.Errorf("failed to serve `server` world: %w", err) 37 | } 38 | 39 | signalCh := make(chan os.Signal, 1) 40 | signal.Notify(signalCh, syscall.SIGINT) 41 | <-signalCh 42 | 43 | if err = stop(); err != nil { 44 | return fmt.Errorf("failed to stop `server` world: %w", err) 45 | } 46 | return nil 47 | } 48 | 49 | func main() { 50 | if err := run(); err != nil { 51 | log.Fatal(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/go/hello-server/cmd/hello-server-tcp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "log/slog" 9 | "net" 10 | "os" 11 | "os/signal" 12 | "syscall" 13 | 14 | app "wrpc.io/examples/go/hello-server" 15 | server "wrpc.io/examples/go/hello-server/bindings" 16 | wrpctcp "wrpc.io/go/x/tcp" 17 | ) 18 | 19 | func run() (err error) { 20 | l, err := net.ListenTCP("tcp", &net.TCPAddr{ 21 | IP: net.IPv6loopback, 22 | Port: 7761, 23 | }) 24 | if err != nil { 25 | return fmt.Errorf("failed to listen on TCP socket: %w", err) 26 | } 27 | 28 | ctx := context.Background() 29 | ctx, cancel := context.WithCancel(ctx) 30 | defer cancel() 31 | 32 | srv := wrpctcp.NewServerWithContext(ctx, l) 33 | stop, err := server.Serve(srv, app.Handler{}) 34 | if err != nil { 35 | return fmt.Errorf("failed to serve `server` world: %w", err) 36 | } 37 | 38 | go func() { 39 | for { 40 | select { 41 | case <-ctx.Done(): 42 | return 43 | default: 44 | slog.Debug("accepting invocation") 45 | if err := srv.Accept(); err != nil { 46 | if !errors.Is(err, net.ErrClosed) { 47 | slog.Error("failed to accept invocation", "err", err) 48 | } 49 | } 50 | } 51 | } 52 | }() 53 | 54 | signalCh := make(chan os.Signal, 1) 55 | signal.Notify(signalCh, syscall.SIGINT) 56 | <-signalCh 57 | 58 | if err = stop(); err != nil { 59 | return fmt.Errorf("failed to stop `server` world: %w", err) 60 | } 61 | return nil 62 | } 63 | 64 | func main() { 65 | if err := run(); err != nil { 66 | log.Fatal(err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/go/hello-server/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/hello-server 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/nats-io/nats.go v1.42.0 9 | wrpc.io/go v0.2.0 10 | ) 11 | 12 | require ( 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/nats-io/nkeys v0.4.11 // indirect 15 | github.com/nats-io/nuid v1.0.1 // indirect 16 | golang.org/x/crypto v0.37.0 // indirect 17 | golang.org/x/sys v0.32.0 // indirect 18 | ) 19 | 20 | replace wrpc.io/go v0.2.0 => ../../../go 21 | -------------------------------------------------------------------------------- /examples/go/hello-server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /examples/go/hello-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/go/hello-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/go/hello-server/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/go/hello-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-go-server; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/go/resources-server/bindings/server.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // server package contains wRPC bindings for `server` world 3 | package server 4 | 5 | import ( 6 | exports__wrpc_examples__resources__resources "wrpc.io/examples/go/resources-server/bindings/exports/wrpc_examples/resources/resources" 7 | wrpc "wrpc.io/go" 8 | ) 9 | 10 | func Serve(s wrpc.Server, h0 exports__wrpc_examples__resources__resources.Handler) (stop func() error, err error) { 11 | stops := make([]func() error, 0, 1) 12 | stop = func() error { 13 | for _, stop := range stops { 14 | if err := stop(); err != nil { 15 | return err 16 | } 17 | } 18 | return nil 19 | } 20 | stop0, err := exports__wrpc_examples__resources__resources.ServeInterface(s, h0) 21 | if err != nil { 22 | return 23 | } 24 | stops = append(stops, stop0) 25 | stop = func() error { 26 | if err := stop0(); err != nil { 27 | return err 28 | } 29 | return nil 30 | } 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /examples/go/resources-server/cmd/resources-server-nats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/nats-io/nats.go" 12 | app "wrpc.io/examples/go/resources-server" 13 | server "wrpc.io/examples/go/resources-server/bindings" 14 | wrpcnats "wrpc.io/go/nats" 15 | ) 16 | 17 | func run() (err error) { 18 | nc, err := nats.Connect(nats.DefaultURL) 19 | if err != nil { 20 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 21 | } 22 | defer nc.Close() 23 | defer func() { 24 | if dErr := nc.Drain(); dErr != nil { 25 | if err == nil { 26 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 27 | } else { 28 | slog.Error("failed to drain NATS.io connection", "err", dErr) 29 | } 30 | } 31 | }() 32 | 33 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix("go")) 34 | stop, err := server.Serve(client, &app.Handler{}) 35 | if err != nil { 36 | return fmt.Errorf("failed to serve `server` world: %w", err) 37 | } 38 | 39 | signalCh := make(chan os.Signal, 1) 40 | signal.Notify(signalCh, syscall.SIGINT) 41 | <-signalCh 42 | 43 | if err = stop(); err != nil { 44 | return fmt.Errorf("failed to stop `server` world: %w", err) 45 | } 46 | return nil 47 | } 48 | 49 | func main() { 50 | if err := run(); err != nil { 51 | log.Fatal(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/go/resources-server/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/resources-server 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/google/uuid v1.6.0 9 | github.com/nats-io/nats.go v1.42.0 10 | wrpc.io/go v0.2.0 11 | ) 12 | 13 | require ( 14 | github.com/klauspost/compress v1.18.0 // indirect 15 | github.com/nats-io/nkeys v0.4.11 // indirect 16 | github.com/nats-io/nuid v1.0.1 // indirect 17 | golang.org/x/crypto v0.37.0 // indirect 18 | golang.org/x/sys v0.32.0 // indirect 19 | ) 20 | 21 | replace wrpc.io/go v0.2.0 => ../../../go 22 | -------------------------------------------------------------------------------- /examples/go/resources-server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 2 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 3 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 4 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 5 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 6 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 7 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 8 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 9 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 10 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 11 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 12 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 13 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 14 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 15 | -------------------------------------------------------------------------------- /examples/go/resources-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [resources] 2 | path = "../../../wit/resources" 3 | sha256 = "d47aff89928fe5bb30ddc79a4bae79a5af6fa075e8694953567544fefa507048" 4 | sha512 = "2de2d6fccb3bde7f9c163890993b53191cc399fb16e28742dbd25f449fc1d8a2e0766a101d0cf4c252be07e2aa3c892daba876b009a0bd33e3c5dd5f74f790da" 5 | -------------------------------------------------------------------------------- /examples/go/resources-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | resources = "../../../wit/resources" 2 | -------------------------------------------------------------------------------- /examples/go/resources-server/wit/deps/resources/resources.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources; 2 | 3 | interface resources { 4 | resource foo { 5 | constructor(); 6 | foo: static func(v: foo) -> string; 7 | bar: func() -> string; 8 | } 9 | 10 | bar: func(v: borrow) -> string; 11 | } 12 | 13 | world client { 14 | import resources; 15 | } 16 | 17 | world server { 18 | export resources; 19 | } 20 | -------------------------------------------------------------------------------- /examples/go/resources-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources-go-server; 2 | 3 | world server { 4 | include wrpc-examples:resources/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/go/streams-client/bindings/client.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // client package contains wRPC bindings for `client` world 3 | package client 4 | -------------------------------------------------------------------------------- /examples/go/streams-client/cmd/streams-client-nats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | 9 | "github.com/nats-io/nats.go" 10 | app "wrpc.io/examples/go/streams-client" 11 | wrpcnats "wrpc.io/go/nats" 12 | ) 13 | 14 | func run() (err error) { 15 | nc, err := nats.Connect(nats.DefaultURL) 16 | if err != nil { 17 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 18 | } 19 | defer nc.Close() 20 | defer func() { 21 | if dErr := nc.Drain(); dErr != nil { 22 | if err == nil { 23 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 24 | } else { 25 | slog.Error("failed to drain NATS.io connection", "err", dErr) 26 | } 27 | } 28 | }() 29 | prefixes := os.Args[1:] 30 | if len(prefixes) == 0 { 31 | prefixes = []string{"go"} 32 | } 33 | for _, prefix := range prefixes { 34 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix(prefix)) 35 | if err := app.Run(prefix, client); err != nil { 36 | return err 37 | } 38 | } 39 | return nil 40 | } 41 | 42 | func main() { 43 | if err := run(); err != nil { 44 | log.Fatal(err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/go/streams-client/cmd/streams-client-tcp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | app "wrpc.io/examples/go/streams-client" 7 | wrpctcp "wrpc.io/go/x/tcp" 8 | ) 9 | 10 | func run() (err error) { 11 | addr := "[::1]:7761" 12 | return app.Run(addr, wrpctcp.NewInvoker(addr)) 13 | } 14 | 15 | func main() { 16 | if err := run(); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/go/streams-client/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/streams-client 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/nats-io/nats.go v1.42.0 9 | wrpc.io/go v0.2.0 10 | ) 11 | 12 | require ( 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/nats-io/nkeys v0.4.11 // indirect 15 | github.com/nats-io/nuid v1.0.1 // indirect 16 | golang.org/x/crypto v0.37.0 // indirect 17 | golang.org/x/sys v0.32.0 // indirect 18 | ) 19 | 20 | replace wrpc.io/go v0.2.0 => ../../../go 21 | -------------------------------------------------------------------------------- /examples/go/streams-client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /examples/go/streams-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [streams] 2 | path = "../../../wit/streams" 3 | sha256 = "5064bee90ebea73f1695987191fbbfea71ed2dbb69839814009490b4fbe8e96f" 4 | sha512 = "dfca3844d91c6c8e83fefd7b9511a366b464cf69d017c61b671409cb26dc9490a0e59a8e60ef15b77fdeb4fc1b8d9e6efa11c2fb1a1dabd0141e5e6afe8a59b9" 5 | -------------------------------------------------------------------------------- /examples/go/streams-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | streams = "../../../wit/streams" 2 | -------------------------------------------------------------------------------- /examples/go/streams-client/wit/deps/streams/streams.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams; 2 | 3 | interface handler { 4 | record req { 5 | numbers: stream, 6 | bytes: stream, 7 | } 8 | echo: func(r: req) -> (numbers: stream, bytes: stream); 9 | } 10 | 11 | world client { 12 | import handler; 13 | } 14 | 15 | world server { 16 | export handler; 17 | } 18 | -------------------------------------------------------------------------------- /examples/go/streams-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams-go-client; 2 | 3 | world client { 4 | include wrpc-examples:streams/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/go/streams-server/app.go: -------------------------------------------------------------------------------- 1 | //go:generate cargo run --bin wit-bindgen-wrpc go --out-dir bindings --package wrpc.io/examples/go/streams-server/bindings wit 2 | 3 | package app 4 | 5 | import ( 6 | "context" 7 | "io" 8 | "log/slog" 9 | "os" 10 | 11 | "wrpc.io/examples/go/streams-server/bindings/exports/wrpc_examples/streams/handler" 12 | wrpc "wrpc.io/go" 13 | ) 14 | 15 | func init() { 16 | slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ 17 | Level: slog.LevelInfo, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { 18 | if a.Key == slog.TimeKey { 19 | return slog.Attr{} 20 | } 21 | return a 22 | }, 23 | }))) 24 | } 25 | 26 | type Handler struct{} 27 | 28 | func (Handler) Echo(ctx context.Context, req *handler.Req) (wrpc.Receiver[[]uint64], io.ReadCloser, error) { 29 | slog.InfoContext(ctx, "handling `wrpc-examples:streams/handler.echo`") 30 | return req.Numbers, req.Bytes, nil 31 | } 32 | -------------------------------------------------------------------------------- /examples/go/streams-server/bindings/server.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // server package contains wRPC bindings for `server` world 3 | package server 4 | 5 | import ( 6 | exports__wrpc_examples__streams__handler "wrpc.io/examples/go/streams-server/bindings/exports/wrpc_examples/streams/handler" 7 | wrpc "wrpc.io/go" 8 | ) 9 | 10 | func Serve(s wrpc.Server, h0 exports__wrpc_examples__streams__handler.Handler) (stop func() error, err error) { 11 | stops := make([]func() error, 0, 1) 12 | stop = func() error { 13 | for _, stop := range stops { 14 | if err := stop(); err != nil { 15 | return err 16 | } 17 | } 18 | return nil 19 | } 20 | stop0, err := exports__wrpc_examples__streams__handler.ServeInterface(s, h0) 21 | if err != nil { 22 | return 23 | } 24 | stops = append(stops, stop0) 25 | stop = func() error { 26 | if err := stop0(); err != nil { 27 | return err 28 | } 29 | return nil 30 | } 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /examples/go/streams-server/cmd/streams-server-nats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/nats-io/nats.go" 12 | app "wrpc.io/examples/go/streams-server" 13 | server "wrpc.io/examples/go/streams-server/bindings" 14 | wrpcnats "wrpc.io/go/nats" 15 | ) 16 | 17 | func run() (err error) { 18 | nc, err := nats.Connect(nats.DefaultURL) 19 | if err != nil { 20 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 21 | } 22 | defer nc.Close() 23 | defer func() { 24 | if dErr := nc.Drain(); dErr != nil { 25 | if err == nil { 26 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 27 | } else { 28 | slog.Error("failed to drain NATS.io connection", "err", dErr) 29 | } 30 | } 31 | }() 32 | 33 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix("go")) 34 | stop, err := server.Serve(client, app.Handler{}) 35 | if err != nil { 36 | return fmt.Errorf("failed to serve `server` world: %w", err) 37 | } 38 | 39 | signalCh := make(chan os.Signal, 1) 40 | signal.Notify(signalCh, syscall.SIGINT) 41 | <-signalCh 42 | 43 | if err = stop(); err != nil { 44 | return fmt.Errorf("failed to stop `server` world: %w", err) 45 | } 46 | return nil 47 | } 48 | 49 | func main() { 50 | if err := run(); err != nil { 51 | log.Fatal(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/go/streams-server/cmd/streams-server-tcp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "log/slog" 9 | "net" 10 | "os" 11 | "os/signal" 12 | "syscall" 13 | 14 | app "wrpc.io/examples/go/streams-server" 15 | server "wrpc.io/examples/go/streams-server/bindings" 16 | wrpctcp "wrpc.io/go/x/tcp" 17 | ) 18 | 19 | func run() (err error) { 20 | l, err := net.ListenTCP("tcp", &net.TCPAddr{ 21 | IP: net.IPv6loopback, 22 | Port: 7761, 23 | }) 24 | if err != nil { 25 | return fmt.Errorf("failed to listen on TCP socket: %w", err) 26 | } 27 | 28 | ctx := context.Background() 29 | ctx, cancel := context.WithCancel(ctx) 30 | defer cancel() 31 | 32 | srv := wrpctcp.NewServerWithContext(ctx, l) 33 | stop, err := server.Serve(srv, app.Handler{}) 34 | if err != nil { 35 | return fmt.Errorf("failed to serve `server` world: %w", err) 36 | } 37 | 38 | go func() { 39 | for { 40 | select { 41 | case <-ctx.Done(): 42 | return 43 | default: 44 | slog.Debug("accepting invocation") 45 | if err := srv.Accept(); err != nil { 46 | if !errors.Is(err, net.ErrClosed) { 47 | slog.Error("failed to accept invocation", "err", err) 48 | } 49 | } 50 | } 51 | } 52 | }() 53 | 54 | signalCh := make(chan os.Signal, 1) 55 | signal.Notify(signalCh, syscall.SIGINT) 56 | <-signalCh 57 | 58 | cancel() 59 | if err := l.Close(); err != nil { 60 | slog.Error("failed to close TCP listener", "err", err) 61 | } 62 | if err = stop(); err != nil { 63 | return fmt.Errorf("failed to stop `server` world: %w", err) 64 | } 65 | return nil 66 | } 67 | 68 | func main() { 69 | if err := run(); err != nil { 70 | log.Fatal(err) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /examples/go/streams-server/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/streams-server 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/nats-io/nats.go v1.42.0 9 | wrpc.io/go v0.2.0 10 | ) 11 | 12 | require ( 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/nats-io/nkeys v0.4.11 // indirect 15 | github.com/nats-io/nuid v1.0.1 // indirect 16 | golang.org/x/crypto v0.37.0 // indirect 17 | golang.org/x/sys v0.32.0 // indirect 18 | ) 19 | 20 | replace wrpc.io/go v0.2.0 => ../../../go 21 | -------------------------------------------------------------------------------- /examples/go/streams-server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /examples/go/streams-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [streams] 2 | path = "../../../wit/streams" 3 | sha256 = "5064bee90ebea73f1695987191fbbfea71ed2dbb69839814009490b4fbe8e96f" 4 | sha512 = "dfca3844d91c6c8e83fefd7b9511a366b464cf69d017c61b671409cb26dc9490a0e59a8e60ef15b77fdeb4fc1b8d9e6efa11c2fb1a1dabd0141e5e6afe8a59b9" 5 | -------------------------------------------------------------------------------- /examples/go/streams-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | streams = "../../../wit/streams" 2 | -------------------------------------------------------------------------------- /examples/go/streams-server/wit/deps/streams/streams.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams; 2 | 3 | interface handler { 4 | record req { 5 | numbers: stream, 6 | bytes: stream, 7 | } 8 | echo: func(r: req) -> (numbers: stream, bytes: stream); 9 | } 10 | 11 | world client { 12 | import handler; 13 | } 14 | 15 | world server { 16 | export handler; 17 | } 18 | -------------------------------------------------------------------------------- /examples/go/streams-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams-go-server; 2 | 3 | world server { 4 | include wrpc-examples:streams/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/bindings/client.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // client package contains wRPC bindings for `client` world 3 | package client 4 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/cmd/wasi-keyvalue-nats-client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | 9 | "github.com/nats-io/nats.go" 10 | app "wrpc.io/examples/go/wasi-keyvalue-client" 11 | wrpcnats "wrpc.io/go/nats" 12 | ) 13 | 14 | func run() (err error) { 15 | nc, err := nats.Connect(nats.DefaultURL) 16 | if err != nil { 17 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 18 | } 19 | defer nc.Close() 20 | defer func() { 21 | if dErr := nc.Drain(); dErr != nil { 22 | if err == nil { 23 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 24 | } else { 25 | slog.Error("failed to drain NATS.io connection", "err", dErr) 26 | } 27 | } 28 | }() 29 | prefixes := os.Args[1:] 30 | if len(prefixes) == 0 { 31 | prefixes = []string{"go"} 32 | } 33 | for _, prefix := range prefixes { 34 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix(prefix)) 35 | if err := app.Run(prefix, client); err != nil { 36 | return err 37 | } 38 | } 39 | return nil 40 | } 41 | 42 | func main() { 43 | if err := run(); err != nil { 44 | log.Fatal(err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/cmd/wasi-keyvalue-tcp-client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | app "wrpc.io/examples/go/wasi-keyvalue-client" 7 | wrpctcp "wrpc.io/go/x/tcp" 8 | ) 9 | 10 | func run() (err error) { 11 | addr := "[::1]:7761" 12 | return app.Run(addr, wrpctcp.NewInvoker(addr)) 13 | } 14 | 15 | func main() { 16 | if err := run(); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/wasi-keyvalue-client 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/nats-io/nats.go v1.42.0 9 | wrpc.io/go v0.2.0 10 | ) 11 | 12 | require ( 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/nats-io/nkeys v0.4.11 // indirect 15 | github.com/nats-io/nuid v1.0.1 // indirect 16 | golang.org/x/crypto v0.37.0 // indirect 17 | golang.org/x/sys v0.32.0 // indirect 18 | ) 19 | 20 | replace wrpc.io/go v0.2.0 => ../../../go 21 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [keyvalue] 2 | path = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 3 | sha256 = "7eaf2e10af6e2de6d5a168893e2656c6685de2009bd37fdc944859f5a6753e55" 4 | sha512 = "ecf0dd2e0b6e5f62c2e10673cc8c2aab86c532f8b19c984fe2ecd9306e9a5c2783183143274477cc4fb3b037b2db2817f248a6bf84b3279180ca4dba832bf5dc" 5 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | keyvalue = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 2 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/wit/deps/keyvalue/watch.wit: -------------------------------------------------------------------------------- 1 | /// A keyvalue interface that provides watch operations. 2 | /// 3 | /// This interface is used to provide event-driven mechanisms to handle 4 | /// keyvalue changes. 5 | interface watcher { 6 | /// A keyvalue interface that provides handle-watch operations. 7 | use store.{bucket}; 8 | 9 | /// Handle the `set` event for the given bucket and key. It includes a reference to the `bucket` 10 | /// that can be used to interact with the store. 11 | on-set: func(bucket: bucket, key: string, value: list); 12 | 13 | /// Handle the `delete` event for the given bucket and key. It includes a reference to the 14 | /// `bucket` that can be used to interact with the store. 15 | on-delete: func(bucket: bucket, key: string); 16 | } -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/wit/deps/keyvalue/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:keyvalue@0.2.0-draft2; 2 | 3 | /// The `wasi:keyvalue/imports` world provides common APIs for interacting with key-value stores. 4 | /// Components targeting this world will be able to do: 5 | /// 6 | /// 1. CRUD (create, read, update, delete) operations on key-value stores. 7 | /// 2. Atomic `increment` and CAS (compare-and-swap) operations. 8 | /// 3. Batch operations that can reduce the number of round trips to the network. 9 | world imports { 10 | /// The `store` capability allows the component to perform eventually consistent operations on 11 | /// the key-value store. 12 | import store; 13 | 14 | /// The `atomic` capability allows the component to perform atomic / `increment` and CAS 15 | /// (compare-and-swap) operations. 16 | import atomics; 17 | 18 | /// The `batch` capability allows the component to perform eventually consistent batch 19 | /// operations that can reduce the number of round trips to the network. 20 | import batch; 21 | } 22 | 23 | world watch-service { 24 | include imports; 25 | export watcher; 26 | } -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:wasi-keyvalue-nats-client; 2 | 3 | world client { 4 | import wasi:keyvalue/store@0.2.0-draft2; 5 | } 6 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/bindings/server.wrpc.go: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen-wrpc-go` 0.12.0. DO NOT EDIT! 2 | // server package contains wRPC bindings for `server` world 3 | package server 4 | 5 | import ( 6 | exports__wasi__keyvalue__store "wrpc.io/examples/go/wasi-keyvalue-server/bindings/exports/wasi/keyvalue/store" 7 | wrpc "wrpc.io/go" 8 | ) 9 | 10 | func Serve(s wrpc.Server, h0 exports__wasi__keyvalue__store.Handler) (stop func() error, err error) { 11 | stops := make([]func() error, 0, 1) 12 | stop = func() error { 13 | for _, stop := range stops { 14 | if err := stop(); err != nil { 15 | return err 16 | } 17 | } 18 | return nil 19 | } 20 | stop0, err := exports__wasi__keyvalue__store.ServeInterface(s, h0) 21 | if err != nil { 22 | return 23 | } 24 | stops = append(stops, stop0) 25 | stop = func() error { 26 | if err := stop0(); err != nil { 27 | return err 28 | } 29 | return nil 30 | } 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/cmd/wasi-keyvalue-nats-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "log/slog" 7 | "os" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/nats-io/nats.go" 12 | app "wrpc.io/examples/go/wasi-keyvalue-server" 13 | server "wrpc.io/examples/go/wasi-keyvalue-server/bindings" 14 | wrpcnats "wrpc.io/go/nats" 15 | ) 16 | 17 | func run() error { 18 | nc, err := nats.Connect(nats.DefaultURL) 19 | if err != nil { 20 | return fmt.Errorf("failed to connect to NATS.io: %w", err) 21 | } 22 | defer nc.Close() 23 | defer func() { 24 | if dErr := nc.Drain(); dErr != nil { 25 | if err == nil { 26 | err = fmt.Errorf("failed to drain NATS.io connection: %w", dErr) 27 | } else { 28 | slog.Error("failed to drain NATS.io connection", "err", dErr) 29 | } 30 | } 31 | }() 32 | 33 | client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix("go")) 34 | stop, err := server.Serve(client, &app.Handler{}) 35 | if err != nil { 36 | return fmt.Errorf("failed to serve `server` world: %w", err) 37 | } 38 | 39 | signalCh := make(chan os.Signal, 1) 40 | signal.Notify(signalCh, syscall.SIGINT) 41 | <-signalCh 42 | 43 | if err = stop(); err != nil { 44 | return fmt.Errorf("failed to stop `server` world: %w", err) 45 | } 46 | return nil 47 | } 48 | 49 | func main() { 50 | if err := run(); err != nil { 51 | log.Fatal(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/cmd/wasi-keyvalue-tcp-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "log/slog" 9 | "net" 10 | "os" 11 | "os/signal" 12 | "syscall" 13 | 14 | app "wrpc.io/examples/go/wasi-keyvalue-server" 15 | server "wrpc.io/examples/go/wasi-keyvalue-server/bindings" 16 | wrpctcp "wrpc.io/go/x/tcp" 17 | ) 18 | 19 | func run() error { 20 | l, err := net.ListenTCP("tcp", &net.TCPAddr{ 21 | IP: net.IPv6loopback, 22 | Port: 7761, 23 | }) 24 | if err != nil { 25 | return fmt.Errorf("failed to listen on TCP socket: %w", err) 26 | } 27 | 28 | ctx := context.Background() 29 | ctx, cancel := context.WithCancel(ctx) 30 | defer cancel() 31 | 32 | srv := wrpctcp.NewServerWithContext(ctx, l) 33 | stop, err := server.Serve(srv, &app.Handler{}) 34 | if err != nil { 35 | return fmt.Errorf("failed to serve `server` world: %w", err) 36 | } 37 | 38 | go func() { 39 | for { 40 | select { 41 | case <-ctx.Done(): 42 | return 43 | default: 44 | slog.Debug("accepting invocation") 45 | if err := srv.Accept(); err != nil { 46 | if !errors.Is(err, net.ErrClosed) { 47 | slog.Error("failed to accept invocation", "err", err) 48 | } 49 | } 50 | } 51 | } 52 | }() 53 | 54 | signalCh := make(chan os.Signal, 1) 55 | signal.Notify(signalCh, syscall.SIGINT) 56 | <-signalCh 57 | 58 | if err = stop(); err != nil { 59 | return fmt.Errorf("failed to stop `server` world: %w", err) 60 | } 61 | return nil 62 | } 63 | 64 | func main() { 65 | if err := run(); err != nil { 66 | log.Fatal(err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/examples/go/wasi-keyvalue-server 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/nats-io/nats.go v1.42.0 9 | wrpc.io/go v0.2.0 10 | ) 11 | 12 | require ( 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/nats-io/nkeys v0.4.11 // indirect 15 | github.com/nats-io/nuid v1.0.1 // indirect 16 | golang.org/x/crypto v0.37.0 // indirect 17 | golang.org/x/sys v0.32.0 // indirect 18 | ) 19 | 20 | replace wrpc.io/go v0.2.0 => ../../../go 21 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [keyvalue] 2 | path = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 3 | sha256 = "7eaf2e10af6e2de6d5a168893e2656c6685de2009bd37fdc944859f5a6753e55" 4 | sha512 = "ecf0dd2e0b6e5f62c2e10673cc8c2aab86c532f8b19c984fe2ecd9306e9a5c2783183143274477cc4fb3b037b2db2817f248a6bf84b3279180ca4dba832bf5dc" 5 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | keyvalue = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 2 | -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/wit/deps/keyvalue/watch.wit: -------------------------------------------------------------------------------- 1 | /// A keyvalue interface that provides watch operations. 2 | /// 3 | /// This interface is used to provide event-driven mechanisms to handle 4 | /// keyvalue changes. 5 | interface watcher { 6 | /// A keyvalue interface that provides handle-watch operations. 7 | use store.{bucket}; 8 | 9 | /// Handle the `set` event for the given bucket and key. It includes a reference to the `bucket` 10 | /// that can be used to interact with the store. 11 | on-set: func(bucket: bucket, key: string, value: list); 12 | 13 | /// Handle the `delete` event for the given bucket and key. It includes a reference to the 14 | /// `bucket` that can be used to interact with the store. 15 | on-delete: func(bucket: bucket, key: string); 16 | } -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/wit/deps/keyvalue/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:keyvalue@0.2.0-draft2; 2 | 3 | /// The `wasi:keyvalue/imports` world provides common APIs for interacting with key-value stores. 4 | /// Components targeting this world will be able to do: 5 | /// 6 | /// 1. CRUD (create, read, update, delete) operations on key-value stores. 7 | /// 2. Atomic `increment` and CAS (compare-and-swap) operations. 8 | /// 3. Batch operations that can reduce the number of round trips to the network. 9 | world imports { 10 | /// The `store` capability allows the component to perform eventually consistent operations on 11 | /// the key-value store. 12 | import store; 13 | 14 | /// The `atomic` capability allows the component to perform atomic / `increment` and CAS 15 | /// (compare-and-swap) operations. 16 | import atomics; 17 | 18 | /// The `batch` capability allows the component to perform eventually consistent batch 19 | /// operations that can reduce the number of round trips to the network. 20 | import batch; 21 | } 22 | 23 | world watch-service { 24 | include imports; 25 | export watcher; 26 | } -------------------------------------------------------------------------------- /examples/go/wasi-keyvalue-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:wasi-keyvalue-nats-server; 2 | 3 | world server { 4 | export wasi:keyvalue/store@0.2.0-draft2; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-component-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-component-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-client/src/main.rs: -------------------------------------------------------------------------------- 1 | mod bindings { 2 | wit_bindgen::generate!({ 3 | with: { 4 | "wrpc-examples:hello/handler": generate, 5 | } 6 | }); 7 | } 8 | 9 | fn main() { 10 | let greeting = bindings::wrpc_examples::hello::handler::hello(); 11 | println!("{greeting}"); 12 | } 13 | -------------------------------------------------------------------------------- /examples/rust/hello-component-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-component-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-component-client/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-component-client; 2 | 3 | world client { 4 | include wrpc-examples:hello/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-component-rpc-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello-rpc" 3 | sha256 = "e11bd974f6b9c0cc440582ae31bcc21285e37860bff5377a89b0259b15e4fe91" 4 | sha512 = "4413b0891afb6e761f1cf2ca305654a5aa73883305fd0dce3a4d27e54ce06ba34947b43ace31ebc4ab6c65bbc12cf17c6e56ea819bd1bea561a735b6374bdf9c" 5 | deps = ["io", "rpc"] 6 | 7 | [io] 8 | sha256 = "7210e5653539a15478f894d4da24cc69d61924cbcba21d2804d69314a88e5a4c" 9 | sha512 = "49184a1b0945a889abd52d25271172ed3dc2db6968fcdddb1bab7ee0081f4a3eeee0977ad2291126a37631c0d86eeea75d822fa8af224c422134500bf9f0f2bb" 10 | 11 | [rpc] 12 | sha256 = "61f1545986917171d3e3dab7edf4286ca1769e73599ba83e1c3667de5ad955e8" 13 | sha512 = "64a16b8fbda6f9335cfd726eb80f9f77ae4551831c443dfad794cb76e2176135015fb1cbef8f50c5b90fd5fec6b2b6feeb8af74010f35c58ca922ad317e26ff7" 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello-rpc" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | use wrpc:rpc/error@0.1.0.{error}; 5 | 6 | hello: func() -> result; 7 | } 8 | 9 | world client { 10 | import handler; 11 | } 12 | 13 | world server { 14 | export handler; 15 | } 16 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/wit/deps/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | 4 | interface error { 5 | /// A resource which represents some error information. 6 | /// 7 | /// The only method provided by this resource is `to-debug-string`, 8 | /// which provides some human-readable information about the error. 9 | /// 10 | /// In the `wasi:io` package, this resource is returned through the 11 | /// `wasi:io/streams/stream-error` type. 12 | /// 13 | /// To provide more specific error information, other interfaces may 14 | /// provide functions to further "downcast" this error into more specific 15 | /// error information. For example, `error`s returned in streams derived 16 | /// from filesystem types to be described using the filesystem's own 17 | /// error-code type, using the function 18 | /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter 19 | /// `borrow` and returns 20 | /// `option`. 21 | /// 22 | /// The set of functions which can "downcast" an `error` into a more 23 | /// concrete type is open. 24 | resource error { 25 | /// Returns a string that is suitable to assist humans in debugging 26 | /// this error. 27 | /// 28 | /// WARNING: The returned string should not be consumed mechanically! 29 | /// It may change across platforms, hosts, or other implementation 30 | /// details. Parsing this string is a major platform-compatibility 31 | /// hazard. 32 | to-debug-string: func() -> string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/wit/deps/io/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | world imports { 4 | import streams; 5 | import poll; 6 | } 7 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-component-rpc-client; 2 | 3 | world client { 4 | include wrpc:rpc/imports@0.1.0; 5 | 6 | include wrpc-examples:hello/client; 7 | } 8 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-component-rpc-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [dependencies] 16 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 17 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod bindings { 2 | use crate::Handler; 3 | 4 | wit_bindgen::generate!({ generate_all }); 5 | export!(Handler); 6 | } 7 | 8 | type Result = core::result::Result; 9 | 10 | struct Handler; 11 | 12 | impl bindings::exports::wrpc_examples::hello::handler::Guest for Handler { 13 | fn hello() -> Result { 14 | Ok("hello from Rust".to_string()) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello-rpc" 3 | sha256 = "e11bd974f6b9c0cc440582ae31bcc21285e37860bff5377a89b0259b15e4fe91" 4 | sha512 = "4413b0891afb6e761f1cf2ca305654a5aa73883305fd0dce3a4d27e54ce06ba34947b43ace31ebc4ab6c65bbc12cf17c6e56ea819bd1bea561a735b6374bdf9c" 5 | deps = ["io", "rpc"] 6 | 7 | [io] 8 | sha256 = "7210e5653539a15478f894d4da24cc69d61924cbcba21d2804d69314a88e5a4c" 9 | sha512 = "49184a1b0945a889abd52d25271172ed3dc2db6968fcdddb1bab7ee0081f4a3eeee0977ad2291126a37631c0d86eeea75d822fa8af224c422134500bf9f0f2bb" 10 | 11 | [rpc] 12 | sha256 = "61f1545986917171d3e3dab7edf4286ca1769e73599ba83e1c3667de5ad955e8" 13 | sha512 = "64a16b8fbda6f9335cfd726eb80f9f77ae4551831c443dfad794cb76e2176135015fb1cbef8f50c5b90fd5fec6b2b6feeb8af74010f35c58ca922ad317e26ff7" 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello-rpc" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | use wrpc:rpc/error@0.1.0.{error}; 5 | 6 | hello: func() -> result; 7 | } 8 | 9 | world client { 10 | import handler; 11 | } 12 | 13 | world server { 14 | export handler; 15 | } 16 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/wit/deps/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | 4 | interface error { 5 | /// A resource which represents some error information. 6 | /// 7 | /// The only method provided by this resource is `to-debug-string`, 8 | /// which provides some human-readable information about the error. 9 | /// 10 | /// In the `wasi:io` package, this resource is returned through the 11 | /// `wasi:io/streams/stream-error` type. 12 | /// 13 | /// To provide more specific error information, other interfaces may 14 | /// provide functions to further "downcast" this error into more specific 15 | /// error information. For example, `error`s returned in streams derived 16 | /// from filesystem types to be described using the filesystem's own 17 | /// error-code type, using the function 18 | /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter 19 | /// `borrow` and returns 20 | /// `option`. 21 | /// 22 | /// The set of functions which can "downcast" an `error` into a more 23 | /// concrete type is open. 24 | resource error { 25 | /// Returns a string that is suitable to assist humans in debugging 26 | /// this error. 27 | /// 28 | /// WARNING: The returned string should not be consumed mechanically! 29 | /// It may change across platforms, hosts, or other implementation 30 | /// details. Parsing this string is a major platform-compatibility 31 | /// hazard. 32 | to-debug-string: func() -> string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/wit/deps/io/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | world imports { 4 | import streams; 5 | import poll; 6 | } 7 | -------------------------------------------------------------------------------- /examples/rust/hello-component-rpc-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-component-server; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-component-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-component-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [dependencies] 16 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 17 | -------------------------------------------------------------------------------- /examples/rust/hello-component-server/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod bindings { 2 | use crate::Handler; 3 | 4 | wit_bindgen::generate!({ 5 | with: { 6 | "wrpc-examples:hello/handler": generate, 7 | } 8 | }); 9 | export!(Handler); 10 | } 11 | 12 | struct Handler; 13 | 14 | impl bindings::exports::wrpc_examples::hello::handler::Guest for Handler { 15 | fn hello() -> String { 16 | "hello from Rust".to_string() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/rust/hello-component-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-component-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-component-server/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-component-server; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-component-tcp-proxy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-component-tcp-proxy" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [dependencies] 16 | anyhow = { workspace = true } 17 | clap = { workspace = true, features = [ 18 | "color", 19 | "derive", 20 | "error-context", 21 | "help", 22 | "std", 23 | "suggestions", 24 | "usage", 25 | ] } 26 | tokio = { workspace = true, features = ["rt"] } 27 | tracing = { workspace = true } 28 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 29 | wasi = { workspace = true } 30 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 31 | wit-bindgen-wrpc = { workspace = true } 32 | wrpc-transport = { workspace = true } 33 | -------------------------------------------------------------------------------- /examples/rust/hello-component-tcp-proxy/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-component-tcp-proxy/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-component-tcp-proxy/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-component-tcp-proxy/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-component-tcp-proxy; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | 7 | world client { 8 | include wrpc-examples:hello/client; 9 | } 10 | -------------------------------------------------------------------------------- /examples/rust/hello-http-tcp-proxy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-http-tcp-proxy" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | categories.workspace = true 6 | edition.workspace = true 7 | homepage.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = [ 14 | "color", 15 | "derive", 16 | "error-context", 17 | "help", 18 | "std", 19 | "suggestions", 20 | "usage", 21 | ] } 22 | http = { workspace = true } 23 | hyper = { workspace = true } 24 | hyper-util = { workspace = true, features = ["http1", "http2", "server", "tokio"] } 25 | tokio = { workspace = true, features = ["rt-multi-thread"] } 26 | tracing = { workspace = true } 27 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 28 | wit-bindgen-wrpc = { workspace = true } 29 | wrpc-transport = { workspace = true, features = ["net"] } 30 | -------------------------------------------------------------------------------- /examples/rust/hello-http-tcp-proxy/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-http-tcp-proxy/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-http-tcp-proxy/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-http-tcp-proxy/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-client; 2 | 3 | world client { 4 | include wrpc-examples:hello/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-nats-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | async-nats = { workspace = true } 14 | clap = { workspace = true, features = [ 15 | "color", 16 | "derive", 17 | "error-context", 18 | "help", 19 | "std", 20 | "suggestions", 21 | "usage", 22 | ] } 23 | tokio = { workspace = true, features = ["rt-multi-thread"] } 24 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 25 | url = { workspace = true } 26 | wit-bindgen-wrpc = { workspace = true } 27 | wrpc-transport-nats = { workspace = true, features = ["async-nats-0_41"] } 28 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-client/src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context as _; 2 | use clap::Parser; 3 | use url::Url; 4 | 5 | mod bindings { 6 | wit_bindgen_wrpc::generate!({ 7 | with: { 8 | "wrpc-examples:hello/handler": generate 9 | } 10 | }); 11 | } 12 | 13 | #[derive(Parser, Debug)] 14 | #[command(author, version, about, long_about = None)] 15 | struct Args { 16 | /// NATS.io URL to connect to 17 | #[arg(short, long, default_value = "nats://127.0.0.1:4222")] 18 | nats: Url, 19 | 20 | /// Prefixes to invoke `wrpc-examples:hello/handler.hello` on 21 | #[arg(default_value = "rust")] 22 | prefixes: Vec, 23 | } 24 | 25 | #[tokio::main] 26 | async fn main() -> anyhow::Result<()> { 27 | tracing_subscriber::fmt().init(); 28 | 29 | let Args { nats, prefixes } = Args::parse(); 30 | 31 | let nats = async_nats::connect_with_options( 32 | String::from(nats), 33 | async_nats::ConnectOptions::new().retry_on_initial_connect(), 34 | ) 35 | .await 36 | .context("failed to connect to NATS.io server")?; 37 | 38 | for prefix in prefixes { 39 | let wrpc = wrpc_transport_nats::Client::new(nats.clone(), prefix.clone(), None) 40 | .await 41 | .context("failed to construct transport client")?; 42 | let hello = bindings::wrpc_examples::hello::handler::hello(&wrpc, None) 43 | .await 44 | .context("failed to invoke `wrpc-examples.hello/handler.hello`")?; 45 | eprintln!("{prefix}: {hello}"); 46 | } 47 | Ok(()) 48 | } 49 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-client/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-client; 2 | 3 | world client { 4 | include wrpc-examples:hello/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-nats-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | async-nats = { workspace = true } 14 | clap = { workspace = true, features = [ 15 | "color", 16 | "derive", 17 | "error-context", 18 | "help", 19 | "std", 20 | "suggestions", 21 | "usage", 22 | ] } 23 | futures = { workspace = true } 24 | tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } 25 | tracing = { workspace = true } 26 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 27 | url = { workspace = true } 28 | wit-bindgen-wrpc = { workspace = true } 29 | wrpc-transport-nats = { workspace = true, features = ["async-nats-0_41"] } 30 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-server/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-nats-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-server; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-tcp-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = [ 14 | "color", 15 | "derive", 16 | "error-context", 17 | "help", 18 | "std", 19 | "suggestions", 20 | "usage", 21 | ] } 22 | tokio = { workspace = true, features = ["rt-multi-thread"] } 23 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 24 | wit-bindgen-wrpc = { workspace = true } 25 | wrpc-transport = { workspace = true, features = ["net"] } 26 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-client/src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context as _; 2 | use clap::Parser; 3 | 4 | mod bindings { 5 | wit_bindgen_wrpc::generate!({ 6 | with: { 7 | "wrpc-examples:hello/handler": generate 8 | } 9 | }); 10 | } 11 | 12 | #[derive(Parser, Debug)] 13 | #[command(author, version, about, long_about = None)] 14 | struct Args { 15 | /// Address to invoke `wrpc-examples:hello/handler.hello` on 16 | #[arg(default_value = "[::1]:7761")] 17 | addr: String, 18 | } 19 | 20 | #[tokio::main] 21 | async fn main() -> anyhow::Result<()> { 22 | tracing_subscriber::fmt().init(); 23 | 24 | let Args { addr } = Args::parse(); 25 | let wrpc = wrpc_transport::tcp::Client::from(&addr); 26 | let hello = bindings::wrpc_examples::hello::handler::hello(&wrpc, ()) 27 | .await 28 | .context("failed to invoke `wrpc-examples.hello/handler.hello`")?; 29 | eprintln!("{hello}"); 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-client/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-client; 2 | 3 | world client { 4 | include wrpc-examples:hello/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-tcp-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = [ 14 | "color", 15 | "derive", 16 | "error-context", 17 | "help", 18 | "std", 19 | "suggestions", 20 | "usage", 21 | ] } 22 | futures = { workspace = true } 23 | tokio = { workspace = true, features = ["rt-multi-thread", "signal", "net"] } 24 | tracing = { workspace = true } 25 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 26 | wit-bindgen-wrpc = { workspace = true } 27 | wrpc-transport = { workspace = true, features = ["net"] } 28 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-server/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-tcp-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-server; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-web-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-web-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = [ 14 | "color", 15 | "derive", 16 | "error-context", 17 | "help", 18 | "std", 19 | "suggestions", 20 | "usage", 21 | ] } 22 | rustls = { workspace = true } 23 | tokio = { workspace = true, features = ["rt-multi-thread"] } 24 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 25 | url = { workspace = true } 26 | wit-bindgen-wrpc = { workspace = true } 27 | wrpc-transport = { workspace = true, features = ["net"] } 28 | wrpc-transport-web = { workspace = true } 29 | wtransport = { workspace = true } 30 | -------------------------------------------------------------------------------- /examples/rust/hello-web-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-web-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-web-client/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-web-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-client; 2 | 3 | world client { 4 | include wrpc-examples:hello/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/hello-web-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-web-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = [ 14 | "color", 15 | "derive", 16 | "error-context", 17 | "help", 18 | "std", 19 | "suggestions", 20 | "usage", 21 | ] } 22 | futures = { workspace = true } 23 | rcgen = { workspace = true, features = ["crypto", "ring", "zeroize"] } 24 | rustls = { workspace = true } 25 | tokio = { workspace = true, features = ["rt-multi-thread", "signal", "net"] } 26 | tracing = { workspace = true } 27 | tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } 28 | wit-bindgen-wrpc = { workspace = true } 29 | wrpc-transport = { workspace = true } 30 | wrpc-transport-web = { workspace = true } 31 | wtransport = { workspace = true } 32 | -------------------------------------------------------------------------------- /examples/rust/hello-web-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [hello] 2 | path = "../../../wit/hello" 3 | sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" 4 | sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" 5 | -------------------------------------------------------------------------------- /examples/rust/hello-web-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | hello = "../../../wit/hello" 2 | -------------------------------------------------------------------------------- /examples/rust/hello-web-server/wit/deps/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/rust/hello-web-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello-rust-server; 2 | 3 | world server { 4 | include wrpc-examples:hello/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/resources-component-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "resources-component-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 14 | -------------------------------------------------------------------------------- /examples/rust/resources-component-client/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::bindings::wrpc_examples::resources::resources; 2 | 3 | mod bindings { 4 | wit_bindgen::generate!({ 5 | with: { 6 | "wrpc-examples:resources/resources": generate 7 | } 8 | }); 9 | } 10 | 11 | fn main() { 12 | let resource = resources::Foo::new(); 13 | println!("resources.bar: {}", resources::bar(&resource)); 14 | println!("foo.bar: {}", resource.bar()); 15 | println!("foo.foo: {}", resources::Foo::foo(resource)); 16 | } 17 | -------------------------------------------------------------------------------- /examples/rust/resources-component-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [resources] 2 | path = "../../../wit/resources" 3 | sha256 = "d47aff89928fe5bb30ddc79a4bae79a5af6fa075e8694953567544fefa507048" 4 | sha512 = "2de2d6fccb3bde7f9c163890993b53191cc399fb16e28742dbd25f449fc1d8a2e0766a101d0cf4c252be07e2aa3c892daba876b009a0bd33e3c5dd5f74f790da" 5 | -------------------------------------------------------------------------------- /examples/rust/resources-component-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | resources = "../../../wit/resources" 2 | -------------------------------------------------------------------------------- /examples/rust/resources-component-client/wit/deps/resources/resources.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources; 2 | 3 | interface resources { 4 | resource foo { 5 | constructor(); 6 | foo: static func(v: foo) -> string; 7 | bar: func() -> string; 8 | } 9 | 10 | bar: func(v: borrow) -> string; 11 | } 12 | 13 | world client { 14 | import resources; 15 | } 16 | 17 | world server { 18 | export resources; 19 | } 20 | -------------------------------------------------------------------------------- /examples/rust/resources-component-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources-component-client; 2 | 3 | world client { 4 | include wrpc-examples:resources/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/resources-component-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "resources-component-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [dependencies] 16 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 17 | -------------------------------------------------------------------------------- /examples/rust/resources-component-server/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod bindings { 2 | use crate::Handler; 3 | 4 | wit_bindgen::generate!({ 5 | with: { 6 | "wrpc-examples:resources/resources": generate 7 | } 8 | }); 9 | 10 | export!(Handler); 11 | } 12 | 13 | use bindings::exports::wrpc_examples::resources::resources::{FooBorrow, GuestFoo}; 14 | 15 | pub struct Handler; 16 | 17 | pub struct Foo; 18 | 19 | impl bindings::exports::wrpc_examples::resources::resources::GuestFoo for Foo { 20 | fn new() -> Self { 21 | Self 22 | } 23 | 24 | fn foo(_: bindings::exports::wrpc_examples::resources::resources::Foo) -> String { 25 | "foo".to_string() 26 | } 27 | 28 | fn bar(&self) -> String { 29 | "bar".to_string() 30 | } 31 | } 32 | 33 | impl bindings::exports::wrpc_examples::resources::resources::Guest for Handler { 34 | type Foo = Foo; 35 | 36 | fn bar(v: FooBorrow<'_>) -> String { 37 | let v: &Foo = v.get(); 38 | v.bar() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/rust/resources-component-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [resources] 2 | path = "../../../wit/resources" 3 | sha256 = "d47aff89928fe5bb30ddc79a4bae79a5af6fa075e8694953567544fefa507048" 4 | sha512 = "2de2d6fccb3bde7f9c163890993b53191cc399fb16e28742dbd25f449fc1d8a2e0766a101d0cf4c252be07e2aa3c892daba876b009a0bd33e3c5dd5f74f790da" 5 | -------------------------------------------------------------------------------- /examples/rust/resources-component-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | resources = "../../../wit/resources" 2 | -------------------------------------------------------------------------------- /examples/rust/resources-component-server/wit/deps/resources/resources.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources; 2 | 3 | interface resources { 4 | resource foo { 5 | constructor(); 6 | foo: static func(v: foo) -> string; 7 | bar: func() -> string; 8 | } 9 | 10 | bar: func(v: borrow) -> string; 11 | } 12 | 13 | world client { 14 | import resources; 15 | } 16 | 17 | world server { 18 | export resources; 19 | } 20 | -------------------------------------------------------------------------------- /examples/rust/resources-component-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources-component-server; 2 | 3 | world server { 4 | include wrpc-examples:resources/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "streams-nats-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | async-nats = { workspace = true } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | futures = { workspace = true } 25 | tokio = { workspace = true, features = ["rt-multi-thread"] } 26 | tokio-stream = { workspace = true, features = ["time"] } 27 | tracing = { workspace = true } 28 | tracing-subscriber = { workspace = true, features = [ 29 | "ansi", 30 | "env-filter", 31 | "fmt", 32 | ] } 33 | url = { workspace = true } 34 | wit-bindgen-wrpc = { workspace = true } 35 | wrpc-transport-nats = { workspace = true, features = ["async-nats-0_41"] } 36 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [streams] 2 | path = "../../../wit/streams" 3 | sha256 = "5064bee90ebea73f1695987191fbbfea71ed2dbb69839814009490b4fbe8e96f" 4 | sha512 = "dfca3844d91c6c8e83fefd7b9511a366b464cf69d017c61b671409cb26dc9490a0e59a8e60ef15b77fdeb4fc1b8d9e6efa11c2fb1a1dabd0141e5e6afe8a59b9" 5 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | streams = "../../../wit/streams" 2 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-client/wit/deps/streams/streams.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams; 2 | 3 | interface handler { 4 | record req { 5 | numbers: stream, 6 | bytes: stream, 7 | } 8 | echo: func(r: req) -> (numbers: stream, bytes: stream); 9 | } 10 | 11 | world client { 12 | import handler; 13 | } 14 | 15 | world server { 16 | export handler; 17 | } 18 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams-rust-client; 2 | 3 | world client { 4 | include wrpc-examples:streams/client; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "streams-nats-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | async-nats = { workspace = true } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | futures = { workspace = true } 25 | tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } 26 | tracing = { workspace = true } 27 | tracing-subscriber = { workspace = true, features = [ 28 | "ansi", 29 | "env-filter", 30 | "fmt", 31 | ] } 32 | url = { workspace = true } 33 | wit-bindgen-wrpc = { workspace = true } 34 | wrpc-transport-nats = { workspace = true, features = ["async-nats-0_41"] } 35 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [streams] 2 | path = "../../../wit/streams" 3 | sha256 = "5064bee90ebea73f1695987191fbbfea71ed2dbb69839814009490b4fbe8e96f" 4 | sha512 = "dfca3844d91c6c8e83fefd7b9511a366b464cf69d017c61b671409cb26dc9490a0e59a8e60ef15b77fdeb4fc1b8d9e6efa11c2fb1a1dabd0141e5e6afe8a59b9" 5 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | streams = "../../../wit/streams" 2 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-server/wit/deps/streams/streams.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams; 2 | 3 | interface handler { 4 | record req { 5 | numbers: stream, 6 | bytes: stream, 7 | } 8 | echo: func(r: req) -> (numbers: stream, bytes: stream); 9 | } 10 | 11 | world client { 12 | import handler; 13 | } 14 | 15 | world server { 16 | export handler; 17 | } 18 | -------------------------------------------------------------------------------- /examples/rust/streams-nats-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams-rust-server; 2 | 3 | world server { 4 | include wrpc-examples:streams/server; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-component-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 15 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/src/main.rs: -------------------------------------------------------------------------------- 1 | mod bindings { 2 | wit_bindgen::generate!({ 3 | with: { 4 | "wasi:keyvalue/store@0.2.0-draft2": generate 5 | } 6 | }); 7 | } 8 | 9 | use anyhow::{ensure, Context as _}; 10 | 11 | use bindings::wasi::keyvalue::store; 12 | 13 | fn main() -> anyhow::Result<()> { 14 | let bucket = store::open("example").context("failed to open empty bucket")?; 15 | bucket.set("foo", b"bar").context("failed to set `foo`")?; 16 | let ok = bucket 17 | .exists("foo") 18 | .context("failed to check if `foo` exists")?; 19 | ensure!(ok); 20 | let v = bucket.get("foo").context("failed to get `foo`")?; 21 | ensure!(v.as_deref() == Some(b"bar".as_slice())); 22 | 23 | let store::KeyResponse { keys, cursor: _ } = 24 | bucket.list_keys(None).context("failed to list keys")?; 25 | for key in keys { 26 | println!("key: {key}"); 27 | } 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [keyvalue] 2 | path = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 3 | sha256 = "7eaf2e10af6e2de6d5a168893e2656c6685de2009bd37fdc944859f5a6753e55" 4 | sha512 = "ecf0dd2e0b6e5f62c2e10673cc8c2aab86c532f8b19c984fe2ecd9306e9a5c2783183143274477cc4fb3b037b2db2817f248a6bf84b3279180ca4dba832bf5dc" 5 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/wit/deps.toml: -------------------------------------------------------------------------------- 1 | keyvalue = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 2 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/wit/deps/keyvalue/watch.wit: -------------------------------------------------------------------------------- 1 | /// A keyvalue interface that provides watch operations. 2 | /// 3 | /// This interface is used to provide event-driven mechanisms to handle 4 | /// keyvalue changes. 5 | interface watcher { 6 | /// A keyvalue interface that provides handle-watch operations. 7 | use store.{bucket}; 8 | 9 | /// Handle the `set` event for the given bucket and key. It includes a reference to the `bucket` 10 | /// that can be used to interact with the store. 11 | on-set: func(bucket: bucket, key: string, value: list); 12 | 13 | /// Handle the `delete` event for the given bucket and key. It includes a reference to the 14 | /// `bucket` that can be used to interact with the store. 15 | on-delete: func(bucket: bucket, key: string); 16 | } -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/wit/deps/keyvalue/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:keyvalue@0.2.0-draft2; 2 | 3 | /// The `wasi:keyvalue/imports` world provides common APIs for interacting with key-value stores. 4 | /// Components targeting this world will be able to do: 5 | /// 6 | /// 1. CRUD (create, read, update, delete) operations on key-value stores. 7 | /// 2. Atomic `increment` and CAS (compare-and-swap) operations. 8 | /// 3. Batch operations that can reduce the number of round trips to the network. 9 | world imports { 10 | /// The `store` capability allows the component to perform eventually consistent operations on 11 | /// the key-value store. 12 | import store; 13 | 14 | /// The `atomic` capability allows the component to perform atomic / `increment` and CAS 15 | /// (compare-and-swap) operations. 16 | import atomics; 17 | 18 | /// The `batch` capability allows the component to perform eventually consistent batch 19 | /// operations that can reduce the number of round trips to the network. 20 | import batch; 21 | } 22 | 23 | world watch-service { 24 | include imports; 25 | export watcher; 26 | } -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-client/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:wasi-keyvalue-component-client; 2 | 3 | world client { 4 | import wasi:keyvalue/store@0.2.0-draft2; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-component-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [dependencies] 16 | wit-bindgen = { workspace = true, features = ["realloc", "macros"] } 17 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-server/wit/deps.lock: -------------------------------------------------------------------------------- 1 | [keyvalue] 2 | path = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 3 | sha256 = "7eaf2e10af6e2de6d5a168893e2656c6685de2009bd37fdc944859f5a6753e55" 4 | sha512 = "ecf0dd2e0b6e5f62c2e10673cc8c2aab86c532f8b19c984fe2ecd9306e9a5c2783183143274477cc4fb3b037b2db2817f248a6bf84b3279180ca4dba832bf5dc" 5 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-server/wit/deps.toml: -------------------------------------------------------------------------------- 1 | keyvalue = "../../../../crates/wasi-keyvalue/wit/deps/keyvalue" 2 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-server/wit/deps/keyvalue/watch.wit: -------------------------------------------------------------------------------- 1 | /// A keyvalue interface that provides watch operations. 2 | /// 3 | /// This interface is used to provide event-driven mechanisms to handle 4 | /// keyvalue changes. 5 | interface watcher { 6 | /// A keyvalue interface that provides handle-watch operations. 7 | use store.{bucket}; 8 | 9 | /// Handle the `set` event for the given bucket and key. It includes a reference to the `bucket` 10 | /// that can be used to interact with the store. 11 | on-set: func(bucket: bucket, key: string, value: list); 12 | 13 | /// Handle the `delete` event for the given bucket and key. It includes a reference to the 14 | /// `bucket` that can be used to interact with the store. 15 | on-delete: func(bucket: bucket, key: string); 16 | } -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-server/wit/deps/keyvalue/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:keyvalue@0.2.0-draft2; 2 | 3 | /// The `wasi:keyvalue/imports` world provides common APIs for interacting with key-value stores. 4 | /// Components targeting this world will be able to do: 5 | /// 6 | /// 1. CRUD (create, read, update, delete) operations on key-value stores. 7 | /// 2. Atomic `increment` and CAS (compare-and-swap) operations. 8 | /// 3. Batch operations that can reduce the number of round trips to the network. 9 | world imports { 10 | /// The `store` capability allows the component to perform eventually consistent operations on 11 | /// the key-value store. 12 | import store; 13 | 14 | /// The `atomic` capability allows the component to perform atomic / `increment` and CAS 15 | /// (compare-and-swap) operations. 16 | import atomics; 17 | 18 | /// The `batch` capability allows the component to perform eventually consistent batch 19 | /// operations that can reduce the number of round trips to the network. 20 | import batch; 21 | } 22 | 23 | world watch-service { 24 | include imports; 25 | export watcher; 26 | } -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-component-server/wit/world.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:wasi-keyvalue-component-server; 2 | 3 | world server { 4 | export wasi:keyvalue/store@0.2.0-draft2; 5 | } 6 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-nats-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-nats-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | async-nats = { workspace = true } 15 | bytes = { workspace = true } 16 | clap = { workspace = true, features = [ 17 | "color", 18 | "derive", 19 | "error-context", 20 | "help", 21 | "std", 22 | "suggestions", 23 | "usage", 24 | ] } 25 | tokio = { workspace = true, features = ["rt-multi-thread"] } 26 | tracing-subscriber = { workspace = true, features = [ 27 | "ansi", 28 | "env-filter", 29 | "fmt", 30 | ] } 31 | url = { workspace = true } 32 | wrpc-transport-nats = { workspace = true, features = ["async-nats-0_41"] } 33 | wrpc-wasi-keyvalue = { workspace = true } 34 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-nats-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-nats-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | async-nats = { workspace = true } 15 | bytes = { workspace = true } 16 | clap = { workspace = true, features = [ 17 | "color", 18 | "derive", 19 | "error-context", 20 | "help", 21 | "std", 22 | "suggestions", 23 | "usage", 24 | ] } 25 | futures = { workspace = true } 26 | tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } 27 | tracing = { workspace = true } 28 | tracing-subscriber = { workspace = true, features = [ 29 | "ansi", 30 | "env-filter", 31 | "fmt", 32 | ] } 33 | url = { workspace = true } 34 | wrpc-transport = { workspace = true } 35 | wrpc-transport-nats = { workspace = true, features = ["async-nats-0_41"] } 36 | wrpc-wasi-keyvalue = { workspace = true } 37 | wrpc-wasi-keyvalue-mem = { workspace = true } 38 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-quic-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-quic-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | futures = { workspace = true } 25 | quinn = { workspace = true, features = [ 26 | "log", 27 | "platform-verifier", 28 | "ring", 29 | "runtime-tokio", 30 | "rustls", 31 | ] } 32 | rcgen = { workspace = true, features = ["crypto", "ring", "zeroize"] } 33 | rustls = { workspace = true } 34 | tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } 35 | tracing = { workspace = true } 36 | tracing-subscriber = { workspace = true, features = [ 37 | "ansi", 38 | "env-filter", 39 | "fmt", 40 | ] } 41 | wrpc-transport = { workspace = true } 42 | wrpc-transport-quic = { workspace = true } 43 | wrpc-wasi-keyvalue = { workspace = true } 44 | wrpc-wasi-keyvalue-mem = { workspace = true } 45 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-tcp-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-tcp-client" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | tokio = { workspace = true, features = ["rt-multi-thread"] } 25 | tracing-subscriber = { workspace = true, features = [ 26 | "ansi", 27 | "env-filter", 28 | "fmt", 29 | ] } 30 | url = { workspace = true } 31 | wrpc-transport = { workspace = true, features = ["net"] } 32 | wrpc-wasi-keyvalue = { workspace = true } 33 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-tcp-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-tcp-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | futures = { workspace = true } 25 | tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } 26 | tracing = { workspace = true } 27 | tracing-subscriber = { workspace = true, features = [ 28 | "ansi", 29 | "env-filter", 30 | "fmt", 31 | ] } 32 | wrpc-transport = { workspace = true, features = ["net"] } 33 | wrpc-wasi-keyvalue = { workspace = true } 34 | wrpc-wasi-keyvalue-mem = { workspace = true } 35 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-unix-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-unix-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | futures = { workspace = true } 25 | tokio = { workspace = true, features = [ 26 | "fs", 27 | "rt-multi-thread", 28 | "net", 29 | "signal", 30 | ] } 31 | tracing = { workspace = true } 32 | tracing-subscriber = { workspace = true, features = [ 33 | "ansi", 34 | "env-filter", 35 | "fmt", 36 | ] } 37 | wrpc-transport = { workspace = true, features = ["net"] } 38 | wrpc-wasi-keyvalue = { workspace = true } 39 | wrpc-wasi-keyvalue-mem = { workspace = true } 40 | -------------------------------------------------------------------------------- /examples/rust/wasi-keyvalue-web-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-keyvalue-web-server" 3 | version = "0.1.0" 4 | 5 | authors.workspace = true 6 | categories.workspace = true 7 | edition.workspace = true 8 | homepage.workspace = true 9 | license.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | anyhow = { workspace = true, features = ["std"] } 14 | bytes = { workspace = true } 15 | clap = { workspace = true, features = [ 16 | "color", 17 | "derive", 18 | "error-context", 19 | "help", 20 | "std", 21 | "suggestions", 22 | "usage", 23 | ] } 24 | futures = { workspace = true } 25 | tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } 26 | tracing = { workspace = true } 27 | tracing-subscriber = { workspace = true, features = [ 28 | "ansi", 29 | "env-filter", 30 | "fmt", 31 | ] } 32 | wrpc-transport = { workspace = true } 33 | wrpc-transport-web = { workspace = true } 34 | wrpc-wasi-keyvalue = { workspace = true } 35 | wrpc-wasi-keyvalue-mem = { workspace = true } 36 | wtransport = { workspace = true, features = ["self-signed"] } 37 | -------------------------------------------------------------------------------- /examples/web/README.md: -------------------------------------------------------------------------------- 1 | # `wasi-keyvalue` in the Web 2 | 3 | This example shows a Web app using `wasi:keyvalue` implementation provided by the server via WebTransport using wRPC. 4 | 5 | The server acts as both a direct implementor of `wasi:keyvalue` and a "proxy", which can delegate `wasi:keyvalue` calls issued by the Web client to other `wasi:keyvalue` implementations via various transports supported by wRPC. 6 | 7 | ## Runing 8 | 9 | With `cargo`: 10 | 11 | ``` 12 | cargo run -p wasi-keyvalue-web 13 | ``` 14 | 15 | ## `wasi-keyvalue` plugins 16 | 17 | To invoke other wRPC `wasi:keyvalue` plugins in "proxy" mode, for example TCP, try: 18 | 19 | ``` 20 | cargo run -p wasi-keyvalue-tcp-server 21 | ``` 22 | 23 | And select `wRPC/TCP` as the protocol in the UI 24 | -------------------------------------------------------------------------------- /examples/wit/hello-rpc/deps/io: -------------------------------------------------------------------------------- 1 | ../../../../crates/runtime-wasmtime/wit/deps/io -------------------------------------------------------------------------------- /examples/wit/hello-rpc/deps/rpc: -------------------------------------------------------------------------------- 1 | ../../../../crates/runtime-wasmtime/wit/deps/rpc -------------------------------------------------------------------------------- /examples/wit/hello-rpc/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | use wrpc:rpc/error@0.1.0.{error}; 5 | 6 | hello: func() -> result; 7 | } 8 | 9 | world client { 10 | import handler; 11 | } 12 | 13 | world server { 14 | export handler; 15 | } 16 | -------------------------------------------------------------------------------- /examples/wit/hello/hello.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:hello; 2 | 3 | interface handler { 4 | hello: func() -> string; 5 | } 6 | 7 | world client { 8 | import handler; 9 | } 10 | 11 | world server { 12 | export handler; 13 | } 14 | -------------------------------------------------------------------------------- /examples/wit/resources/resources.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:resources; 2 | 3 | interface resources { 4 | resource foo { 5 | constructor(); 6 | foo: static func(v: foo) -> string; 7 | bar: func() -> string; 8 | } 9 | 10 | bar: func(v: borrow) -> string; 11 | } 12 | 13 | world client { 14 | import resources; 15 | } 16 | 17 | world server { 18 | export resources; 19 | } 20 | -------------------------------------------------------------------------------- /examples/wit/streams/streams.wit: -------------------------------------------------------------------------------- 1 | package wrpc-examples:streams; 2 | 3 | interface handler { 4 | record req { 5 | numbers: stream, 6 | bytes: stream, 7 | } 8 | echo: func(r: req) -> (numbers: stream, bytes: stream); 9 | } 10 | 11 | world client { 12 | import handler; 13 | } 14 | 15 | world server { 16 | export handler; 17 | } 18 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.24 2 | 3 | use ( 4 | ./examples/go/hello-client 5 | ./examples/go/hello-server 6 | ./examples/go/resources-server 7 | ./examples/go/streams-client 8 | ./examples/go/streams-server 9 | ./examples/go/wasi-keyvalue-client 10 | ./examples/go/wasi-keyvalue-server 11 | ./go 12 | ./tests/go 13 | ) 14 | 15 | replace wrpc.io/go v0.2.0 => ./go 16 | -------------------------------------------------------------------------------- /go/future.go: -------------------------------------------------------------------------------- 1 | package wrpc 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | ) 7 | 8 | // ReadFutureStatus reads a single byte from `r` and returns: 9 | // - `true` if future is "ready" 10 | // - `false` if future is "pending" 11 | func ReadFutureStatus(r ByteReader) (bool, error) { 12 | status, err := r.ReadByte() 13 | if err != nil { 14 | return false, fmt.Errorf("failed to read `future` status byte: %w", err) 15 | } 16 | switch status { 17 | case 0: 18 | return false, nil 19 | case 1: 20 | return true, nil 21 | default: 22 | return false, fmt.Errorf("invalid `future` status byte %d", status) 23 | } 24 | } 25 | 26 | // ReadFuture reads a future from `r` 27 | func ReadFuture[T any](r IndexReadCloser, f func(IndexReadCloser) (T, error), path ...uint32) (Receiver[T], error) { 28 | slog.Debug("reading future status byte") 29 | ok, err := ReadFutureStatus(r) 30 | if err != nil { 31 | return nil, err 32 | } 33 | if !ok { 34 | slog.Debug("indexing pending future reader") 35 | r, err := r.Index(append(path, 0)...) 36 | if err != nil { 37 | return nil, fmt.Errorf("failed to get future reader: %w", err) 38 | } 39 | return NewDecodeReceiver(r, f), nil 40 | } 41 | slog.Debug("reading ready future") 42 | v, err := f(r) 43 | if err != nil { 44 | return nil, err 45 | } 46 | return NewCompleteReceiver(v), nil 47 | } 48 | -------------------------------------------------------------------------------- /go/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/go 2 | 3 | go 1.24 4 | 5 | require github.com/nats-io/nats.go v1.42.0 6 | 7 | require ( 8 | github.com/klauspost/compress v1.18.0 // indirect 9 | github.com/nats-io/nkeys v0.4.11 // indirect 10 | github.com/nats-io/nuid v1.0.1 // indirect 11 | golang.org/x/crypto v0.37.0 // indirect 12 | golang.org/x/sys v0.32.0 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 2 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 3 | github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= 4 | github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= 5 | github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= 6 | github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= 7 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 8 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 9 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 10 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 11 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 12 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 13 | -------------------------------------------------------------------------------- /go/x/tcp/conn.go: -------------------------------------------------------------------------------- 1 | package wrpctcp 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | ) 7 | 8 | type writeConn struct { 9 | *net.TCPConn 10 | } 11 | 12 | func (c writeConn) Close() error { 13 | err := c.CloseWrite() 14 | if err == nil || errors.Is(err, net.ErrClosed) { 15 | return nil 16 | } 17 | return err 18 | } 19 | 20 | type readConn struct { 21 | *net.TCPConn 22 | } 23 | 24 | func (c readConn) Close() error { 25 | err := c.CloseRead() 26 | if err == nil || errors.Is(err, net.ErrClosed) { 27 | return nil 28 | } 29 | return err 30 | } 31 | -------------------------------------------------------------------------------- /go/x/tcp/invoker.go: -------------------------------------------------------------------------------- 1 | package wrpctcp 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | 8 | wrpc "wrpc.io/go" 9 | ) 10 | 11 | // Invoker is a thin wrapper around *net.TCPAddr, which is able to invoke wRPC functions 12 | type Invoker struct { 13 | addr string 14 | } 15 | 16 | func NewInvoker(addr string) *Invoker { 17 | return &Invoker{addr: addr} 18 | } 19 | 20 | func (c *Invoker) Invoke(ctx context.Context, instance string, name string, buf []byte, paths ...wrpc.SubscribePath) (wrpc.IndexWriteCloser, wrpc.IndexReadCloser, error) { 21 | addr, err := net.ResolveTCPAddr("tcp", c.addr) 22 | if err != nil { 23 | return nil, nil, fmt.Errorf("failed to resolve `%s` as TCP address: %w", c.addr, err) 24 | } 25 | conn, err := net.DialTCP("tcp", nil, addr) 26 | if err != nil { 27 | return nil, nil, fmt.Errorf("failed to establish TCP connection: %w", err) 28 | } 29 | return wrpc.InvokeFramed(ctx, writeConn{conn}, readConn{conn}, instance, name, buf, paths...) 30 | } 31 | -------------------------------------------------------------------------------- /go/x/tcp/server.go: -------------------------------------------------------------------------------- 1 | package wrpctcp 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | 8 | wrpc "wrpc.io/go" 9 | ) 10 | 11 | type Server struct { 12 | l *net.TCPListener 13 | srv *wrpc.FramedServer 14 | } 15 | 16 | func NewServerWithContext(ctx context.Context, l *net.TCPListener) *Server { 17 | return &Server{ 18 | l: l, 19 | srv: wrpc.NewFramedServer(ctx), 20 | } 21 | } 22 | 23 | func NewServer(l *net.TCPListener) *Server { 24 | return NewServerWithContext(context.Background(), l) 25 | } 26 | 27 | func (s *Server) Serve(instance string, name string, f wrpc.HandleFunc, paths ...wrpc.SubscribePath) (func() error, error) { 28 | return s.srv.Serve(instance, name, f, paths...) 29 | } 30 | 31 | func (s *Server) Accept() error { 32 | conn, err := s.l.AcceptTCP() 33 | if err != nil { 34 | return fmt.Errorf("failed to accept TCP connection: %w", err) 35 | } 36 | if err := s.srv.Accept(writeConn{conn}, readConn{conn}); err != nil { 37 | return fmt.Errorf("failed to accept invocation: %w", err) 38 | } 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | components = ["clippy", "rust-src", "rustfmt"] 4 | targets = [ 5 | "wasm32-wasip2" 6 | ] 7 | -------------------------------------------------------------------------------- /src/bin/wrpc-wasmtime.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> anyhow::Result<()> { 3 | wrpc_wasmtime_cli::run().await 4 | } 5 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! wRPC is an RPC framework based on WIT 2 | 3 | #![deny(missing_docs)] 4 | 5 | /// wRPC transport 6 | pub mod transport { 7 | pub use wrpc_transport::*; 8 | 9 | #[cfg(feature = "nats")] 10 | pub use wrpc_transport_nats as nats; 11 | 12 | #[cfg(feature = "quic")] 13 | pub use wrpc_transport_quic as quic; 14 | 15 | #[cfg(feature = "web-transport")] 16 | pub use wrpc_transport_web as web; 17 | } 18 | 19 | /// wRPC runtime 20 | pub mod runtime { 21 | #[cfg(feature = "wasmtime")] 22 | pub use wrpc_runtime_wasmtime as wasmtime; 23 | } 24 | 25 | pub use transport::{Index, Invoke, Serve}; 26 | -------------------------------------------------------------------------------- /tests/codegen/allow-unused.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | world bindings { 4 | export component; 5 | } 6 | 7 | interface component { 8 | variant unused-variant { 9 | %enum(unused-enum), 10 | %record(unused-record) 11 | } 12 | enum unused-enum { 13 | unused 14 | } 15 | record unused-record { 16 | x: u32 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/codegen/async-client.wit: -------------------------------------------------------------------------------- 1 | package test:async-client; 2 | 3 | interface async { 4 | record sync { 5 | foo: string, 6 | } 7 | 8 | variant var { 9 | a(stream>>), 10 | b(future), 11 | c(list), 12 | } 13 | 14 | record rec { 15 | a: stream, 16 | b: future, 17 | } 18 | 19 | with-streams: func(complete: bool) -> (bytes: stream, lists: stream>); 20 | with-future: func(s: stream) -> future>; 21 | with-nested: func(r: rec, f: future) -> rec; 22 | } 23 | 24 | world async-client { 25 | import async; 26 | } 27 | -------------------------------------------------------------------------------- /tests/codegen/async-server.wit: -------------------------------------------------------------------------------- 1 | package test:async-server; 2 | 3 | interface async { 4 | record sync { 5 | foo: string, 6 | } 7 | 8 | variant var { 9 | a(stream>>), 10 | b(future), 11 | c(list), 12 | } 13 | 14 | record rec { 15 | a: stream, 16 | b: future, 17 | } 18 | 19 | with-streams: func(complete: bool) -> (bytes: stream, lists: stream>); 20 | with-future: func(s: stream) -> future>; 21 | with-nested: func(r: rec, f: future) -> rec; 22 | } 23 | 24 | world async-server { 25 | export async; 26 | } 27 | -------------------------------------------------------------------------------- /tests/codegen/char.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface chars { 4 | /// A function that accepts a character 5 | take-char: func(x: char); 6 | /// A function that returns a character 7 | return-char: func() -> char; 8 | } 9 | 10 | world the-world { 11 | import chars; 12 | export chars; 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/conventions.wit: -------------------------------------------------------------------------------- 1 | // hello 🐱 world 2 | 3 | package foo:foo; 4 | 5 | interface conventions { 6 | kebab-case: func(); 7 | 8 | record ludicrous-speed { 9 | how-fast-are-you-going: u32, 10 | i-am-going-extremely-slow: u64, 11 | } 12 | 13 | foo: func(x: ludicrous-speed); 14 | %function-with-dashes: func(); 15 | %function-with-no-weird-characters: func(); 16 | 17 | apple: func(); 18 | apple-pear: func(); 19 | apple-pear-grape: func(); 20 | a0: func(); 21 | 22 | // Comment out identifiers that collide when mapped to snake_case, for now; see 23 | // https://github.com/WebAssembly/component-model/issues/118 24 | //APPLE: func() 25 | //APPLE-pear-GRAPE: func() 26 | //apple-PEAR-grape: func() 27 | 28 | is-XML: func(); 29 | 30 | %explicit: func(); 31 | %explicit-kebab: func(); 32 | 33 | // Identifiers with the same name as keywords are quoted. 34 | %bool: func(); 35 | } 36 | 37 | world the-world { 38 | import conventions; 39 | export conventions; 40 | } 41 | -------------------------------------------------------------------------------- /tests/codegen/empty.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world empty {} 4 | -------------------------------------------------------------------------------- /tests/codegen/enum-has-go-keyword.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface foo-bar { 4 | record foo{ 5 | something: string, 6 | anything: string 7 | } 8 | 9 | enum bar{ 10 | anything, 11 | %type 12 | } 13 | 14 | fetch: func(x: foo, e: bar) -> string; 15 | } 16 | 17 | world foo-world { 18 | import foo-bar; 19 | } -------------------------------------------------------------------------------- /tests/codegen/flags.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface %flags { 4 | flags flag1 { 5 | b0, 6 | } 7 | 8 | flags flag2 { 9 | b0, b1, 10 | } 11 | 12 | flags flag4 { 13 | b0, b1, b2, b3, 14 | } 15 | 16 | flags flag8 { 17 | b0, b1, b2, b3, b4, b5, b6, b7, 18 | } 19 | 20 | flags flag16 { 21 | b0, b1, b2, b3, b4, b5, b6, b7, 22 | b8, b9, b10, b11, b12, b13, b14, b15, 23 | } 24 | 25 | flags flag32 { 26 | b0, b1, b2, b3, b4, b5, b6, b7, 27 | b8, b9, b10, b11, b12, b13, b14, b15, 28 | b16, b17, b18, b19, b20, b21, b22, b23, 29 | b24, b25, b26, b27, b28, b29, b30, b31, 30 | } 31 | 32 | flags withdashes { 33 | with-dashes, 34 | } 35 | 36 | roundtrip-flag1: func(x: flag1) -> flag1; 37 | roundtrip-flag2: func(x: flag2) -> flag2; 38 | roundtrip-flag4: func(x: flag4) -> flag4; 39 | roundtrip-flag8: func(x: flag8) -> flag8; 40 | roundtrip-flag16: func(x: flag16) -> flag16; 41 | roundtrip-flag32: func(x: flag32) -> flag32; 42 | } 43 | 44 | world the-flags { 45 | import %flags; 46 | export %flags; 47 | } 48 | -------------------------------------------------------------------------------- /tests/codegen/floats.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface floats { 4 | f32-param: func(x: f32); 5 | f64-param: func(x: f64); 6 | f32-result: func() -> f32; 7 | f64-result: func() -> f64; 8 | } 9 | 10 | world the-world { 11 | import floats; 12 | export floats; 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/fully-qualified-java-address.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | interface my-import { 4 | record address { 5 | field: u32, 6 | attribute: bool, 7 | } 8 | } 9 | 10 | world bindings { 11 | import my-import; 12 | 13 | export init: func(baz: string); 14 | } 15 | -------------------------------------------------------------------------------- /tests/codegen/go_params.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world go-params { 4 | import error-code: func(err: u32) -> option; 5 | import error-code2: func(ret: u32) -> option; 6 | import error-code3: func(err: u32, ret: option) -> result; 7 | import error-code4: func() -> result; 8 | } 9 | -------------------------------------------------------------------------------- /tests/codegen/guest-name.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | interface guest { 4 | type guest = u32; 5 | x: func() -> guest; 6 | } 7 | 8 | interface other-guest { 9 | guest: func(); 10 | } 11 | 12 | world another-guest { 13 | import guest; 14 | export guest; 15 | import other-guest; 16 | export other-guest; 17 | 18 | export i1; 19 | export i2; 20 | export i3; 21 | export i4; 22 | } 23 | 24 | interface i1 { 25 | enum guest { 26 | a, b, c, 27 | } 28 | x: func() -> guest; 29 | } 30 | 31 | interface i2 { 32 | use i1.{guest}; 33 | x: func() -> guest; 34 | } 35 | 36 | interface i3 { 37 | record guest { 38 | x: u32, 39 | } 40 | x: func() -> guest; 41 | } 42 | 43 | interface i4 { 44 | variant guest { 45 | x(u32), 46 | } 47 | x: func() -> guest; 48 | } 49 | -------------------------------------------------------------------------------- /tests/codegen/import-and-export-resource-alias.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | 3 | interface foo { 4 | resource x { 5 | constructor(s: string); 6 | get: func() -> string; 7 | } 8 | 9 | type y = x; 10 | transmogriphy: func(y: y) -> x; 11 | } 12 | 13 | world resources { 14 | import foo; 15 | export foo; 16 | } 17 | -------------------------------------------------------------------------------- /tests/codegen/import-and-export-resource.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | 3 | interface baz { 4 | resource x { 5 | constructor(s: string); 6 | get: func() -> string; 7 | } 8 | } 9 | 10 | world resources { 11 | import baz; 12 | export baz; 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/import-func.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world foo { 4 | import foo: func(); 5 | import foo1: func() -> string; 6 | import foo2: func(x: string); 7 | import foo3: func(x: list) -> result, string>; 8 | } 9 | -------------------------------------------------------------------------------- /tests/codegen/integers.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface integers { 4 | a1: func(x: u8); 5 | a2: func(x: s8); 6 | a3: func(x: u16); 7 | a4: func(x: s16); 8 | a5: func(x: u32); 9 | a6: func(x: s32); 10 | a7: func(x: u64); 11 | a8: func(x: s64); 12 | 13 | a9: func( 14 | p1: u8, 15 | p2: s8, 16 | p3: u16, 17 | p4: s16, 18 | p5: u32, 19 | p6: s32, 20 | p7: u64, 21 | p8: s64, 22 | ); 23 | 24 | 25 | r1: func() -> u8; 26 | r2: func() -> s8; 27 | r3: func() -> u16; 28 | r4: func() -> s16; 29 | r5: func() -> u32; 30 | r6: func() -> s32; 31 | r7: func() -> u64; 32 | r8: func() -> s64; 33 | 34 | pair-ret: func() -> tuple; 35 | } 36 | 37 | world the-world { 38 | import integers; 39 | export integers; 40 | } 41 | -------------------------------------------------------------------------------- /tests/codegen/interface-has-go-keyword.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface %type { 4 | record foo{ 5 | something: string, 6 | anything: string 7 | } 8 | 9 | record bar{ 10 | anything: u16 11 | } 12 | 13 | fetch: func(x: foo) -> result; 14 | } 15 | 16 | world foo-world { 17 | import %type; 18 | } -------------------------------------------------------------------------------- /tests/codegen/issue544.wit: -------------------------------------------------------------------------------- 1 | // ./wit/issue.wit 2 | package foo:foo; 3 | 4 | world issue { 5 | variant variants { 6 | list-u8(list), 7 | list-tuple-bool(list>), 8 | } 9 | 10 | record record-tuple-u8 { 11 | field: tuple, 12 | } 13 | 14 | import func-using-list-u8-in-args: func(body: list) -> (); 15 | export func-using-list-tuple-bool-in-return: func() -> list>; 16 | export func-using-tuple-u8-in-return: func() -> tuple; 17 | } 18 | -------------------------------------------------------------------------------- /tests/codegen/issue551.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world bindings { 4 | import component; 5 | } 6 | 7 | interface component { 8 | type value = list>; 9 | type entity = list>; 10 | 11 | add-components: func(entity: u64, data: entity); 12 | query-eval: func(q: u64) -> list>>; 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/issue569/wit/deps/io/streams.wit: -------------------------------------------------------------------------------- 1 | package wasi:io; 2 | 3 | interface streams { 4 | use wasi:poll/poll.{pollable}; 5 | 6 | type input-stream = u32; 7 | 8 | read: func() -> list; 9 | } 10 | -------------------------------------------------------------------------------- /tests/codegen/issue569/wit/deps/poll/poll.wit: -------------------------------------------------------------------------------- 1 | package wasi:poll; 2 | 3 | interface poll { 4 | type pollable = u32; 5 | 6 | poll-oneoff: func() -> list; 7 | } 8 | -------------------------------------------------------------------------------- /tests/codegen/issue569/wit/issue569.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world command { 4 | use wasi:io/streams.{input-stream}; 5 | } 6 | -------------------------------------------------------------------------------- /tests/codegen/issue607.wit: -------------------------------------------------------------------------------- 1 | package local:demo; 2 | 3 | interface interface1 { 4 | variant error { 5 | some-error 6 | } 7 | record my-record { 8 | some-field: u32 9 | } 10 | my-func: func() -> result; 11 | my-optional: func() -> option; 12 | my-tuple: func() -> tuple; 13 | my-list: func() -> list; 14 | } 15 | 16 | interface interface2 { 17 | variant error { 18 | other-error 19 | } 20 | record my-record { 21 | other-field: u32 22 | } 23 | my-func: func() -> result; 24 | my-optional: func() -> option; 25 | my-tuple: func() -> tuple; 26 | my-list: func() -> list; 27 | } 28 | 29 | world my-world { 30 | import interface1; 31 | import interface2; 32 | } 33 | -------------------------------------------------------------------------------- /tests/codegen/issue668.wit: -------------------------------------------------------------------------------- 1 | package test:test; 2 | 3 | interface test-import { 4 | resource resource-a { 5 | constructor(id: u32); 6 | } 7 | 8 | record record-a { 9 | resource-a: resource-a, 10 | resources: list, 11 | } 12 | 13 | resource resource-b { 14 | make: static func(record-a: record-a); 15 | } 16 | } 17 | 18 | world test-world { 19 | import test-import; 20 | } 21 | -------------------------------------------------------------------------------- /tests/codegen/issue929-no-export.wit: -------------------------------------------------------------------------------- 1 | package foo:bar1; 2 | 3 | interface f { 4 | resource fd; 5 | } 6 | 7 | interface utils { 8 | use f.{fd}; 9 | my-func: func() -> own; 10 | } 11 | 12 | world test { 13 | export utils; 14 | } 15 | -------------------------------------------------------------------------------- /tests/codegen/issue929-no-import.wit: -------------------------------------------------------------------------------- 1 | package foo:bar2; 2 | 3 | interface f { 4 | resource fd; 5 | } 6 | 7 | interface utils { 8 | use f.{fd}; 9 | my-func: func() -> own; 10 | } 11 | 12 | world test { 13 | export f; 14 | export utils; 15 | } 16 | -------------------------------------------------------------------------------- /tests/codegen/issue929-only-methods.wit: -------------------------------------------------------------------------------- 1 | package foo:bar3; 2 | 3 | interface f { 4 | resource fd { 5 | get-a: func() -> s32; 6 | set-a: func(a: s32); 7 | } 8 | } 9 | 10 | interface utils { 11 | use f.{fd}; 12 | my-func: func() -> own; 13 | } 14 | 15 | world test { 16 | import f; 17 | export f; 18 | export utils; 19 | } 20 | -------------------------------------------------------------------------------- /tests/codegen/issue929.wit: -------------------------------------------------------------------------------- 1 | package foo:bar4; 2 | 3 | interface f { 4 | resource fd; 5 | } 6 | 7 | interface utils { 8 | use f.{fd}; 9 | my-func: func() -> own; 10 | } 11 | 12 | world test { 13 | import f; 14 | export f; 15 | export utils; 16 | } 17 | -------------------------------------------------------------------------------- /tests/codegen/just-export.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | world foo { 3 | export generate: func(name: string, wit: list) -> result>>, string>; 4 | } 5 | -------------------------------------------------------------------------------- /tests/codegen/keywords-in-interfaces-and-worlds.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world trait { 4 | import continue: interface { 5 | break: func(); 6 | } 7 | 8 | export match: interface { 9 | return: func(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/codegen/keywords.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface keywords { 4 | record for { 5 | return: u32, 6 | } 7 | %type: func(%type: u32) -> tuple; 8 | %variant: func(%enum: s32) -> (); 9 | %interface: func(%interface: s32) -> (); 10 | throw: func(throw: s32) -> (); 11 | new: func(new: s32) -> (); 12 | %package: func(%package: s32) -> (); 13 | final: func(final: s32) -> (); 14 | auto: func(auto: s32) -> (); 15 | else: func(for: s32) -> (); 16 | long: func(long: s32) -> (); 17 | switch: func(switch: s32) -> (); 18 | break: func(break: s32) -> (); 19 | register: func(register: s32) -> (); 20 | typedef: func(typedef: s32) -> (); 21 | case: func(case: s32) -> (); 22 | extern: func(extern: s32) -> (); 23 | %char: func(%char: s32) -> (); 24 | float: func(float: s32) -> (); 25 | short: func(short: s32) -> (); 26 | unsigned: func(unsigned: s32) -> (); 27 | const: func(const: s32) -> (); 28 | signed: func(signed: s32) -> (); 29 | void: func(void: s32) -> (); 30 | continue: func(continue: s32) -> (); 31 | goto: func(goto: s32) -> (); 32 | sizeof: func(sizeof: s32) -> (); 33 | volatile: func(volatile: s32) -> (); 34 | default: func(default: s32) -> (); 35 | if: func(if: s32) -> (); 36 | %static: func(%static: s32) -> (); 37 | while: func(while: s32) -> (); 38 | do: func(do: s32) -> (); 39 | %int: func(%int: s32) -> (); 40 | %struct: func(%struct: s32) -> (); 41 | } 42 | 43 | world the-world { 44 | import keywords; 45 | export keywords; 46 | } 47 | -------------------------------------------------------------------------------- /tests/codegen/lift-lower-foreign.wit: -------------------------------------------------------------------------------- 1 | package my:lift-lower-foreign; 2 | 3 | interface a { 4 | type t1 = u32; 5 | record t2 { a: t1 } 6 | flags t3 { a, b, c } 7 | type t4 = tuple; 8 | variant t5 { a, b(t2), c(t3) } 9 | enum t6 { a, b, c } 10 | type t7 = option; 11 | type t8 = result; 12 | type t10 = list; 13 | type t11 = t10; 14 | } 15 | 16 | interface the-interface { 17 | use a.{t1 as u1, t2 as u2, t3 as u3, t4 as u4, t5 as u5}; 18 | use a.{t6 as u6, t7 as u7, t8 as %u8}; 19 | use a.{t10 as u10, t11 as u11}; 20 | 21 | f1: func(a: u1) -> u1; 22 | f2: func(a: u2) -> u2; 23 | f3: func(a: u3) -> u3; 24 | f4: func(a: u4) -> u4; 25 | f5: func(a: u5) -> u5; 26 | f6: func(a: u6) -> u6; 27 | f7: func(a: u7) -> u7; 28 | f8: func(a: %u8) -> %u8; 29 | f10: func(a: u10) -> u10; 30 | f11: func(a: u11) -> u11; 31 | } 32 | 33 | world foo { 34 | use a.{t1 as u1, t2 as u2, t3 as u3, t4 as u4, t5 as u5}; 35 | use a.{t6 as u6, t7 as u7, t8 as %u8}; 36 | use a.{t10 as u10, t11 as u11}; 37 | 38 | export foo-f1: func(a: u1) -> u1; 39 | export foo-f2: func(a: u2) -> u2; 40 | export foo-f3: func(a: u3) -> u3; 41 | export foo-f4: func(a: u4) -> u4; 42 | export foo-f5: func(a: u5) -> u5; 43 | export foo-f6: func(a: u6) -> u6; 44 | export foo-f7: func(a: u7) -> u7; 45 | export foo-f8: func(a: %u8) -> %u8; 46 | export foo-f10: func(a: u10) -> u10; 47 | export foo-f11: func(a: u11) -> u11; 48 | 49 | import the-interface; 50 | export the-interface; 51 | } 52 | -------------------------------------------------------------------------------- /tests/codegen/many-arguments.wit: -------------------------------------------------------------------------------- 1 | package many:arguments; 2 | 3 | interface manyarg { 4 | many-args: func( 5 | a1: u64, 6 | a2: u64, 7 | a3: u64, 8 | a4: u64, 9 | a5: u64, 10 | a6: u64, 11 | a7: u64, 12 | a8: u64, 13 | a9: u64, 14 | a10: u64, 15 | a11: u64, 16 | a12: u64, 17 | a13: u64, 18 | a14: u64, 19 | a15: u64, 20 | a16: u64, 21 | ); 22 | 23 | record big-struct { 24 | a1: string, 25 | a2: string, 26 | a3: string, 27 | a4: string, 28 | a5: string, 29 | a6: string, 30 | a7: string, 31 | a8: string, 32 | a9: string, 33 | a10: string, 34 | a11: string, 35 | a12: string, 36 | a13: string, 37 | a14: string, 38 | a15: string, 39 | a16: string, 40 | a17: string, 41 | a18: string, 42 | a19: string, 43 | a20: string, 44 | } 45 | 46 | big-argument: func(x: big-struct); 47 | } 48 | 49 | world the-world { 50 | import manyarg; 51 | export manyarg; 52 | } 53 | -------------------------------------------------------------------------------- /tests/codegen/multi-return.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface multi-return { 4 | mra: func(); 5 | mrb: func() -> (); 6 | mrc: func() -> u32; 7 | } 8 | 9 | world the-world { 10 | import multi-return; 11 | export multi-return; 12 | } 13 | -------------------------------------------------------------------------------- /tests/codegen/multiversion/wit/deps/v1/root.wit: -------------------------------------------------------------------------------- 1 | package my:dep@0.1.0; 2 | 3 | interface a { 4 | type foo = u8; 5 | x: func(); 6 | } -------------------------------------------------------------------------------- /tests/codegen/multiversion/wit/deps/v2/root.wit: -------------------------------------------------------------------------------- 1 | package my:dep@0.2.0; 2 | 3 | interface a { 4 | use my:dep/a@0.1.0.{foo}; 5 | x: func() -> foo; 6 | } -------------------------------------------------------------------------------- /tests/codegen/multiversion/wit/root.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | world foo { 4 | import my:dep/a@0.1.0; 5 | import my:dep/a@0.2.0; 6 | export my:dep/a@0.2.0; 7 | } -------------------------------------------------------------------------------- /tests/codegen/option-result.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface option-result { 4 | // NB: this record used to be empty, but that's no longer valid, so now it's 5 | // non-empty. Don't want to delete the whole test however. 6 | record empty { 7 | not-empty-anymore: bool, 8 | } 9 | record o-one { 10 | a: option, 11 | } 12 | 13 | record o-nested { 14 | a: option>, 15 | } 16 | 17 | type o1 = option; 18 | type o2 = option; 19 | type o4 = option>; 20 | 21 | type r1 = result; 22 | type r2 = result<_, empty>; 23 | type r3 = result; 24 | type r4 = result; 25 | type r5 = result, o1>; 26 | type r6 = result>, o2>; 27 | type r7 = result>, o4>; 28 | 29 | 30 | type o5 = option; 31 | type o6 = option>>; 32 | 33 | 34 | o5-arg: func(x: o5); 35 | o5-result: func() -> o5; 36 | 37 | o6-arg: func(x: o6); 38 | o6-result: func() -> o6; 39 | 40 | r1-arg: func(x: r1); 41 | r1-result: func() -> r1; 42 | 43 | r2-arg: func(x: r2); 44 | r2-result: func() -> r2; 45 | 46 | r3-arg: func(x: r3); 47 | r3-result: func() -> r3; 48 | 49 | r4-arg: func(x: r4); 50 | r4-result: func() -> r4; 51 | 52 | r5-arg: func(x: r5); 53 | r5-result: func() -> r5; 54 | 55 | r6-arg: func(x: r6); 56 | r6-result: func() -> r6; 57 | 58 | r7-arg: func(x: r7); 59 | r7-result: func() -> r7; 60 | 61 | multi: func(x: r7, y: r7) -> tuple; 62 | multi-option: func(x: r7, y: r7) -> option>; 63 | } 64 | 65 | world my-world { 66 | import option-result; 67 | export option-result; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /tests/codegen/record-has-go-keyword-and-used-in-fn.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface foo-bar { 4 | record foo{ 5 | %type: string, 6 | anything: string 7 | } 8 | 9 | record bar{ 10 | anything: u16 11 | } 12 | 13 | fetch: func(x: foo) -> result; 14 | } 15 | 16 | world foo-world { 17 | import foo-bar; 18 | } -------------------------------------------------------------------------------- /tests/codegen/records.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface records { 4 | tuple-arg: func(x: tuple); 5 | tuple-result: func() -> tuple; 6 | 7 | // NB: this record used to be empty, but that's no longer valid, so now it's 8 | // non-empty. Don't want to delete the whole test however. 9 | record empty { 10 | not-empty-anymore: bool, 11 | } 12 | 13 | empty-arg: func(x: empty); 14 | empty-result: func() -> empty; 15 | 16 | /// A record containing two scalar fields 17 | /// that both have the same type 18 | record scalars { 19 | /// The first field, named a 20 | a: u32, 21 | /// The second field, named b 22 | b: u32, 23 | } 24 | 25 | scalar-arg: func(x: scalars); 26 | scalar-result: func() -> scalars; 27 | 28 | /// A record that is really just flags 29 | /// All of the fields are bool 30 | record really-flags { 31 | a: bool, 32 | b: bool, 33 | c: bool, 34 | d: bool, 35 | e: bool, 36 | f: bool, 37 | g: bool, 38 | h: bool, 39 | i: bool, 40 | } 41 | 42 | flags-arg: func(x: really-flags); 43 | flags-result: func() -> really-flags; 44 | 45 | record aggregates { 46 | a: scalars, 47 | b: u32, 48 | c: empty, 49 | d: string, 50 | e: really-flags, 51 | } 52 | 53 | aggregate-arg: func(x: aggregates); 54 | aggregate-result: func() -> aggregates; 55 | 56 | type tuple-typedef = tuple; 57 | type int-typedef = s32; 58 | type tuple-typedef2 = tuple; 59 | typedef-inout: func(e: tuple-typedef2) -> s32; 60 | } 61 | 62 | world the-world { 63 | import records; 64 | export records; 65 | } 66 | -------------------------------------------------------------------------------- /tests/codegen/rename-interface.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface foo { 4 | record bar { 5 | r: bool, 6 | } 7 | } 8 | 9 | world the-world { 10 | import foo; 11 | import other-name: interface { 12 | use foo.{bar}; 13 | 14 | a: func() -> bar; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/codegen/resource-alias.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | 3 | interface e1 { 4 | resource x { 5 | constructor(s: string); 6 | get: func() -> string; 7 | } 8 | 9 | record foo { x: x } 10 | 11 | a: func(f: foo) -> list; 12 | } 13 | 14 | interface e2 { 15 | use e1.{x, foo as bar}; 16 | 17 | record foo { x: x } 18 | 19 | a: func(f: foo, g: bar) -> list; 20 | } 21 | 22 | world resources { 23 | use e2.{x}; 24 | 25 | export frobnicate: func(x: list) -> list; 26 | 27 | import e1; 28 | import e2; 29 | export e1; 30 | export e2; 31 | } 32 | -------------------------------------------------------------------------------- /tests/codegen/resource-borrow-in-record-export.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | interface foo4 { 4 | resource y; 5 | 6 | record r { 7 | y: borrow 8 | } 9 | 10 | f: func(a: list); 11 | } 12 | 13 | world x { 14 | export foo4; 15 | } 16 | -------------------------------------------------------------------------------- /tests/codegen/resource-borrow-in-record.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | world x { 4 | resource y; 5 | 6 | record r { 7 | y: borrow 8 | } 9 | 10 | import f: func(a: list); 11 | } 12 | -------------------------------------------------------------------------------- /tests/codegen/resource-local-alias-borrow-import.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | interface foo2 { 4 | resource a; 5 | type b = a; 6 | f1: func(a: borrow); 7 | f2: func(b: borrow); 8 | } 9 | 10 | world x { 11 | import foo2; 12 | } 13 | -------------------------------------------------------------------------------- /tests/codegen/resource-local-alias-borrow.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | interface foo3 { 4 | resource a; 5 | type b = a; 6 | f1: func(a: borrow); 7 | f2: func(b: borrow); 8 | } 9 | 10 | world x { 11 | export foo3; 12 | } 13 | -------------------------------------------------------------------------------- /tests/codegen/resource-local-alias.wit: -------------------------------------------------------------------------------- 1 | package foo:bar; 2 | 3 | interface foo { 4 | resource a; 5 | type b = a; 6 | f1: func(a: a); 7 | f2: func(b: b); 8 | } 9 | 10 | world x { 11 | import foo; 12 | export foo; 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/resource-own-in-other-interface.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | interface e1 { 3 | resource x { 4 | fun: func() -> tuple; 5 | } 6 | } 7 | 8 | world resources { 9 | import e2: interface { 10 | use e1.{x}; 11 | use-res: func() -> x; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/resources-in-aggregates.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | 3 | interface aggregates { 4 | resource z; 5 | 6 | record r1 { 7 | z: z 8 | } 9 | record r2 { 10 | z: borrow 11 | } 12 | record r3 { 13 | z1: borrow, 14 | z2: z, 15 | } 16 | type t1 = tuple; 17 | type t2 = tuple>; 18 | 19 | variant v1 { 20 | z(z), 21 | } 22 | variant v2 { 23 | z(borrow), 24 | } 25 | 26 | type l1 = list; 27 | type l2 = list>; 28 | 29 | f: func( 30 | r1: r1, 31 | r2: r2, 32 | r3: r3, 33 | t1: t1, 34 | t2: t2, 35 | v1: v1, 36 | v2: v2, 37 | l1: l1, 38 | l2: l2, 39 | o1: option, 40 | o2: option>, 41 | result1: result, 42 | result2: result>, 43 | ); 44 | } 45 | 46 | world resources { 47 | import aggregates; 48 | export aggregates; 49 | } 50 | -------------------------------------------------------------------------------- /tests/codegen/resources-with-lists.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | 3 | interface with-lists { 4 | resource x { 5 | constructor(l: list); 6 | get: func() -> list; 7 | set: func(l: list); 8 | etc: static func(l: list) -> list; 9 | } 10 | } 11 | 12 | world resources { 13 | import with-lists; 14 | export with-lists; 15 | } 16 | -------------------------------------------------------------------------------- /tests/codegen/resources.wit: -------------------------------------------------------------------------------- 1 | package my:resources; 2 | 3 | interface types { 4 | resource z { 5 | constructor(a: f64); 6 | } 7 | } 8 | 9 | world resources { 10 | use types.{z}; 11 | 12 | export add: func(a: borrow, b: borrow) -> own; 13 | 14 | export maybe-with-z: func(a: option>); 15 | 16 | variant includes-borrow { 17 | a, 18 | b(borrow), 19 | } 20 | 21 | export variant-with-z: func(a: includes-borrow); 22 | export maybe-variant-with-z: func(a: option); 23 | 24 | record big { 25 | x1: borrow, 26 | x2: borrow, 27 | x3: borrow, 28 | x4: borrow, 29 | x5: borrow, 30 | x6: borrow, 31 | x7: borrow, 32 | x8: borrow, 33 | x9: borrow, 34 | x10: borrow, 35 | } 36 | 37 | export big-record: func(r: big); 38 | 39 | export exports: interface { 40 | resource x { 41 | constructor(a: f64); 42 | get-a: func() -> f64; 43 | set-a: func(a: f64); 44 | add: static func(x: x, a: f64) -> x; 45 | } 46 | } 47 | 48 | import imports: interface { 49 | resource y { 50 | constructor(a: f64); 51 | get-a: func() -> f64; 52 | set-a: func(a: f64); 53 | add: static func(y: y, a: f64) -> y; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/codegen/result-empty.wit: -------------------------------------------------------------------------------- 1 | package local:demo; 2 | 3 | interface my-interface { 4 | variant stuff { 5 | this, 6 | that 7 | } 8 | 9 | // NB: this record used to be empty, but that's no longer valid, so now it's 10 | // non-empty. Don't want to delete the whole test however. 11 | record empty { 12 | not-empty-anymore: bool, 13 | } 14 | 15 | stuff-or-stuff: func() -> result; 16 | stuff-or-empty: func() -> result; 17 | empty-or-stuff: func() -> result; 18 | empty-or-empty: func() -> result; 19 | 20 | stuff-or-absent: func() -> result; 21 | absent-or-stuff: func() -> result<_, stuff>; 22 | 23 | empty-or-absent: func() -> result; 24 | absent-or-empty: func() -> result<_, empty>; 25 | 26 | absent-or-absent: func() -> result; 27 | } 28 | 29 | 30 | world my-world { 31 | import my-interface; 32 | } 33 | -------------------------------------------------------------------------------- /tests/codegen/ret-areas.wit: -------------------------------------------------------------------------------- 1 | // This test generates multiple `RetArea` structs. 2 | 3 | package foo:foo; 4 | 5 | interface tcp { 6 | type ipv6-socket-address = tuple; 7 | 8 | connect: func( 9 | local-address: ipv6-socket-address, 10 | remote-address: ipv6-socket-address, 11 | ) -> tuple; 12 | } 13 | 14 | world wasi { 15 | import tcp; 16 | } 17 | -------------------------------------------------------------------------------- /tests/codegen/return-resource-from-export.wit: -------------------------------------------------------------------------------- 1 | package test:test; 2 | 3 | world foo { 4 | resource x; 5 | 6 | export return-resource: func() -> x; 7 | } 8 | -------------------------------------------------------------------------------- /tests/codegen/same-names1.wit: -------------------------------------------------------------------------------- 1 | package name1:name1; 2 | 3 | world name1 { 4 | import name1: func(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/codegen/same-names2.wit: -------------------------------------------------------------------------------- 1 | package name2:name2; 2 | 3 | world name2 { 4 | export name2: func(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/codegen/same-names3.wit: -------------------------------------------------------------------------------- 1 | package name3:name3; 2 | 3 | interface name3 { 4 | name3: func(); 5 | } 6 | 7 | world w { 8 | import name3; 9 | export name3; 10 | } 11 | -------------------------------------------------------------------------------- /tests/codegen/same-names4.wit: -------------------------------------------------------------------------------- 1 | package name4:name4; 2 | 3 | interface name4 { 4 | type name4 = u32; 5 | 6 | bar: func() -> name4; 7 | } 8 | 9 | world w { 10 | import name4; 11 | export name4; 12 | } 13 | -------------------------------------------------------------------------------- /tests/codegen/same-names5.wit: -------------------------------------------------------------------------------- 1 | package name5:name5; 2 | 3 | world name5 { 4 | record name5 { 5 | r: bool, 6 | } 7 | 8 | export x: func() -> name5; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/codegen/simple-enum.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface enums { 4 | enum e1 { 5 | a, 6 | b, 7 | c 8 | } 9 | 10 | enum e2 { 11 | something, 12 | else 13 | } 14 | 15 | e1-arg: func(x: e1); 16 | e2-arg: func(x: e2); 17 | 18 | e1-ret: func(x: e1) -> e2; 19 | } 20 | 21 | world the-world { 22 | import enums; 23 | export enums; 24 | } 25 | -------------------------------------------------------------------------------- /tests/codegen/simple-functions.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface simple { 4 | f1: func(); 5 | f2: func(a: u32); 6 | f3: func(a: u32, b: u32); 7 | 8 | f4: func() -> u32; 9 | f5: func() -> tuple; 10 | 11 | f6: func(a: u32, b: u32, c: u32) -> tuple; 12 | } 13 | 14 | world the-world { 15 | import simple; 16 | export simple; 17 | } 18 | -------------------------------------------------------------------------------- /tests/codegen/simple-http.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface http-fetch-imports { 4 | record request{ 5 | method: string, 6 | uri: string, 7 | body: string 8 | } 9 | 10 | record response{ 11 | status: u16, 12 | body: string 13 | } 14 | 15 | fetch: func(req: request) -> result; 16 | } 17 | 18 | world http-fetch-simple { 19 | import http-fetch-imports; 20 | } 21 | -------------------------------------------------------------------------------- /tests/codegen/simple-lists.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface simple-lists { 4 | simple-list1: func(l: list); 5 | simple-list2: func() -> list; 6 | simple-list3: func(a: list, b: list) -> tuple, list>; 7 | simple-list4: func(l: list>) -> list>; 8 | } 9 | 10 | world my-world { 11 | import simple-lists; 12 | export simple-lists; 13 | } 14 | -------------------------------------------------------------------------------- /tests/codegen/simple-option.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface option-simple { 4 | // NB: this record used to be empty, but that's no longer valid, so now it's 5 | // non-empty. Don't want to delete the whole test however. 6 | record empty { 7 | not-empty-anymore: bool, 8 | } 9 | record o-one { 10 | a: option, 11 | } 12 | 13 | record o-nested { 14 | a: option>, 15 | } 16 | 17 | type o1 = option; 18 | type o2 = option; 19 | type o3 = option; 20 | type o4 = option>; 21 | 22 | 23 | oint-arg: func(x: option); 24 | oint-result: func() -> option; 25 | 26 | o1-arg: func(x: o1); 27 | o1-result: func() -> o1; 28 | 29 | o2-arg: func(x: o2); 30 | o2-result: func() -> o2; 31 | 32 | o3-arg: func(x: o3); 33 | o3-result: func() -> o3; 34 | 35 | o4-arg: func(x: o4); 36 | o4-result: func() -> o4; 37 | } 38 | 39 | world my-world { 40 | import option-simple; 41 | export option-simple; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /tests/codegen/small-anonymous.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface anon { 4 | enum error { 5 | success, 6 | failure, 7 | } 8 | 9 | option-test: func() -> result, error>; 10 | } 11 | 12 | world the-world { 13 | import anon; 14 | export anon; 15 | } 16 | -------------------------------------------------------------------------------- /tests/codegen/smoke-default.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world the-world { 4 | export y: func(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/codegen/smoke-export.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world the-world { 4 | export the-name: interface { 5 | y: func(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/codegen/smoke.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world the-world { 4 | import imports: interface { 5 | y: func(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/codegen/strings.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface strings { 4 | a: func(x: string); 5 | b: func() -> string; 6 | c: func(a: string, b: string) -> string; 7 | } 8 | 9 | world the-world { 10 | import strings; 11 | export strings; 12 | } 13 | -------------------------------------------------------------------------------- /tests/codegen/unused-import.wit: -------------------------------------------------------------------------------- 1 | package unused:%import; 2 | 3 | interface types { 4 | record r { 5 | a: list, 6 | } 7 | } 8 | 9 | world the-world { 10 | import foo: interface { 11 | use types.{r}; 12 | 13 | foo: func(data: r); 14 | } 15 | 16 | export bar: interface { 17 | use types.{r}; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/codegen/use-across-interfaces.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface foo { 4 | type headers = list>; 5 | record a { 6 | headers: headers 7 | } 8 | x: func() -> a; 9 | } 10 | 11 | interface bar { 12 | use foo.{a}; 13 | x: func() -> a; 14 | } 15 | 16 | world baz { 17 | import foo; 18 | import bar; 19 | import baz: interface { 20 | use foo.{a}; 21 | x: func() -> a; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/codegen/world-has-go-keyword.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface foo-bar { 4 | hello: func() -> string; 5 | } 6 | 7 | world %type { 8 | import foo-bar; 9 | } 10 | -------------------------------------------------------------------------------- /tests/codegen/worlds-with-types.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | interface i { 4 | type type1 = u32; 5 | } 6 | 7 | world foo { 8 | use i.{type1}; 9 | 10 | type type2 = u32; 11 | 12 | record type3 { 13 | r: u32, 14 | } 15 | 16 | export foo: func() -> tuple; 17 | } 18 | -------------------------------------------------------------------------------- /tests/codegen/zero-size-tuple.wit: -------------------------------------------------------------------------------- 1 | package foo:foo; 2 | 3 | world bindings { 4 | import component; 5 | } 6 | 7 | interface component { 8 | type value = tuple; 9 | query-eval: func(q: u64) -> list; 10 | } 11 | -------------------------------------------------------------------------------- /tests/go/.gitignore: -------------------------------------------------------------------------------- 1 | /bindings 2 | -------------------------------------------------------------------------------- /tests/go/async.go: -------------------------------------------------------------------------------- 1 | //go:generate $WIT_BINDGEN_WRPC go --world async-server --out-dir bindings/async_server --package wrpc.io/tests/go/bindings/async_server ../wit 2 | 3 | package integration 4 | 5 | import ( 6 | "bytes" 7 | "context" 8 | "errors" 9 | "io" 10 | "log/slog" 11 | 12 | wrpc "wrpc.io/go" 13 | "wrpc.io/tests/go/bindings/async_server/exports/wrpc_test/integration/async" 14 | ) 15 | 16 | type AsyncHandler struct{} 17 | 18 | func (AsyncHandler) WithStreams(ctx context.Context) (io.ReadCloser, wrpc.Receiver[[][]string], error) { 19 | slog.DebugContext(ctx, "handling `with-streams`") 20 | buf := io.NopCloser(bytes.NewBuffer([]byte("test"))) 21 | str := wrpc.NewCompleteReceiver([][]string{{"foo"}, {"bar", "baz"}}) 22 | return buf, str, nil 23 | } 24 | 25 | func (AsyncHandler) WithFuture(ctx context.Context, x *async.Something, s io.ReadCloser) (wrpc.Receiver[io.ReadCloser], error) { 26 | slog.DebugContext(ctx, "handling `with-future`", "x", x) 27 | if x.Foo != "bar" { 28 | return nil, errors.New("`foo` is not `bar`") 29 | } 30 | return wrpc.NewCompleteReceiver(s), nil 31 | } 32 | 33 | func (AsyncHandler) IdentityNestedAsync(ctx context.Context, v wrpc.Receiver[wrpc.Receiver[wrpc.Receiver[wrpc.Receiver[[]string]]]]) (wrpc.Receiver[wrpc.Receiver[wrpc.Receiver[wrpc.Receiver[[]string]]]], error) { 34 | slog.DebugContext(ctx, "handling `identity-nested-async`") 35 | return v, nil 36 | } 37 | -------------------------------------------------------------------------------- /tests/go/go.mod: -------------------------------------------------------------------------------- 1 | module wrpc.io/tests/go 2 | 3 | go 1.24 4 | 5 | require ( 6 | github.com/google/uuid v1.6.0 7 | github.com/lmittmann/tint v1.0.5 8 | github.com/nats-io/nats-server/v2 v2.10.14 9 | github.com/nats-io/nats.go v1.42.0 10 | wrpc.io/go v0.2.0 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/klauspost/compress v1.18.0 // indirect 16 | github.com/minio/highwayhash v1.0.2 // indirect 17 | github.com/nats-io/jwt/v2 v2.5.5 // indirect 18 | github.com/nats-io/nkeys v0.4.11 // indirect 19 | github.com/nats-io/nuid v1.0.1 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | github.com/stretchr/testify v1.9.0 22 | golang.org/x/crypto v0.37.0 // indirect 23 | golang.org/x/sys v0.32.0 // indirect 24 | golang.org/x/time v0.5.0 // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | 28 | replace wrpc.io/go v0.2.0 => ../../go 29 | -------------------------------------------------------------------------------- /tests/go/internal/internal.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "log/slog" 5 | "os" 6 | "testing" 7 | "time" 8 | 9 | "github.com/lmittmann/tint" 10 | "github.com/nats-io/nats-server/v2/server" 11 | "github.com/nats-io/nats-server/v2/test" 12 | ) 13 | 14 | func init() { 15 | slog.SetDefault(slog.New(tint.NewHandler(os.Stderr, &tint.Options{ 16 | AddSource: true, 17 | Level: slog.LevelDebug, 18 | ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { 19 | if a.Key == slog.TimeKey { 20 | return slog.Attr{} 21 | } 22 | return a 23 | }, 24 | }))) 25 | } 26 | 27 | func RunNats(t *testing.T) *server.Server { 28 | opts := test.DefaultTestOptions 29 | opts.Cluster.Compression.Mode = server.CompressionOff 30 | opts.Cluster.PoolSize = -1 31 | opts.Debug = true 32 | opts.LeafNode.Compression.Mode = server.CompressionOff 33 | opts.NoLog = false 34 | opts.Port = -1 35 | opts.Trace = true 36 | opts.TraceVerbose = true 37 | 38 | s, err := server.NewServer(&opts) 39 | if err != nil { 40 | t.Fatal("failed to contruct NATS server") 41 | } 42 | s.ConfigureLogger() 43 | go s.Start() 44 | if !s.ReadyForConnections(10 * time.Second) { 45 | t.Fatal("failed to start NATS Server") 46 | } 47 | return s 48 | } 49 | -------------------------------------------------------------------------------- /tests/go/types_test.go: -------------------------------------------------------------------------------- 1 | //go:generate $WIT_BINDGEN_WRPC go --gofmt=false --world types --out-dir bindings/types --package wrpc.io/tests/go/bindings/types ../wit 2 | 3 | package integration_test 4 | 5 | import ( 6 | "bytes" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | wrpc "wrpc.io/go" 11 | "wrpc.io/tests/go/bindings/types/wrpc_test/integration/get_types" 12 | ) 13 | 14 | type indexReader struct { 15 | *bytes.Buffer 16 | } 17 | 18 | func (r *indexReader) Index(path ...uint32) (wrpc.IndexReadCloser, error) { 19 | panic("not implemented") 20 | } 21 | 22 | func TestTypes_Flags(t *testing.T) { 23 | t.Run("WriteToIndex", func(t *testing.T) { 24 | check := assert.New(t) 25 | 26 | flags := get_types.FeatureFlags{ 27 | ShowA: true, 28 | ShowC: true, 29 | } 30 | var b bytes.Buffer 31 | _, err := flags.WriteToIndex(&b) 32 | check.NoError(err) 33 | check.Equal([]byte{0b00000101}, b.Bytes()) 34 | }) 35 | 36 | t.Run("ReadFromIndex", func(t *testing.T) { 37 | check := assert.New(t) 38 | 39 | var flags get_types.FeatureFlags 40 | err := flags.ReadFromIndex(&indexReader{ 41 | Buffer: bytes.NewBuffer([]byte{0b00000101}), 42 | }) 43 | check.NoError(err) 44 | check.Equal(get_types.FeatureFlags{ 45 | ShowA: true, 46 | ShowC: true, 47 | }, flags) 48 | 49 | t.Run("invalid bit set", func(t *testing.T) { 50 | check := assert.New(t) 51 | 52 | var flags get_types.FeatureFlags 53 | err := flags.ReadFromIndex(&indexReader{ 54 | Buffer: bytes.NewBuffer([]byte{0b10000000}), 55 | }) 56 | if check.Error(err) { 57 | check.Equal("bit not associated with any flag is set", err.Error()) 58 | } 59 | check.Zero(flags) 60 | }) 61 | }) 62 | } 63 | --------------------------------------------------------------------------------