E0038 and E0599: Box does not satisfy std::marker::Sized

⚓ Rust    📅 2026-03-27    👤 surdeus    👁️ 2      

surdeus

I've been trying to fix this error for some time and I've come to the conclusion that it must be a concept error on my part, so please be patient and tell me where I'm making the wrong assumptions.

I want to write a pattern that I've implemented in lots of other languages: I have some objects with the same interface (in Rust, they implement the same trait) and want to add them to a collection to work with them dynamically. Here's the trait:

use nusb::Interface;
use std::io;

// Just in case, here's nusb::Interface:
//     #[derive(Clone)]
//     pub struct Interface {
//         backend: Arc<platform::Interface>,
//     }

pub struct Mouse {
    iface: Interface,
}

pub trait Action {
    fn help(&self) -> Vec<String>;
    fn run(&self, mouse: Mouse, args: &[String]) -> io::Result<()>;
}

Then, I implement this trait in two modules. The first does nothing yet, but does implement the trait:

pub struct Help;

impl Action for Help {
    fn help(&self) -> Vec<String> {
        vec![]
    }

    fn run(&self, _: Mouse, _: &[String]) -> io::Result<()> {
        Ok(())
    }
}

I don't think the implementation details are relevant here, but just in case, here's the second struct's full implementation (Colour and Mouse elided):

use super::action::Action;
use crate::colour::Colour;
use crate::mouse::Mouse;

use std::io::{self, Error, ErrorKind};

const COLOUR_HINT: &str = "Elided...";
const HELP_HEAD: &str = r"Elided...";
const HELP_TAIL: &str = r#"Elided..."#;

pub struct Solid;

impl Action for Solid {
    fn help(&self) -> Vec<String> {
        let mut lines = vec![String::from(HELP_HEAD)];

        Colour::available_colours()
            .iter()
            .for_each(|(name, colour)| lines.push(format!("  - {}: {}", name, colour)));

        lines.push(String::from(HELP_TAIL));
        lines
    }

    fn run(&self, mouse: Mouse, args: &[String]) -> io::Result<()> {
        let Some(colour_name) = args.first() else {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                format!("Expected colour name or value.\n{}", COLOUR_HINT),
            ));
        };

        let Some(colour) = Colour::from_str(colour_name) else {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                format!("Unknown colour '{}'.\n{}", colour_name, COLOUR_HINT),
            ));
        };

        mouse.disable_onboard_memory()?;
        mouse.set_solid_colour(&colour)
    }
}

Now, I want to make a map with each of these structs so we can reference them by name. Again, this is a common pattern I'm well used to, so it may be here where I'm having the big concept error. Here's the map implementation:

pub struct Actions {
    actions: HashMap<&'static str, Box<dyn Action>>,
}

impl Actions {
    pub fn new() -> Self {
        Self {
            actions: HashMap::from_iter([
                ("help", Box::<dyn Action>::new(Help)),
                ("solid", Box::<dyn Action>::new(Solid))
            ]),
        }
    }

    pub fn run(&self, name: &str, mouse: Mouse, args: &[String]) -> Option<io::Result<()>> {
        match self.actions.get(name) {
            Some(action) => Some(action.run(mouse, args)),
            None => None,
        }
    }
}

As I understand, we cannot know the size of a dyn Action at compile time, so we have to store a ptr to it. To do so, we wrap the action object in a Box, same way it works in C++ by working with std::vector<std::unique_ptr<MyVirtualClass>>, for example. This should work automatically, but then I get this compiler error:

error[E0599]: the function or associated item `new` exists for struct `Box<dyn Action>`, but its trait bounds were not satisfied
    --> src/actions.rs:21:45
     |
  21 |                 ("help", Box::<dyn Action>::new(Help)),
     |                                             ^^^ function or associated item cannot be called on `Box<dyn Action>` due to unsatisfied trait bounds
     |
    ::: src/actions/action.rs:4:1
     |
   4 | pub trait Action {
     | ---------------- doesn't satisfy `dyn Action: Sized`
     |
note: if you're trying to build a new `Box<dyn Action>` consider using one of the following associated functions:
      Box::<T>::from_raw
      Box::<T>::from_non_null
      Box::<T, A>::from_raw_in
      Box::<T, A>::from_non_null_in
    --> /home/groctel/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:1044:5
     |
1044 |     pub unsafe fn from_raw(raw: *mut T) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1098 |     pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1271 |     pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1324 |     pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: the following trait bounds were not satisfied:
             `dyn Action: Sized`

error[E0599]: the function or associated item `new` exists for struct `Box<dyn Action>`, but its trait bounds were not satisfied
    --> src/actions.rs:22:46
     |
  22 |                 ("solid", Box::<dyn Action>::new(Solid))
     |                                              ^^^ function or associated item cannot be called on `Box<dyn Action>` due to unsatisfied trait bounds
     |
    ::: src/actions/action.rs:4:1
     |
   4 | pub trait Action {
     | ---------------- doesn't satisfy `dyn Action: Sized`
     |
note: if you're trying to build a new `Box<dyn Action>` consider using one of the following associated functions:
      Box::<T>::from_raw
      Box::<T>::from_non_null
      Box::<T, A>::from_raw_in
      Box::<T, A>::from_non_null_in
    --> /home/groctel/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:1044:5
     |
1044 |     pub unsafe fn from_raw(raw: *mut T) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1098 |     pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1271 |     pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1324 |     pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: the following trait bounds were not satisfied:
             `dyn Action: Sized`

For more information about this error, try `rustc --explain E0599`.

Reading about E0599 doesn't give me much information. After some digging, I found about E0038 which I read but it didn't help me understand why my particular code is failing. Then I went and read the Dyn compatibility section in the Rust Reference and for what I read, it seems that my trait should be dyn compatible? I don't find any of the incompatibilities listed in the reference applying to my trait.

I haven't tried the unsafe functions suggested by the compiler yet, as I am almost sure that this fairly simple code should be 100% safe... right?

So my questions are:

  • Which of my assumptions of how traits work in Rust are wrong?
  • How can I make this code compile and run, ideally without unsafe blocks?
  • Is there a better, rustier way of building a structure like this?

Thanks :slight_smile:

4 posts - 3 participants

Read full topic

🏷️ Rust_feed