| Crates.io | interoptopus |
| lib.rs | interoptopus |
| version | 0.15.0-alpha.17 |
| created_at | 2021-06-13 22:31:40.919978+00 |
| updated_at | 2025-09-17 16:56:45.19961+00 |
| description | The polyglot bindings generator for your library (C#, C, Python, ...). 🐙 |
| homepage | |
| repository | https://github.com/ralfbiedert/interoptopus |
| max_upload_size | |
| id | 409699 |
| size | 227,595 |
The polyglot bindings generator for your library.
Write a robust library in Rust, easily access it from your second-favorite language:
.dll / .so in Rust, consume it from anywhere.QoL features (e.g., classes, strings) in languages that have them.We strive to make our generated bindings zero cost. They should be as idiomatic as you could have reasonably written them yourself, but never magic or hiding the interface you actually wanted to expose.
#[ffi_type]
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
#[ffi_function]
pub fn my_function(input: Vec2) {
println!("{}", input.x);
}
// List functions you want to export, types are inferred.
pub fn ffi_inventory() -> Inventory {
InventoryBuilder::new()
.register(function!(my_function))
.validate()
.build()
}
| Language | Crate | Sample Output1 | Status |
|---|---|---|---|
| C# | interoptopus_backend_csharp | Interop.cs | ✅ |
| C | interoptopus_backend_c | my_header.h | ⏯️ |
| Python | interoptopus_backend_cpython | reference.py | ⏯️ |
| Other | Write your own backend2 | - |
✅ Tier 1 target. Active maintenance and production use. Full support of all features.
⏯️ Tier 2 target. Might be missing features or UX, contributors wanted!
1 For the reference project.
2 Add basic support for a new language in just a few hours. No pull request needed.
If you want to ...
See the reference project for an overview:
functions (freestanding functions and delegates)
types (composites, enums, opaques, references, ...)
constants (primitive constants; results of const evaluation)
patterns (ASCII pointers, options, slices, ...)
services (turn to classes in C# and Python, and async methods)
Generated low-level bindings are zero cost w.r.t. hand-crafted bindings for that language.
That said, even hand-crafted bindings encounter some target-specific overhead at the FFI boundary (e.g., marshalling, pinning, and safety checks). For C# that cost is often nanoseconds, for Python it can be microseconds.
Detailed call cost tables can be found here: 🔥
For a quick overview, this table lists some common round trip times in ns / call:
| Construct | C# | Python |
|---|---|---|
primitive_void() |
3 | (TODO) |
primitive_u64(0) |
4 | |
pattern_option(Option.None) |
14 | |
pattern_delegate_adhoc(x => x[0]) |
477 1 | |
pattern_delegate_retained(delegate) |
21 | |
pattern_ascii_pointer("hello world") |
20 | |
pattern_utf8_string("hello world") |
52 | |
await serviceAsync.Success() |
361 2 |
1 First time delegate creation and pinning is expensive in C# (100's of ns). We
recommend you retain the delegate instead for >20x faster calls, see for example here.
2 Preliminary numbers for full round trip to tokio and back. Although async calls have some intrinsic overhead
(e.g., spawning a new TaskCompletionSource is ~100ns), some of that overhead appears to be a
benchmarking effect when spin-waiting for a newly spawned task. In essence, if your application
benefits from async this overhead is negligible, but simple getters or setters shouldn't needlessly be made async.
Gated behind feature flags, these enable:
derive - Proc macros such as ffi_type, ...
serde - Serde attributes on internal types.
log - Invoke log on FFI errors.
ctypes now.Also see our upgrade instructions.
PRs are very welcome!