Returning an owned "dyn" object without heap allocations

Hello.

Is it possible to return an owned dyn Trait from a function without using heap-allocations, like Box or Arc?

In my case, the types implementing Trait are expected to be small, no more than N bytes, so I thought maybe it would be possible to return a type that reserves the needed N bytes, and stores a pointer to the dyn vtable, like so (just a high-level sketch):

trait MyTrait {}
struct MyType; // this is no more than 16 bytes
impl MyTrait for MyType {}

struct OnStack<T, const N: usize> {
    vtable: *mut T::Vtable,
    data: [u8; N],
}

fn my_function() -> OnStack<dyn MyTrait, 16> {
    OnStack::new(MyType::new()).expect("MyType is larger than 16 bytes")
}

Rust already uses space reservation for enums: the size of an enum is determined by the size of its largest variant. So maybe it’s also possible to do for other types with variable size, like `dyn Trait`?

Thanks!

I'm not aware of any existing implementations of that, but it would be possible to implement such an OnStack in unsafe code.

1 Like

A quick job yields no_alloc - Rust, though note I have not vetted it at all.

If you choose to write your own, you must remember to account for alignment.

2 Likes

That is exactly what I was looking for!

Here is the example code, also has a nice feature that it checks size and alignment requirements at compile time, so no need for runtime error checking:

use no_alloc::{boxed_s, BoxS};

trait MyTrait {
    fn hello(&self);
}

struct MyType {
    name: String,
}

impl MyTrait for MyType {
    fn hello(&self) {
        println!("Hello, {}!", self.name);
    }
}

type MyTraitLocal = BoxS<dyn MyTrait, [usize; 4]>;

fn my_function(name: &str) -> MyTraitLocal {
    boxed_s!(MyType {
        name: name.to_string()
    })
}

fn main() {
    let mytrait = my_function("Ferris");

    mytrait.hello();
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.