Returning any struct that implements trait in no_std with heapless crate

First, thank you all for the amazing help recently.

I understand my problem and why its not working, but I can't find a solution. I'm thinking it may be time to re architecture, but I don't know which way to go.

The simplest form is a Factory::make() method that returns one of many structs that implement a trait. The structs are all of different sizes (my problem)

In a std environment, this is straightforward with Box<dyn MyTrait>. But w/o the allocator, I have no Box.

I used heapless::Box, but am getting an error. Likely because what I want is impossible or I am not using Box right.

Here is the simplest version to produce the error. This isn't even trying to build a box, just return an error and get it to compile.

#![no_std]

trait IsHeader {}

struct MyHeader {}
impl IsHeader for MyHeader {}

struct SecondHeader {}
impl IsHeader for SecondHeader {}

struct Factory {}
impl Factory
{
    fn make(x: i32) -> Result<Box<dyn IsHeader>, i32>
    {
        // if x == 1 {
        //     @todo: How do I create a box?
        // } else if x == 2 {
        //     return Ok(Box::??(SecondHeader {}));
        // } else {
               return Err(500);
        // }
    }
}

fn main() -> ! {
    let header = Factory::make(1);
}

Obviously that snippet won't run w/o setting up the no_std target, but I think it shows the issue.

the error is:

error[E0277]: the size for values of type `(dyn IsHeader + 'static)` cannot be known at compilation time
   --> src/main.rs:42:24
    |
42  |     fn make(x: i32) -> Result<Box<dyn IsHeader>, i32>
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    | 
   /heapless-0.7.9/src/pool/mod.rs:434:16
    |
434 | pub struct Box<T, STATE = Init> {
    |                - required by this bound in `heapless::pool::Box`
    |
    = help: the trait `Sized` is not implemented for `(dyn IsHeader + 'static)`

Which is telling me what I expect -- It doesn't know how big the return value from make() will be. I get that. I am happy to pre-allocate some Boxed value or something that is a max size for all the structs it could possible return. It's a pretty small set.

Do I have a path forward here? I didn't find anything on heapless except the documentation heapless - Rust, which is great, but doesn't have a Box example.

Thanks a ton.

2 Likes

I don't have experience with heapless, but structures default to sized parameters, and that Box does not specify T: ?Sized.

Do you really need to return any type implementing that trait, or is it a known list? Because if you know the possible types, you can make an enum with each variant.

1 Like

Without a heap, you can store things on the stack or you can put them in some other non-stack memory, like in some static memory or the like. With the former, you can take a closure which accepts a &dyn reference and call the closure. With the latter, you can create &'static dyn references. lazy_static can help with this.

Examples.

1 Like

This was really helpful. @quinedot I marked your answer as the solution. I integrated it into my project and it worked perfectly.

But I ended up taking @cuviper's advice. What I'm trying to accomplish is what enums were made for. It simplified my code and worked like a charm.

Thank you both.

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.