Skip to content

Auto-generate C API bindings#12

Open
asinghvi17 wants to merge 4 commits into
earth-mover:mainfrom
asinghvi17:as/cbindings
Open

Auto-generate C API bindings#12
asinghvi17 wants to merge 4 commits into
earth-mover:mainfrom
asinghvi17:as/cbindings

Conversation

@asinghvi17

Copy link
Copy Markdown

This PR addresses the last point from #11. The idea here is that we can automate both the generation of the C header file from Rust (via cbindgen) and the Julia wrapping of that (via Clang.jl and some expression rewriting to handle the ZarrsResult). I tested this locally and all tests seem to pass.

Changelog

This was generated by Claude

Rust crate (deps/zarrs_jl/)

  • Added cbindgen = "0.29" as a build dependency with build.rs
  • Made StorageHandle, ArrayHandle, GroupHandle pub (fields stay pub(crate)) so cbindgen can see them in function signatures
  • Added cbindgen.toml with opaque handle forward-declarations and #if defined(ZARRS_ICECHUNK) feature guards

Generator (gen/)

  • generator.jl — Clang.jl script with an expression rewriter that handles four patterns:
    • Handle outputs (Ptr{Ptr{X}}) → auto-allocates Ref, returns Ptr{Cvoid}
    • String outputs (Ptr{Cstring}) → auto-allocates Ref, frees via zarrsFreeString
    • Scalar outputs (Ptr{Int32}/Ptr{Csize_t}) → auto-allocates Ref, returns value
    • Buffer pointers (Ptr{UInt64}/Ptr{UInt8}) → left as-is for caller
  • generator.toml — Clang.jl config
  • Project.toml — deps: Clang.jl, MacroTools, JuliaFormatter

Call-site updates (src/)

  • Added explicit Cint(1) pretty arg to metadata/attribute string calls
  • Allocate shape buffers at call sites instead of inside the wrapper
  • Pass explicit ndim and byte counts to subset/chunk I/O functions
  • Wrap Int()/Bool() around return values where types changed

asinghvi17 and others added 4 commits March 19, 2026 21:32
Add cbindgen (0.29) as a build dependency to the zarrs_jl Rust crate so
that `zarrs_jl.h` is auto-generated on every `cargo build`. Opaque handle
types (StorageHandle, ArrayHandle, GroupHandle, IcStorageHandle,
IcRepoHandle, IcSessionHandle) are forward-declared in the header since
their fields contain Rust trait objects that cbindgen cannot translate.
Icechunk functions are guarded behind `#if defined(ZARRS_ICECHUNK)`.

Add a `gen/` directory with a Clang.jl-based generator (modeled after
GDAL.jl) that parses the generated header and produces `src/libzarrs_api.jl`
— a self-contained `module API` with auto-generated ccall wrappers. The
expression rewriter handles four patterns:
- Handle outputs (Ptr{Ptr{X}}) → auto-allocates Ref, returns Ptr{Cvoid}
- String outputs (Ptr{Cstring}) → auto-allocates Ref, frees via zarrsFreeString
- Scalar outputs (Ptr{Int32}/Ptr{Csize_t}) → auto-allocates Ref, returns value
- Buffer pointers (Ptr{UInt64}/Ptr{UInt8}) → left as-is for caller

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update the generator to output `module LibZarrs` directly (replacing the
hand-written 779-line module), and update all call sites to match the
generated function signatures:

- Add explicit `Cint(1)` pretty arg to metadata/attribute string calls
- Allocate shape buffers at call sites instead of inside the wrapper
- Pass explicit ndim and byte counts to subset/chunk I/O functions
- Pass explicit ndim to array_resize and erase_chunk
- Wrap Int() around get_dimensionality return (Csize_t → Int)
- Wrap Bool() around session_has_changes return (Int32 → Bool)

All 190 tests pass with zero regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant