SparseIR C-API
C-compatible interface to the SparseIR Rust library.
Overview
This crate provides a libsparseir-compatible C API for the SparseIR library, designed as a drop-in replacement for the C++ implementation.
Language Support
- Julia β (tested)
- Python (via ctypes/cffi)
- Fortran (via ISO_C_BINDING)
- C/C++
Compatibility with libsparseir C++ π
This API is 100% compatible with the libsparseir C++ library:
| Feature | libsparseir C++ | sparse-ir-capi Rust | Status |
|---|---|---|---|
| Type name | spir_kernel |
spir_kernel |
β Identical |
| Function names | spir_logistic_kernel_new() |
spir_logistic_kernel_new() |
β Identical |
| Error codes | SPIR_COMPUTATION_SUCCESS, etc. |
Same codes | β Identical |
| Memory model | Opaque pointers | Opaque pointers | β Compatible |
| Function signature | spir_kernel* f(..., int* status) |
spir_kernel* f(..., int* status) |
β Identical |
Why choose Rust over C++?
- π Memory safety - No use-after-free, no double-free
- π‘οΈ Panic safety -
catch_unwind()prevents crashes - π Zero-cost abstractions - Same performance as C++
- π¦ Easy deployment - Single static library, no C++ runtime needed
Features
Currently Implemented β
- Kernel API (5 functions) - libsparseir compatible
spir_logistic_kernel_new()- Create LogisticKernelspir_reg_bose_kernel_new()- Create RegularizedBoseKernelspir_kernel_release()- Free kernelspir_kernel_get_lambda()- Get Ξ» parameterspir_kernel_compute()- Compute K(x, y)
Error Handling π‘οΈ
All C-API functions use catch_unwind() to prevent panics from crossing the FFI boundary:
- Returns error codes instead of panicking
- Process remains stable even on internal errors
- Safe for production use
Building
# Build shared library (.dylib on macOS, .so on Linux, .dll on Windows)
# The C header is automatically generated by cbindgen during build
# Run tests
Header Generation
The C header (include/sparseir.h) is automatically generated from Rust source code using cbindgen:
- Build time: Header is regenerated automatically when Rust sources change
- Manual regeneration:
cargo build(header is created bybuild.rs) - Configuration: See
cbindgen.tomlfor generation settings
Do not edit the generated header manually - edit the Rust source code instead!
Usage Examples
Julia
# Load library
const lib = "../target/release/libsparse_ir_capi.dylib"
# Create kernel
kernel_ptr = Ref{Ptr{Cvoid}}()
status = ccall((:spir_kernel_logistic_new, lib),
Int32, (Float64, Ref{Ptr{Cvoid}}),
10.0, kernel_ptr)
# Compute kernel value
result = Ref{Float64}()
status = ccall((:spir_kernel_compute, lib),
Int32, (Ptr{Cvoid}, Float64, Float64, Ref{Float64}),
kernel_ptr[], 0.5, 0.5, result)
println("K(0.5, 0.5) = ", result[])
# Release
ccall((:spir_kernel_release, lib), Cvoid, (Ptr{Cvoid},), kernel_ptr[])
See examples/test_julia.jl for a complete example.
C
int
Testing
Run the Julia example:
Memory Management
All objects returned by *_new() functions must be released with their corresponding *_release() function:
spir_kernel_release()- (more to come:
spir_basis_release(), etc.)
Error Codes
| Code | Name | Description |
|---|---|---|
0 |
SPIR_SUCCESS |
Operation succeeded |
-1 |
SPIR_ERROR_NULL_POINTER |
NULL pointer argument |
-2 |
SPIR_ERROR_INVALID_ARGUMENT |
Invalid argument value |
-99 |
SPIR_ERROR_PANIC |
Internal panic (bug) |
Implementation Status
- Kernel API (5/5 functions) β
- SVE API (0/10 functions)
- Basis API (0/15 functions)
- Sampling API (0/15 functions)
- DLR API (0/8 functions)
See C-API_IMPLEMENTATION_PLAN.md for details.
Architecture
ββββββββββββββββ
β Julia/Python β β High-level languages
ββββββββ¬ββββββββ
β ccall/ctypes
ββββββββΌββββββββ
β C-API β β This crate (FFI boundary)
β catch_unwind β β Panic protection
ββββββββ¬ββββββββ
β
ββββββββΌββββββββ
β sparseir-rustβ β Core Rust implementation
ββββββββββββββββ
Safety Features
- Input Validation - User errors return error codes (don't panic)
- Panic Catching -
catch_unwind()at FFI boundary prevents UB - Arc-based Sharing - Efficient memory management for large objects
- Type Safety - Opaque pointers hide implementation details
License
MIT