Skip to content

Idiomatic and FFI Safe dyn traits in Rust

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

outfoxxed/dyntable

Repository files navigation

dyntable

crates.io docs.rs

Idiomatic and FFI Safe dyn traits.

Overview

This crate is an alternative implementation of Rust trait objects that aims to get around one main limitation: The ABI of trait objects is unspecified.

Usually this limitation is not an issue because the majority of rust code is statically linked, but it means trait objects are largely useless for a variety of situations such as:

  • Implementing a plugin system
  • Interacting with C, or any other language
  • Dynamic linking
  • On the fly codegen

This crate implements idiomatic trait objects, implemented using fat pointers similar to native rust traits, with support for trait bounds (inheritance) and upcasting. Implementing dyntable traits works exactly the same as normal rust traits.

Notable features

  • Uses fat pointers internally
  • Trait bounds and trait upcasting
  • Custom allocator support (optionally using std's allocator_api)
  • Uses existing dyn syntax
  • Only one annotation macro required per trait
  • Extensive testing
  • Passes Miri

Examples

Below is a simple example from the docs

use dyntable::*;

#[dyntable]
trait MessageBuilder {
    // Note that String is not FFI safe, but is used here for simplicity.
    extern "C" fn build(&self) -> String;
}

struct Greeter(&'static str);

impl MessageBuilder for Greeter {
    extern "C" fn build(&self) -> String {
        format!("Hello {}!", self.0)
    }
}

let greeter = Greeter("World");

// move the greeter into a DynBox of MessageBuilder. This box can hold any
// object safe MessageBuilder implementation.
let greeter_box = DynBox::<dyn MessageBuilder>::new(greeter);

// methods implemented on a dyntrait are callable directly from the DynBox.
assert_eq!(greeter_box.build(), "Hello World!");

Stability

This crate is somewhat early in development. Things most likely won't break if you stick to the non-internal types (pointer, ref, box, the macro), but more internal ones may. A semver bump will be required for breaking interface changes.

Alternatives

A few other crates may suit your needs better than dyntable. There is a comparison in COMPARISON.md