Downcasting a Box<dyn ForeignTrait> inside a struct? - rust

I'm having some dificulty wrapping my head around downcasting.
I have a struct which contains a Boxed trait, for example:
struct MyContainer {
reader: Box<dyn std::io::Read>,
}
How could I downcast the reader to my known type?
Here is a minimal example of what I'm trying to do:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=14b44be2412342d851d3c83fd9e080b0
Normally, I'd create a as_any(&self) on the trait which would result in a &dyn Any but this is a foreign trait which I do not own.

Define your own trait which has both Any and Read as supertraits, then use that as the dyn type.
trait DowncastableRead: Read + Any {
fn as_any(&self) -> &dyn Any;
}
impl<T: Read + Any> DowncastableRead for T {
fn as_any(&self) -> &dyn Any {
self
}
}
struct MyContainer {
reader: Box<dyn DowncastableRead>,
}
With these changes, your desired code will run.
There's no way to avoid defining your own trait, because dyn requires specifying exactly one non-auto trait (carries one vtable pointer), to get the functionality of Read and the functionality of Any, you need to define a trait that combines them (and defines a vtable that supports both sets of methods).

Related

How to create a factory method in rust to return generic container - getting an error "doesn't have a size known at compile-time" returning generic

I have a container type like this:
struct Container<T: Sized + MyTrait + Serialize> {
data: T,
key: String
}
wrapping this trait:
trait MyTrait {
fn do_something(&self) -> Something;
}
I have many concrete implementors of MyTrait:
struct S1 {}
impl MyTrait for S1 { ... };
... many kinds ...
struct S10{}
impl MyTrait for S10 { ... }
I have a higher level which should vend the appropriate implementation based on some decision logic (a factory of MyTrait types):
fn get_appropriate_impl(type_of_instance: SomeEnum ... ) -> Container<MyTrait> {
...choose appropriate implementation to return...
return match type_of_instance {
// each branch should return a different type
}
}
I get an error
Container<MyTrait> {
doesn't have a size known at compile-time
I've tried many variations:
Container<Box<MyTrait>>
Box<Container<MyTrait>>
Box<Container<Box<MyTrait>>
each has their own errors
How do I resolve this?
PS - I've also implemented Deref and DerefMut on Container:
impl<T: MyTrait > Deref for Container<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
You are trying to return a trait, not an object. The size of an implementation of a trait is not known at compile time (imagine, you implement MyTrait for u8 and u16, what size the return type would have?). The Sized bound does not help here (and it's implicit, too), because it only requires that T is Sized, but not MyTrait. Also, adding a bound to MyTrait: Sized does not help because it only requires, that the object, you implement MyTrait for, is sized, but it does not specify which size it may have.
This can be solved by either returning a concrete type, which is implementing MyTrait or wrapping the trait (e.g. in a Box). You are probably looking for the latter approach.
Returning a concrete type can be either done by adding a generic argument to the function:
fn get_appropriate_impl<T: MyTrait>() -> Container<T> {
...
}
or by using the impl Trait notation:
fn get_appropriate_impl() -> Container<impl MyTrait> {
...
}
However, if you don't know the return type beforehand, you probably want to store the object on the heap and return a pointer to that, e.g. by using Box, Rc, or Arc:
fn get_appropriate_impl() -> Container<Box<dyn MyTrait>> {
...
}
This requires you to implement MyTrait on Box<dyn MyTrait> as well, this can be done by implementing it on Box yourself:
impl MyTrait for Box<dyn MyTrait> {
fn do_something(&self) -> Something {
(**self).do_something()
}
}
If you know that you will only use Box for Container<T> you might want to encapsulate it there directly:
struct Container {
data: Box<dyn MyTrait>,
}

Understanding "the trait X cannot be made into an object" for `&mut Box<Self>` parameter

I've got this code snippet (playground):
struct TeddyBear {
fluffiness: u8,
}
trait Scruffy {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy>;
}
impl Scruffy for TeddyBear {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy> {
// do something about the TeddyBear's fluffiness
}
}
It doesn't compile. The error is:
the trait Scruffy cannot be made into an object
, along with the hint:
because method scruff_up's self parameter cannot be dispatched on.
I checked the "E0038" error description, but I haven't been able to figure out which category my error falls into.
I also read the "object-safety" entry in "The Rust Reference", and I believe this matches the "All associated functions must either be dispatchable from a trait object", but I'm not sure, partly because I'm not sure what "receiver" means in that context.
Can you please clarify for me what's the problem with this code and why it doesn't work?
The problem is when you pass it in as a reference, because the inner type may not be well-sized (e.g. a trait object, like if you passed in a Box<Fluffy>) the compiler doesn't have enough information to figure out how to call methods on it. If you restrict it to sized objects (like your TeddyBear) it should compile
trait Scruffy {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy> where Self: Sized;
}
A receiver is the self (&self, &mut self, self: &mut Box<Self> and so on).
Note that the list you cited from the reference lists both Box<Self> and &mut Self, but does not list &mut Box<Self> nor it says that combinations of these types are allowed.
This is, indeed, forbidden. As for the why, it is a little more complex.
In order for a type to be a valid receiver, it needs to hold the following condition:
Given any type Self that implements Trait and the receiver type Receiver, the receiver type should implement DispatchFromDyn<dyn Trait> for itself with all Self occurrences of Self replaced with dyn Trait.
For instance:
&self (has the type &Self) has to implement DispatchFromDyn<&dyn Trait>, which it does.
Box<Self> has to implement DispatchFromDyn<Box<dyn Trait>>, which it does.
But in order for &mut Box<Self> to be an object-safe receiver, it would need to impl DispatchFromDyn<&mut Box<dyn Trait>>. What you want is kind of blanket implementation DispatchFromDyn<&mut T> for &mut U where U: DispatchFromDyn<T>.
This impl will never exist. Because it is unsound (even ignoring coherence problems).
As explained in the code in rustc that calculates this:
The only case where the receiver is not dispatchable, but is still a valid receiver type (just not object-safe), is when there is more than one level of pointer indirection. E.g., self: &&Self, self: &Rc<Self>, self: Box<Box<Self>>. In these cases, there is no way, or at least no inexpensive way, to coerce the receiver from the version where Self = dyn Trait to the version where Self = T, where T is the unknown erased type contained by the trait object, because the object that needs to be coerced is behind a pointer.
The problem is inherent to how Rust handles dyn Trait.
dyn Trait is a fat pointer: it is actually two words sized. One is a pointer to the data, and the other is a pointer to the vtable.
When you call a method on dyn Trait, the compiler looks up in the vtable, find the method for the concrete type (which is unknown at compilation time, but known at runtime), and calls it.
This all may be very abstract without an example:
trait Trait {
fn foo(&self);
}
impl Trait for () {
fn foo(&self) {}
}
fn call_foo(v: &dyn Trait) {
v.foo();
}
fn create_dyn_trait(v: &impl Trait) {
let v: &dyn Trait = v;
call_foo(v);
}
The compiler generates code like:
trait Trait {
fn foo(&self);
}
impl Trait for () {
fn foo(&self) {}
}
struct TraitVTable {
foo: fn(*const ()),
}
static TRAIT_FOR_UNIT_VTABLE: TraitVTable = TraitVTable {
foo: unsafe { std::mem::transmute(<() as Trait>::foo) },
};
type DynTraitRef = (*const (), &'static TraitVTable);
impl Trait for dyn Trait {
fn foo(self: DynTraitRef) {
(self.1.foo)(self.0)
}
}
fn call_foo(v: DynTraitRef) {
v.foo();
}
fn create_dyn_trait(v: &impl Trait) {
let v: DynTraitRef = (v as *const (), &TRAIT_FOR_UNIT_VTABLE);
call_foo(v);
}
Now suppose that the pointer to the value is behind an indirection. I'll use Box<&self> because it's simple but demonstrates the concept best, but the concept applies to &mut Box<Self> too: they have the same layout. How will we write foo() for impl Trait for dyn Trait?
trait Trait {
fn foo(self: Box<&Self>);
}
impl Trait for () {
fn foo(self: Box<&Self>) {}
}
struct TraitVTable {
foo: fn(Box<*const ()>),
}
static TRAIT_FOR_UNIT_VTABLE: TraitVTable = TraitVTable {
foo: unsafe { std::mem::transmute(<() as Trait>::foo) },
};
type DynTraitRef = (*const (), &'static TraitVTable);
impl Trait for dyn Trait {
fn foo(self: Box<DynTraitRef>) {
let concrete_foo: fn(Box<*const ()>) = self.1.foo;
let data: *const () = self.0;
concrete_foo(data) // We need to wrap `data` in `Box`! Error.
}
}
You may think "then the compiler should just insert a call to Box::new()!" But besides Box not being the only one here (what with Rc, for example?) and we will need some trait to abstract over this behavior, Rust never performs any hard work implicitly. This is a design choice, and an important one (as opposed to e.g. C++, where an innocent-looking statement like auto v1 = v; can allocate and copy 10GB by a copy constructor). Converting a type to dyn Trait and back is done implicitly: the first one by a coercion, the second one when you call a method of the trait. Thus, the only thing that Rust does for that is attaching a VTable pointer in the first case, or discarding it in the second case. Even allowing only references (&&&Self, no need to call a method, just take the address of a temporary) exceeds that. And it can have severe implications in unexpected places, e.g. register allocation.
So, what to do? You can take &mut self or self: Box<Self>. Which one to choose depends on whether you need ownership (use Box) or not (use a reference). And anyway, &mut Box<Self> is not so useful (its only advantage over &mut T is that you can replace the box and not just its contents, but when you do that that's usually a mistake).

What's the difference between `impl<T> Trait for T where T: Trait2` and `impl Trait for dyn Trait2`?

When extending traits defined in other crates, there seem to be two ways to default implement a new trait.
The original definition of a trait is
pub trait Trait1 {
fn f1(&self);
}
In order to extend the functionality of this trait, we define a trait Trait2,
pub trait Trait2 {
fn f2(&self);
}
Now, because we want the functionality to be available by default, we can implement the following
impl<T> Trait2 for T
where
T: Trait1,
{
pub fn f2(&self) {
self.f1()
}
}
impl Trait2 for dyn Trait1 {
pub fn f2(&self) {
self.f1()
}
}
What I have observed is that, when mixing with trait objects, both of these implementations are required.
I understand that the impl<T> one is for concrete classes where as other is for dyn objects. Is that correct? Is there any way to share the default implementation here for both of these types? In my scenario, I had to copy and paste the whole implementation with just the change of the first line.
If I understood your question correctly, just add the unsized (?Sized) bound to T:
impl<T> Trait2 for T where T: Trait1 + ?Sized
This implements Trait2 for unsized types (eg. dyn Trait1) that implement Trait1 as well. By default, all type parameters are sized, and hence do not match unsized types.
Playground

What does it mean to implement a trait for another trait?

I read this answer but I'm still confused.
How do you interpret impl B for dyn A {}?
trait A {
fn method_a(&self) {
println!("a");
}
}
trait B {
fn method_b(&self) {
println!("b")
}
}
impl B for dyn A {}
impl A for i32 {}
fn main() {
let x: &dyn A = &10;
x.method_b();
}
Playground
I can understand impl A for i32 {} because i32 is a concrete type. dyn A is not a concrete type (unsized, can't pass by value), and you cannot declare a dyn A but you can only declare a &dyn A. Should I interpret
// x.method_b();
(*x).method_b();
as *x is dyn A?
I can also declare impl B for &dyn A {}, so why I need impl B for dyn A {}? What's the use case?
Follow up: If I modify the code
fn main() {
let x: &dyn A = &10;
// have a B trait object over dyn A since
// dyn A implements B
let y: &dyn B = x;
}
It will fail and complain &dyn A is not &dyn B. I understand this is a reasonable complain but I provide the option for compiler to use impl B for dyn A {}. Apparently, the compiler doesn't consider that's an option.
You can't declare dyn A but you can declare &dyn A because dyn A is a trait object type while &dyn A is a pointer to an instance of type T that implements A.
Historically, a trait could be used as a type and a trait. For instance, these both work:
// Where B and A are traits
impl B for A {}
impl B for dyn A {}
Basically, dyn A is just a sugar over A to make it clearer that it is meant to be used as a trait object type. You don't implement a trait for another trait. You implement a trait for another trait object type.
&dyn A is a pointer instance to an instance of type T that implements A and a virtual method table (vtable), which contains all the baggage of methods of A that T implements. This vtable lookup is necessary when an instance of type T later calls A's implementation at runtime.
Therefore, dyn A is an unsized type while &dyn A is a pointer with a known size.
Trait object of type dyn A must be cast from a pointer to be used as a concrete type that implements A. For example, in the code example, i32 can be cast to a dyn A:
impl B for dyn A {}
impl A for i32 {}
fn main() {
let x: i32 = 10;
(&x as &dyn A).method_a();
(&x as &dyn A).method_b();
}
or it can be coerced by a function:
fn dispatch(a: &dyn A) {
a.method_b();
}
Because traits are dynamically sized types (DSTs), to use them as trait objects, we must put them behind some kind of pointer, like &dyn A or Box<dyn A> so it can point to a variable-sized value and access the vtable to call the implemented methods.
See also: What makes something a “trait object”?

How do I write a trait method that knows the implementor is [u8]?

I'm implementing a trait for &[u8] but I cannot use self in the trait implementation. I assume that the trait can not detect the type and I should use a where clause, but I don't know how can I use it without an implementor.
use std::fmt::Debug;
pub trait Xor: Debug {
fn xor(&self, key_bytes: &[u8]) -> &[u8] {
for n in &self[..] {
dbg!(n);
}
unimplemented!()
}
}
impl Xor for [u8] {}
fn main() {
let xa = b"1234";
xa.xor(b"123");
}
Playground
error[E0608]: cannot index into a value of type `&Self`
--> src/main.rs:5:19
|
5 | for n in &self[..] {
| ^^^^^^^^
There are two places you can write the body of a trait method:
inside the trait itself, as a provided method
inside an impl block.
If a method is not provided, it is required, which means all implementors have to write their own body in the appropriate impl block.
Provided methods can only use properties that are common to all the implementors of the trait, which means you can only use other trait methods or methods of supertraits (like : Debug). But methods in an impl block may use properties that are specific to the type implementing the trait. You want to use something specific to [u8] -- indexing via [..] -- so xor should be a required method:
pub trait Xor {
fn xor(&self, key_bytes: &[u8]) -> &[u8];
}
impl Xor for [u8] {
fn xor(&self, key_bytes: &[u8]) -> &[u8] {
for n in &self[..] {
dbg!(n);
}
unimplemented!()
}
}
Provided methods are usually for conveniences that only use other methods of the same trait, like most of the methods on Iterator (see Why don't we implement all the functions from Iterator to implement an iterator?).
is it possible to implement the trait for several kind of types [without writing multiple impl blocks]?
Yes, if there is a trait that exposes the functionality you would use to write Xor, you may use that trait to write a generic impl. For example, String and [u8] both implement AsRef<[u8]>, so you can use that to write an impl that applies to both:
impl<T: ?Sized + AsRef<[u8]>> Xor for T {
fn xor(&self, key_bytes: &[u8]) -> &[u8] {
for n in &self.as_ref()[..] {
dbg!(n);
}
unimplemented!()
}
}
Playground link.
See also
How does Rust know which trait methods are required or provided? for more on provided and required trait functions
What does the question mark mean in a type parameter bound? for what ?Sized means

Resources