Crate interoptopus[][src]

Expand description

Interoptopus

Create FFI bindings to your favorite language. Composable. Escape hatches included.

Overview

  • you wrote an extern "C" API in Rust
  • the types at the FFI boundary are (mostly) owned by yourself
  • you prefer to keep all your binding-related information (e.g., documentation) in Rust code

Known limitations

  • not used in production yet
  • somewhat verbose if you don’t own most of your types (still possible, just more work)
  • if you target only a single language and don’t care about your FFI layer other solutions might be better

Supported Languages

LanguageCrateComment
C#interoptopus_backend_csharpBuilt-in.
Cinteroptopus_backend_cBuilt-in.
Python CFFIinteroptopus_backend_cpython_cffiBuilt-in.
Your languageWrite your own backend!See existing backends for what to do.*

(*) Ok, right now I don’t really recommend writing a new backend just yet as lots of internals might change. That said, it should only take a few hours and feedback is more than welcome.

Example

Slightly abridged, see the examples/hello_world for full code:

use interoptopus::{ffi_function, ffi_type};
use interoptopus_backend_csharp::Interop;

#[ffi_type]
#[repr(C)]
pub struct Vec2f32 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

/// A function which does something with the vector.
#[ffi_function]
#[no_mangle]
pub extern "C" fn my_game_function(input: Option<&Vec2f32>) -> Vec2f32 {
    Vec2f32 { x: 2.0, y: 4.0, z: 6.0 }
}

// This ultimately defines our FFI exports, all functions have to be listed here.
interoptopus::inventory_function!(ffi_inventory, [], [my_game_function]);

#[test]
fn generate_csharp_bindings() {
    use interoptopus::writer::IndentWriter;

    let library = ffi_inventory();

    let config = interoptopus_backend_csharp::Config {
        namespace: "My.Company".to_string(),
        class: "InteropClass".to_string(),
        dll_name: "hello_world".to_string(),
        ..interoptopus_backend_csharp::Config::default()
    };

    let generator = interoptopus_backend_csharp::Generator::new(config, library);

    generator.write_to(my_file)?;
}

With a Cargo.toml:

[dependencies]
interoptopus = { version = "0.1", features = ["derive"] }
interoptopus_backend_csharp = "0.1"

Will produce:

using System;
using System.Runtime.InteropServices;

namespace My.Company
{
    public static class InteropClass
    {
        public const string NativeLib = "hello_world";

        /// A function which does something with the vector.
        [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "my_game_function")]
        public static extern Vec2f32 my_game_function(ref Vec2f32 input);
    }

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public partial struct Vec2f32
    {
        public float x;
        public float y;
        public float z;
    }
}

For other languages (Python, C, …) see examples folder.

Modules

lang

Abstractions for authors of backends.

util

Helpers for backend authors.

writer

Types used by backends to produce pretty output.

Structs

Library

Represents all FFI-relevant items, produced via [crate::inventory_function], ingested by backends.

Enums

Error

Can be observed if something goes wrong.