Expand description
Lightweight dynamic dispatch, intended for embedded use.
Ref<dyn Trait>
and RefMut<dyn Trait>
wrap a pointer and metadata necessary to call
trait methods, and Deref
into a tinydyn trait object that implements the Trait
.
Traits must currently opt-in by annotating with tinydyn
.
This defines an alternate, lighter weight vtable, and if the trait has one method, eliminates
it entirely by putting the function pointer inline.
This does not affect normal behavior of the trait, and can still be made into a dyn Trait
.
This, however, would be wasteful.
Example
use tinydyn::{tinydyn, Ref, RefMut};
#[tinydyn]
trait Spam {
fn ham(&mut self) -> i32;
fn eggs(&self) -> i32 { 10 }
}
impl Spam for i32 {
fn ham(&self) -> i32 {
*self += 2;
*self - 1
}
}
let mut x = 15;
// Like upcasting to `&dyn Foo`, but with a lighter weight vtable.
let mut mutable: RefMut<dyn Foo> = RefMut::new(&mut x);
assert_eq!(mutable.ham(), 16);
assert_eq!(mutable.eggs(), 10);
// mutable.into() would instead consume and have the same lifetime as `mutable`
let shared: Ref<dyn Foo> = mutable.as_ref();
assert_eq!(shared.eggs(), 10);
// Cannot call `shared.ham()` as it's a shared ref and can't call `&mut self` methods.
assert_eq!(x, 17);
Planned features
⚠️ This library is not yet tested enough to be production ready ⚠️
-
&self
and&mut self
methods -
+ Send
and+ Sync
trait objects -
lifetime
where
bounds on methods - lifetime generics on methods
- implementing on foreign traits/custom vtables
-
implementations for common
core
/std
traits (nevercore::fmt::{Debug, Display}
as they use&dyn
) - generics on the trait
- associated types
-
supertraits
-
upcasting
Ref<dyn Subtrait>
toRef<dyn Supertrait>
-
upcasting
-
Pin<&mut self>
and similar non-reference object-safe receivers -
where
bounds on the trait -
where Self: Sized
methods (and appropriate exclusion from the vtable)- non-lifetime generics on methods
-
non-lifetime
where
bounds on methods -
An attribute to manually exclude a method from a vtable, necessary for bounds
including subtraits or aliases of
Sized
-
An
tinydyn(inline_vtable[ = "all"])
attribute to force inlining of the vtable into the wide pointer. This would require the metadata type to always be carried in the trait. -
Put
Ref
vtables inline even ifRefMut
won’t. Ex: 1&self
and 1&mut self
method. - UI tests to ensure proper rejection and error message quality
Implementing on foreign traits
Implementing on foreign traits is not yet supported, and is an ergonomic and safety challenge
to get right, especially with regards to default methods.
As a workaround, you can create a local helper trait that contains the desired methods and
blanket implements for all T: TargetTrait
.
This functionality might be added by tinydyn in the future, or a better solution like defining
custom local vtables for foreign traits.
Traits with supertraits that wish to use this version of tinydyn
have a similar workaround.
Design
See the README for how this library is designed and works.
Structs
- A shared reference to a tinydyn trait object.
- A mutable reference to a tinydyn trait object.
Traits
- Builds the tinydyn trait metadata for a given type.
- A trait object that works with
tinydyn
, including any extra bounds. - Types that could be cast to the given
Trait
trait object. - A trait object supported by
tinydyn
.