Allows trait values that are no larger than the specified size to be assigned on the stack

Similarly to the following, and provide a certain compiler support.

#![feature(ptr_metadata)]
#![feature(layout_for_ptr)]

use std::ops::{Deref, DerefMut};
use std::any::Any;

pub struct TraitValue<DynTrait: ?Sized, const MAX_SIZE: usize> {
    data: [u8; MAX_SIZE],
    metadata: <DynTrait as std::ptr::Pointee>::Metadata,
}

impl<DynTrait: ?Sized, const MAX_SIZE: usize> TraitValue<DynTrait, MAX_SIZE> {
    pub fn new(v: &DynTrait) -> Self {
        let ptr = v as *const DynTrait;
        assert!(unsafe { std::mem::size_of_val_raw(ptr) } <= MAX_SIZE);
        let data = unsafe { std::ptr::read(ptr as *const [u8; MAX_SIZE]) };
        let metadata = std::ptr::metadata(ptr);
        Self {
            data,
            metadata,
        }
    }
}

impl<DynTrait: ?Sized, const MAX_SIZE: usize> Drop for TraitValue<DynTrait, MAX_SIZE> {
    fn drop(&mut self) {
        unsafe { std::ptr::drop_in_place(self.deref_mut() as *mut DynTrait); }
    }
}

impl<DynTrait: ?Sized, const MAX_SIZE: usize> Deref for TraitValue<DynTrait, MAX_SIZE> {
    type Target = DynTrait;

    fn deref(&self) -> &Self::Target {
        unsafe { &*std::ptr::from_raw_parts(&self.data as *const _ as *const (), self.metadata) }
    }
}

impl<DynTrait: ?Sized, const MAX_SIZE: usize> DerefMut for TraitValue<DynTrait, MAX_SIZE> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *std::ptr::from_raw_parts_mut(&mut self.data as *mut _ as *mut (), self.metadata) }
    }
}

struct Foo {}

impl Drop for Foo {
    fn drop(&mut self) {
        println!("Drop");
    }
}

fn main() {
    let x = Foo {};
    let mut z = TraitValue::<dyn Any, 10usize>::new(&x as &dyn Any);
    std::mem::forget(x);

    println!("Test drop trait");
    drop(z);
}

Have you seen smallbox and other similar crates?

9 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.