Sometimes one might need to create an object at run-time that implements a Rust trait. This is one way to do so, provided the trait to be implemented is known statically.
Here's how:
- Define a struct that will hold the implementation of each trait method.
- Define a second "object" struct that holds a "self" value and a reference to an implementation struct.
- Implement the desired trait for the object struct, dispatching to the function pointers in the implementation struct.
An example:
// example trait
trait Greeter {
fn greet(&self) -> String;
}
// make a wrapper struct
struct GreeterImpl<T> {
// all the implementation function pointers go here
greet_fn: fn(&T) -> String,
}
impl<T> GreeterImpl<T> {
fn create_instance(&self, slf: T) -> GreeterObject<T> {
GreeterObject { slf, impl_: self }
}
}
struct GreeterObject<'a, T> {
slf: T,
impl_: &'a GreeterImpl<T>,
}
impl<'a, T> Greeter for GreeterObject<'a, T> {
fn greet(&self) -> String {
(self.impl_.greet_fn)(&self.slf)
}
}
This means you can JIT-compile the implementation of a trait's methods and then create objects that implement the trait dynamically.
Obviously this means that the implementations of the trait methods will be called indirectly (through a function pointer) and cannot be inlined by the compiler.