Is there a reason you are avoiding a simple compilation of Zig part of codebase into a dynamically or statically linked library and calling into it with P/Invoke? You only need a `Target` and maybe `None Include=...` items in .csproj to instrument MSBuild to hook the building process of Zig into dotnet build and co.
I'm just putting a disclaimer that using WASM is a very wrong kind of suggestion, would likely not work the way you expect it to (you would have to use WASM for .NET too which is in many places experimental and is a huge performance killer) and no one does it - there are appropriate ways to target multiple platforms in a solution that splits logic between .NET and C/C++/Rust/Zig/Swift/etc., especially that Zig offers nice cross-compilation toolchain. Mind you, the use case for this is accessing language-specific libraries and for performance the solution really is writing faster C# instead.
I want the editor to be usable in other GUI stacks, a C-compatible library is the only approach that makes sense here
https://github.com/dotnet/ClangSharp
I strongly caution against WASM suggestions in a sibling comment - I’m not even sure if the author has actually done any C# at all, given how ridiculous it is.
WASM is definitely a strange suggestion here, I didn’t take it seriously. I’m already using a C-compatible zig library approach. Some details of the use case here: https://news.ycombinator.com/item?id=41729059
But I think the more interesting thing is that if you remove all features in C# that require heap allocations, the resulting subset is basically C with namespaces and generics, which is still useful, and certainly possible to compile efficiently even for very constrained platforms.
C# is quite a bit more than just enhanced C if you remove GC-reliant features as the generics and interface constraints enable a huge subset of features, alongside SIMD API, stack-allocated buffers and all sorts of memory wrappable in Span<T>s, which almost every method in the standard library that works on some sort of buffer accepts nowadays instead of plain arrays.
You can also manually allocate objects - there are multiple ways to go about it and even with the presence of GC, there is a "hidden" but supported API to register a NonGC heap that GC understands when scanning object references.
Though effective targeting is limited to much fewer count of platforms. Mono can target as low as ARMv6 but CoreCLR/NativeAOT mainly work with x86, x86_64, ARM and ARM64. For microcontrollers you are better off using Rust in my opinion. But for anything bigger .NET can be a surprisingly capable choice.