Idiomatic and FFI Safe dyn traits.
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.
- 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
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!");
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.
A few other crates may suit your needs better than dyntable. There is a comparison in COMPARISON.md