Skip to content

Instantly share code, notes, and snippets.

@derrickturk
Created October 8, 2020 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save derrickturk/fbadf6d97c0ff3d76937e756a12fb4b0 to your computer and use it in GitHub Desktop.
Save derrickturk/fbadf6d97c0ff3d76937e756a12fb4b0 to your computer and use it in GitHub Desktop.
Arcane vtable hacks in Rust: working with generic traits, dynamically
#![feature(raw)]
// tested with rustc 1.49.0-nightly (91a79fb29 2020-10-07)
use std::{
any::{Any, TypeId},
collections::HashMap,
mem,
raw::TraitObject,
};
trait Factory<T> {
fn make(&self) -> T;
}
trait DynamicFactory {
fn menu(&self) -> HashMap<TypeId, *mut ()>;
}
fn try_make<T: Any>(fac: &dyn DynamicFactory) -> Option<T> {
let raw: TraitObject = unsafe { mem::transmute(fac) };
let vtable = *fac.menu().get(&TypeId::of::<T>())?;
let specific_fac: &dyn Factory<T> = unsafe {
mem::transmute(TraitObject { data: raw.data, vtable })
};
Some(specific_fac.make())
}
struct A;
impl Factory<i32> for A {
fn make(&self) -> i32 {
17
}
}
impl Factory<f64> for A {
fn make(&self) -> f64 {
-23.7
}
}
// macrotize this stuff
impl DynamicFactory for A {
fn menu(&self) -> HashMap<TypeId, *mut ()> {
let mut result = HashMap::new();
{
let fac: &dyn Factory<i32> = self;
let raw: TraitObject = unsafe { mem::transmute(fac) };
result.insert(TypeId::of::<i32>(), raw.vtable);
}
{
let fac: &dyn Factory<f64> = self;
let raw: TraitObject = unsafe { mem::transmute(fac) };
result.insert(TypeId::of::<f64>(), raw.vtable);
}
result
}
}
fn main() {
let df: &dyn DynamicFactory = &A;
dbg!(try_make::<i32>(df));
dbg!(try_make::<f64>(df));
dbg!(try_make::<String>(df));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment