Repository navigation
Conversation
This comment has been minimized.
This comment has been minimized.
|
I didn't look at this in detail yet, but I did notice it is not using the same component type elaboration infrastructure from the Rust macros. I think this is probably a mistake as it does not seem to me that most of the more complex cases are possible to get right without the explicit representation of type variables. I think pretty much the only thing in |
9ab4272 to
fcd4c0f
Compare
Thanks, reworked it this way. The C# generator now drives off read_wit_type and the elaborated component, with its own equivalents of rtypes/host emit_toplevel in types.rs and host.rs. State is parametrised on the root module (defaulting to Mod), and C# uses resolve_bound_var and emit_fn_hl_name from it. I left BindgenInputParams in the macro crate, since C# takes a WitSource and calls read_wit_type, so the source handling is already shared and the parser's only user is the macro syntax. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
🟡 Changes recommended
Supported inputs can produce uncompilable bindings, and decoding and structural hashing defects remain.
11 open issues
Resolve CLI WIT paths before invoking the shared reader · New Hash byte arrays consistently with enumerable byte lists · New Allow zero-byte list elements with separate allocation limits · New Generate compilable C# for empty tuples · New Avoid enum and flags members matching enclosing types · New Prevent generated type parameter name collisions · New Compute empty and full flags masks safely · New Avoid imported method names matching interface types · New Prevent export names from conflicting with generated members · New Validate and escape namespace segments for valid C# · New Avoid variant case names matching enclosing record names · New
What changed in this PR
Adds C# host bindings for Hyperlight components, sharing WIT type resolution and wire naming with the Rust generators.
Changes:
- C# generation and runtime support for component values and calls.
- Little-endian encoding and interface-qualified wire names.
- Cross-language tests, documentation, CI and publishing integration.
| File | Description |
|---|---|
| src/tests/component_wire/wire.wit | Shared wire-format fixture. |
| src/tests/component_wire/vectors.txt | Cross-language encoding vectors. |
| src/tests/component_wire/csharp/WireTests.cs | Encoding and decoding checks. |
| src/tests/component_wire/csharp/RuntimeTests.cs | Runtime validation checks. |
| src/tests/component_wire/csharp/Program.cs | Test runner and assertions. |
| src/tests/component_wire/csharp/Fakes.cs | Fake guest and registry. |
| src/tests/component_wire/csharp/EdgeTests.cs | Naming and type checks. |
| src/tests/component_wire/csharp/edge.wit | Edge-case WIT fixture. |
| src/tests/component_wire/csharp/ComponentTests.csproj | Generates and compiles test bindings. |
| src/hyperlight_host/tests/component_wire_test.rs | Rust wire-vector checks. |
| src/hyperlight_component_util/src/util.rs | WIT path resolution fallback. |
| src/hyperlight_component_util/src/host.rs | Host instance naming context. |
| src/hyperlight_component_util/src/hl.rs | Wire names and little-endian encoding. |
| src/hyperlight_component_util/src/guest.rs | Guest instance naming context. |
| src/hyperlight_component_util/src/emit.rs | Shared generation state. |
| src/hyperlight_component_csharp/src/types.rs | Type discovery and validation. |
| src/hyperlight_component_csharp/src/tests.rs | Generator tests. |
| src/hyperlight_component_csharp/src/Runtime.cs | C# codecs and support types. |
| src/hyperlight_component_csharp/src/names.rs | C# identifier helpers. |
| src/hyperlight_component_csharp/src/lib.rs | Generator API and namespaces. |
| src/hyperlight_component_csharp/src/host.rs | Call wrappers and import registration. |
| src/hyperlight_component_csharp/src/codec.rs | Type and codec generation. |
| src/hyperlight_component_csharp/README.md | Generator usage documentation. |
| src/hyperlight_component_csharp/examples/csharp_bindgen.rs | Command-line generation example. |
| src/hyperlight_component_csharp/Cargo.toml | Crate definition. |
| Justfile | Build and test integration. |
| docs/README.md | Wire-format documentation link. |
| docs/how-to-make-releases.md | Published crate list. |
| docs/component-wire-format.md | Wire contract and C# mappings. |
| CHANGELOG.md | Features and breaking changes. |
| Cargo.toml | Workspace registration. |
| Cargo.lock | Crate dependency entry. |
| .github/workflows/dep_code_checks.yml | C# test execution. |
| .github/workflows/CargoPublish.yml | Crate publishing integration. |
Review effort: Balanced
fcd4c0f to
92cc474
Compare
This comment has been minimized.
This comment has been minimized.
simongdavies
left a comment
There was a problem hiding this comment.
I don't know if this should be in hyperlight rather than hyperlight-wasm, I appreciate we have the rust example but we also have a Rust hosting API so we can show how it is used completely. It feels like half a solution here, that said if we moved it to hyperlight-wasm that wouldn't be solved, we still need a dotnet hosting API.
I think we should consider this in our investigation into the feasibility of having a single host API instead of hyperlight-js/hypelright-wasm etc.
| @@ -0,0 +1,43 @@ | |||
| // SPDX-License-Identifier: Apache-2.0 | |||
There was a problem hiding this comment.
Is there a reason not to use a dotnet test framework like xunit?
There was a problem hiding this comment.
I wanted to keep it as light as possible and have no requirements to download anything
I believe this should definitely be here in hyperlight, it's the same as
I agree we should consider this, but since there's no concrete plan for it yet, I think it's better we get this in. And this will still be needed even if we manage to make a single host api if we want c# host bindigs (at least some form of this) |
I definitely think it should stay in hl core. The wit macros are usable entirely without hyperlight-wasm and I think that is one promising route to having a more uniform approach to host/guest API. Especially since there is room to improve the performance of guest function dispatch by eliminating names when the wit macros are in use. |
92cc474 to
56c0a94
Compare
jsturtevant
left a comment
There was a problem hiding this comment.
overall LGTM, a few comments and really cool way to enable .net developers to write hyperlight guests and I love all the tests!
We don't really have a way to mark a package as experimental. Maybe this is something we want to think about in 1.0? I am sure we will have more of these in the future.
c907c97 to
ad25c60
Compare
This comment has been minimized.
This comment has been minimized.
ad25c60 to
2e27c96
Compare
This comment has been minimized.
This comment has been minimized.
Signed-off-by: Ludvig Liljenberg <[email protected]>
Wire names were the module path plus the function, such as r#wasi::r#clocks::now. They dropped the interface and version, so functions in different interfaces collided. They are now <instance>#<function>, such as wasi:clocks/[email protected]#now. Values are encoded little-endian. Every supported target is little-endian, so the bytes are unchanged. Signed-off-by: Ludvig Liljenberg <[email protected]>
Signed-off-by: Ludvig Liljenberg <[email protected]>
Add world-level functions, an inline export interface, and nested and composite types to guest.wit. Other host bindings can then be tested against witguest. Signed-off-by: Ludvig Liljenberg <[email protected]>
State takes its output type as a parameter, which defaults to Mod. new, clone and resolve_bound_var work for any output, and so does emit_fn_hl_name. read_wit_type also works outside a cargo build. Signed-off-by: Ludvig Liljenberg <[email protected]>
Signed-off-by: Ludvig Liljenberg <[email protected]>
A test-only native library runs witguest in a sandbox, and the C# tests call it through the generated bindings. They run in the X64 build and test jobs, which have the guests and the .NET SDK. Signed-off-by: Ludvig Liljenberg <[email protected]>
2e27c96 to
616d788
Compare
Benchmark ResultsMeasured commit: kvm / amd (Linux) (🌟 5.99x)Top improvements
Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
kvm / intel (Linux) (🌟 5.58x)Top improvements
Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
mshv3 / amd (Linux) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
mshv3 / intel (Linux) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
hyperv-ws2025 / amd (Windows) (🌟 9.48x)Top improvements
Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
hyperv-ws2025 / intel (Windows) (🌟 6.80x)Top improvements
Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
Reported by |

Adds new crate hyperlight-component-csharp which generates c# host bindings from wit. The intended usage is a .NET hyperlight-wasm library, so .net hosts don't need to write rust.
The crate is in rust and not .net because it reuses the component type elaboration from hyperlight-component-util, the same one the rust bindings use. Both generators resolve types and name wire functions the same way. In the future the remaining core (encoding) could be shared too, so they cannot drift.
breakign changes:
<instance>#<function>, such aswasi:http/[email protected]#[method]fields.get, rather thanr#wasi::r#http::[method]fields.get. The old name dropped the interface and version, so functions in different interfaces or versions of one package collided. For example,wasi:clocks/monotonic-clockandwasi:clocks/wall-clockboth registerednowasr#wasi::r#clocks::now, and the second silently replaced the first.The C# bindings support resources the host defines, like the Rust host bindings.
Testing: a test-only native library (
src/tests/csharp_host/native) runs witguest in a sandbox, and the C# tests call it through the generated bindings. guest.wit got world-level functions, an inline interface and more composite types, so the Rust and C# hosts are tested against the same guest.