https://github.com/ralfbiedert/interoptopus
The polyglot bindings generator for your library (C#, C, Python, …) 🐙
https://github.com/ralfbiedert/interoptopus
c csharp ffi python rust
Last synced: about 1 month ago
JSON representation
The polyglot bindings generator for your library (C#, C, Python, …) 🐙
- Host: GitHub
- URL: https://github.com/ralfbiedert/interoptopus
- Owner: ralfbiedert
- License: mit
- Created: 2021-06-13T22:13:10.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2025-05-12T07:01:22.000Z (about 1 month ago)
- Last Synced: 2025-05-12T08:22:50.027Z (about 1 month ago)
- Topics: c, csharp, ffi, python, rust
- Language: Rust
- Homepage:
- Size: 2.92 MB
- Stars: 407
- Watchers: 8
- Forks: 35
- Open Issues: 20
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
[![crates.io-badge]][crates.io-url]
[![docs.rs-badge]][docs.rs-url]
![license-badge]
[![rust-version-badge]][rust-version-url]
[![rust-build-badge]][rust-build-url]## Interoptopus 🐙
The polyglot bindings generator for your library.
Write a robust library in Rust, easily access it from your second-favorite language:
- Design a single `.dll` / `.so` in Rust, consume it from anywhere.
- Get `QoL` features (e.g., classes, strings) in languages that have them.
- Painless workflow, no external tooling required.
- Easy to support more languages, backends fully decoupled from main project.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.### Code you write ...
```rust
#[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()
}```
### ... Interoptopus generates
| Language | Crate | Sample Output1 | Status |
| --- | --- | --- | --- |
| C# | [**interoptopus_backend_csharp**](https://crates.io/crates/interoptopus_backend_csharp) | [Interop.cs](https://github.com/ralfbiedert/interoptopus/blob/master/tests/tests/csharp_reference_project/Interop.cs) | ✅ |
| C | [**interoptopus_backend_c**](https://crates.io/crates/interoptopus_backend_c) | [my_header.h](https://github.com/ralfbiedert/interoptopus/blob/master/tests/tests/c_reference_project/reference_project.h) | ⏯️ |
| Python | [**interoptopus_backend_cpython**](https://crates.io/crates/interoptopus_backend_cpython) | [reference.py](https://github.com/ralfbiedert/interoptopus/blob/master/tests/tests/cpython_reference_project/reference_project.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](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src).
2 Add basic support for a new language in just a few hours. [No pull request needed](https://github.com/ralfbiedert/interoptopus/blob/master/FAQ.md#new-backends).### Getting Started 🍼
If you want to ...
- **get started** see the [**hello world**](https://github.com/ralfbiedert/interoptopus/tree/master/examples/hello_world),
- **productify your project**, see the [**real project layout**](https://github.com/ralfbiedert/interoptopus/tree/master/examples/real_project_layout),
- **understand what's possible**, see the [**reference project**](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src),
- **support a new language**, [**copy the C backend**](https://github.com/ralfbiedert/interoptopus/tree/master/crates/backend_c).### Supported Rust Constructs
See the [**reference project**](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src) for an overview:
- [functions](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src/functions) (freestanding functions and delegates)
- [types](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src/types) (composites, enums, opaques, references, ...)
- [constants](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src/constants.rs) (primitive constants; results of const evaluation)
- [patterns](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src/patterns) (ASCII pointers, options, slices, ...)
- [services](https://github.com/ralfbiedert/interoptopus/tree/master/crates/reference_project/src/services) (turn to classes in C# and Python, and async methods)### Performance 🏁
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: 🔥
- [**C# call overhead**](https://github.com/ralfbiedert/interoptopus/blob/master/tests/tests/csharp_benchmarks/RESULTS.md)
- [**Python call overhead**](https://github.com/ralfbiedert/interoptopus/blob/master/tests/tests/cpython_benchmarks/RESULTS.md)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](https://github.com/ralfbiedert/interoptopus/blob/master/tests/tests/csharp_reference_project/Test.Pattern.Callbacks.cs).
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.
### Feature Flags
Gated behind **feature flags**, these enable:
- `derive` - Proc macros such as `ffi_type`, ...
- `serde` - Serde attributes on internal types.
- `log` - Invoke [log](https://crates.io/crates/log) on FFI errors.### Changelog
- **v0.15** - Massive cleanup, bugfix, UX overhaul (+syn2).
- **v0.14** - Better inventory UX.
- **v0.13** - Python backend uses `ctypes` now.Also see our [upgrade instructions](https://github.com/ralfbiedert/interoptopus/blob/master/UPGRADE_INSTRUCTIONS.md).
### FAQ
- [FAQ and Safety Guides](https://github.com/ralfbiedert/interoptopus/blob/master/FAQ.md).
### Contributing
PRs are very welcome!
- Submit small bug fixes directly. Major changes should be issues first.
- New features or patterns must be materialized in the reference project and accompanied by
at least an C# interop test.[crates.io-badge]: https://img.shields.io/crates/v/interoptopus.svg
[crates.io-url]: https://crates.io/crates/interoptopus
[license-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[docs.rs-badge]: https://docs.rs/interoptopus/badge.svg
[docs.rs-url]: https://docs.rs/interoptopus/
[rust-version-badge]: https://img.shields.io/badge/rust-1.85%2B-blue.svg?maxAge=3600
[rust-version-url]: https://github.com/ralfbiedert/interoptopus
[rust-build-badge]: https://github.com/ralfbiedert/interoptopus/actions/workflows/rust.yml/badge.svg
[rust-build-url]: https://github.com/ralfbiedert/interoptopus/actions/workflows/rust.yml