#dylib #dlopen #ffi #binary-encoding

savefile-abi

Easy to use, simple, stable ABI for Rust-libraries. Allows creating dynamically loadable plugins written in rust.

32 releases

new 0.18.5 Dec 1, 2024
0.18.4 Nov 4, 2024
0.18.2 Oct 27, 2024
0.17.14 Oct 20, 2024
0.17.0-beta.15 Apr 30, 2024

#827 in Parser implementations

Download history 17/week @ 2024-09-13 7/week @ 2024-09-20 119/week @ 2024-09-27 222/week @ 2024-10-04 657/week @ 2024-10-11 469/week @ 2024-10-18 164/week @ 2024-10-25 266/week @ 2024-11-01 16/week @ 2024-11-08 4/week @ 2024-11-15 137/week @ 2024-11-29

170 downloads per month

MIT/Apache

445KB
9K SLoC

Welcome to Savefile-abi!

Full docs: https://docs.rs/savefile-abi/latest/

Savefile-abi is a crate that is primarily meant to help building binary plugins using Rust. It supports many data types from the standard library, as well as custom user types.

It supports async methods, through use of the #[async_trait] attribute macro.

savefile-abi = "0.18"
savefile = "0.18"
savefile-derive = "0.18"

Example

Let's say we have a crate that defines this trait for adding u32s:

interface_crate

use savefile_derive::savefile_abi_exportable;

#[savefile_abi_exportable(version=0)]
pub trait AdderInterface {
    fn add(&self, x: u32, y: u32) -> u32;
}

Now, we want to implement addition in a different crate, compile it to a shared library (.dll or .so), and use it in the first crate (or some other crate):

implementation_crate

use interface_crate::{AdderInterface};
use savefile_derive::savefile_abi_export;

#[derive(Default)]
struct MyAdder { }

impl AdderInterface for MyAdder {
    fn add(&self, x: u32, y: u32) -> u32 {
        x + y
    }
}

// Export this implementation as the default-implementation for
// the interface 'AdderInterface', for the current library.
savefile_abi_export!(MyAdder, AdderInterface);

We add the following to Cargo.toml in our implementation crate:

[lib]
crate-type = ["cdylib"]

Now, in our application, we add a dependency to interface_crate, but not to ImplementationCrate.

We then load the implementation dynamically at runtime:

app

use savefile_abi::{AbiConnection};
use interface_crate::{AdderInterface};


fn main() {
    // Load the implementation of `dyn AdderInterface` that was published
    // using the `savefile_abi_export!` above.
    let connection = AbiConnection::<dyn AdderInterface>
      ::load_shared_library("./ImplementationCrate.so").unwrap();

    // The type `AbiConnection::<dyn AdderInterface>` implements
    // the `AdderInterface`-trait, so we can use it to call its methods.
    assert_eq!(connection.add(1, 2), 3);
}

Limitations

There are multiple limitations:

  • Tuples are presently not supported as direct function arguments!
  • There may be safety issues, Savefile-Abi is not mature yet.

See full docs: https://docs.rs/savefile-abi/latest/

Dependencies

~2–7MB
~52K SLoC