2

Consider such code:

trait Foo {
    fn foo(&self);
}

fn consume_func(b: Box<Box<Foo>>) {
    unimplemented!();
}

fn produce_func() -> Box<Box<Foo + Send>> {
    unimplemented!();
}

fn main() {
    let b = produce_func();
    consume_func(b);
}

It doesn't compile:

error[E0308]: mismatched types
  --> src/main.rs:24:18
   |
24 |     consume_func(b);
   |                  ^ expected trait `Foo`, found trait `Foo + std::marker::Send`
   |
   = note: expected type `std::boxed::Box<std::boxed::Box<Foo + 'static>>`
              found type `std::boxed::Box<std::boxed::Box<Foo + std::marker::Send>>`

The double Box is a way to give a C library a void * pointer from Box<Trait>. Because of fat pointers, I can not convert Box<Foo> to void *.

I can not change consume_func, and I'd prefer to not use unsafe or additional allocation.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1244932
  • 7,352
  • 5
  • 46
  • 103

2 Answers2

4

Here's one way to do it: dereference b ("un-boxing" it to a Box<Foo + Send>), then wrap it up immediately in another Box<T>, allowing the compiler to infer the correct T (in this case Box<Foo>).

consume_func(Box::new(*b));

This works because Box<Foo + Send> can be automatically coerced to Box<Foo>, but Box<Box<Foo + Send>> cannot be coerced to Box<Box<Foo>>.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
trent
  • 25,033
  • 7
  • 51
  • 90
2

Although you've stated you cannot change consume_func, others with similar issues can change it to accept a generic:

fn consume_func<F: Foo + ?Sized>(b: Box<Box<F>>) {
    unimplemented!();
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366