Language Bindings (C ABI)
Every non-Node binding is layered on a single shared C ABI crate,
corsa_ffi.
It exposes the Rust corsa_client::ApiClient, corsa_core::utils, and
corsa_lsp::VirtualDocument surfaces over a stable C interface, and the thin
per-language wrappers add idiomatic ergonomics on top.
corsa_client / corsa_core::utils / corsa_lsp (Rust)
│
corsa_ffi (C ABI: cdylib + staticlib)
│
┌────────┬─────┴──────┬──────┬──────┬──────────┐
C C++ Go Zig C# Swift / MoonBit
The Node.js binding is documented separately in the
Node binding guide; it uses napi-rs rather than this
C ABI.
What each binding exposes
All seven language wrappers cover the same three surfaces:
- Utils — Rust-backed type-text predicates and splitters
(
classify_type_text,is_string_like_type_texts,split_type_text, …), with no checker process required. - Virtual document — in-memory document editing
(
untitled,apply_changes,replace,state). - API client — spawn a Corsa process and run checker queries
(
spawn,initialize,update_snapshot, …).
| Language | Wrapper location | Header / module |
|---|---|---|
| C | src/bindings/c/corsa_ffi |
include/corsa_utils.h |
| C++ | src/bindings/cpp |
corsa_api.hpp, corsa_utils.hpp, corsa_virtual_document.hpp |
| Go | src/bindings/go/corsa_utils |
github.com/ubugeeei-prod/corsa-bind/src/bindings/go/corsa_utils |
| Zig | src/bindings/zig |
corsa_api.zig, corsa_utils.zig, corsa_virtual_document.zig |
| C# | src/bindings/csharp/CorsaUtils |
CorsaUtils.csproj |
| Swift | src/bindings/swift/CorsaUtils |
Package.swift |
| MoonBit | src/bindings/moonbit/corsa_utils |
moon.pkg.json |
IMPORTANT
Like the Node binding, these wrappers do not bundle a Corsa executable. The API client surface requires a Corsa binary you provide at runtime. The utils and virtual-document surfaces need no external process.
Build the shared library
All bindings link against corsa_ffi. Build it first; the C ABI crate is
configured as both a cdylib and a staticlib:
cargo build -p corsa_ffi
This writes the artifacts into the Cargo target directory:
| Platform | Shared library | Static library |
|---|---|---|
| Linux | target/debug/libcorsa_ffi.so |
target/debug/libcorsa_ffi.a |
| macOS | target/debug/libcorsa_ffi.dylib |
target/debug/libcorsa_ffi.a |
| Windows | target/debug/corsa_ffi.dll |
target/debug/corsa_ffi.lib |
The C header lives at
src/bindings/c/corsa_ffi/include/corsa_utils.h and declares the full struct
set (CorsaStrRef, CorsaString, CorsaBytes, CorsaApiClient,
CorsaVirtualDocument, …) and functions.
NOTE
When you link the dynamic library, the loader has to find it at runtime. Add
target/debug to LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (macOS),
or link the static library instead.
C
Include the header and link the library:
#include "corsa_utils.h"
int main(void) {
CorsaStrRef text = { (const uint8_t *)"string[]", 8 };
CorsaString kind = corsa_utils_classify_type_text(text);
/* use kind.ptr / kind.len, then free Rust-owned strings via the take APIs */
return 0;
}
cargo build -p corsa_ffi
cc main.c \
-I src/bindings/c/corsa_ffi/include \
-L target/debug -lcorsa_ffi \
-o main
LD_LIBRARY_PATH=target/debug ./main
Strings returned as CorsaString are owned by Rust; release the thread-local
last-error string with corsa_error_message_take() where the API documents it.
C++
The C++ headers are header-only RAII wrappers over the same ABI. Include the
headers and add both the cpp and C header directories to the include path:
#include "corsa_api.hpp"
#include "corsa_utils.hpp"
#include "corsa_virtual_document.hpp"
int main() {
auto ref = corsa::utils::to_ref("string");
return ref.len == 0 ? 1 : 0;
}
cargo build -p corsa_ffi
c++ -std=c++20 \
-I src/bindings/cpp \
-I src/bindings/c/corsa_ffi/include \
main.cpp \
-L target/debug -lcorsa_ffi \
-o main
corsa::api::corsa_api_client is move-only and closes the underlying handle in
its destructor, so client lifetime follows normal RAII scoping.
Go
The Go module wraps the C ABI with cgo. Build the shared library, then point the loader at it:
cargo build -p corsa_ffi
cd src/bindings/go/corsa_utils
LD_LIBRARY_PATH=$PWD/../../../../target/debug go test ./...
Import it as:
import corsa "github.com/ubugeeei-prod/corsa-bind/src/bindings/go/corsa_utils"
The package provides the utils predicates plus VirtualDocument and
ApiClient types mirroring the Rust surface.
Zig
The Zig wrapper imports the C header through @cImport and exposes typed
ApiClient, VirtualDocument, and utils APIs:
const corsa = @import("corsa_api.zig");
const client = try corsa.ApiClient.spawn(allocator, .{
.executable = "/path/to/corsa",
.cwd = ".",
.mode = .msgpack,
});
defer client.deinit();
SpawnOptions mirrors the C ABI spawn options (executable, cwd, mode,
request_timeout_ms, shutdown_timeout_ms, outbound_capacity,
allow_unstable_upstream_calls). Add target/debug to the library search path
and link corsa_ffi.
C#
The CorsaUtils project provides CorsaUtils, CorsaApiClient, and
CorsaVirtualDocument over P/Invoke:
cargo build -p corsa_ffi
dotnet build src/bindings/csharp/CorsaUtils/CorsaUtils.csproj
Ensure the native loader can find corsa_ffi at runtime (set the platform
library path or copy the shared library next to the managed assembly).
Swift
The Swift package links corsa_ffi from the Cargo target directory:
cargo build -p corsa_ffi
cd src/bindings/swift/CorsaUtils
swift build
Package.swift links the library with -L ../../../../target/debug -lcorsa_ffi. The Sources/CorsaUtils module exposes CorsaUtils,
CorsaApiClient, and CorsaVirtualDocument.
MoonBit
The MoonBit package wraps the C ABI through a small C shim (cwrap.c):
cargo build -p corsa_ffi
cd src/bindings/moonbit/corsa_utils
moon test
See README.mbt.md in that directory for the MoonBit-specific build details.
The package mirrors the same utils, API client, and virtual document surfaces.
How they are verified
CI builds corsa_ffi, runs the Go binding tests, and compiles a C++ smoke
translation unit against the headers in the non-node-bindings job. The
binding benchmark harness (scripts/bench_bindings.ts, vp run -w bench_bindings) builds and links the C, C++, and Go bindings against the same
shared library. See the CI guide for the full job layout.
See also
- Node.js binding — the
napi-rsJavaScript surface - Architecture — where
corsa_ffisits in the workspace - Support policy — supported platforms and experimental scope