Skip to content

Instantly share code, notes, and snippets.

@abonander
Created June 21, 2019 19:45
Show Gist options
  • Save abonander/40cff87913c63001d9d4479d6ce3409c to your computer and use it in GitHub Desktop.
Save abonander/40cff87913c63001d9d4479d6ce3409c to your computer and use it in GitHub Desktop.
Prototype for stack-based trait objects in Rust, ICEs as of rustc 1.37.0-nightly (b25ee6449 2019-06-17)
#![feature(const_generics, raw, unsize)]
use std::marker::{PhantomData, Unsize};
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::raw::TraitObject;
#[repr(align(64))] // ensures minimum alignment for all native types
pub struct StackTraitObj<T: ?Sized, const SIZE: usize> {
storage: [u8; SIZE],
vtable: *mut (),
type_: PhantomData<T>,
}
// we have to express that `U` can coerce to `T` and that's with the unstable `Unsize` marker
impl<T: ?Sized, const SIZE: usize> StackTraitObj<T, {SIZE}> {
pub fn new<U: Unsize<T>>(val: U) -> StackTraitObj<T, {SIZE}> {
assert!(mem::size_of::<U>() <= SIZE);
let mut storage = [0u8; SIZE];
unsafe {
let vtable = mem::transmute::<&T, TraitObject>(&val).vtable;
ptr::copy_nonoverlapping(&val as *const _ as *const u8, storage.as_mut_ptr(), SIZE);
StackTraitObj {
storage,
vtable,
type_: PhantomData,
}
}
}
}
impl<T: ?Sized, const SIZE: usize> Deref for StackTraitObj<T, {SIZE}> {
type Target = T;
fn deref(&self) -> &T {
unsafe {
mem::transmute(
TraitObject {
data: self.storage.as_mut_ptr() as *mut (),
vtable: self.vtable
}
)
}
}
}
fn main() {
let stack_trait_obj: StackTraitObj<dyn ToString, 4> = StackTraitObj::new(255i32);
println!("{}", stack_trait_obj.to_string());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment