Created
June 21, 2019 19:45
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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