There are definitively other ways to solve this problem but I was just curious whether there was any way to make the following code work in Rust in some way I do not know yet.
The following code sample (playground)
use std::sync::{Arc, Mutex};
trait ProvidesFoo {
fn magic(&mut self);
}
struct Foo {
magic_value: u32
}
impl Default for Foo {
fn default() -> Self {
Self {magic_value: 42}
}
}
impl ProvidesFoo for Foo {
fn magic(&mut self) {
println!("ProvidesFoo magic {}", self.magic_value);
}
}
pub type SharedFooConcrete = Arc<Mutex<Box<Foo>>>;
pub type SharedFooTraitObj = Arc<Mutex<Box<dyn ProvidesFoo + Send + Sync>>>;
struct FooProvider {
foo_as_trait_obj: SharedFooTraitObj
}
impl FooProvider {
fn magic_and_then_some(&mut self) {
let mut fooguard = self.foo_as_trait_obj.lock().unwrap();
fooguard.magic();
println!("Additional magic");
}
}
fn uses_shared_foo_boxed_trait_obj(foo: SharedFooTraitObj) {
let mut foo_provider = FooProvider {
foo_as_trait_obj: foo
};
foo_provider.magic_and_then_some();
}
fn uses_shared_foo_concrete(foo: SharedFooConcrete) {
let mut fooguard = foo.lock().unwrap();
fooguard.magic();
}
fn main() {
let shared_foo = Arc::new(Mutex::new(Box::new(Foo::default())));
uses_shared_foo_concrete(shared_foo.clone());
uses_shared_foo_boxed_trait_obj(shared_foo);
}
will fail to compile with the following error:
error[E0308]: mismatched types
--> fsrc-example/src/bin/test2.rs:52:37
|
52 | uses_shared_foo_boxed_trait_obj(shared_foo);
| ------------------------------- ^^^^^^^^^^ expected trait object `dyn ProvidesFoo`, found struct `Foo`
| |
| arguments to this function are incorrect
|
= note: expected struct `Arc<Mutex<Box<(dyn ProvidesFoo + Send + Sync + 'static)>>>`
found struct `Arc<Mutex<Box<Foo>>>`
note: function defined here
There is definitely a way to "cast" a boxed trait object back to its concrete type like shown here, but this is basically the other way around. I come from a C++ background, so I am familiar with this type of API where a derived object can be passed as a base class.
The other possible solution I mentioned and used was to have a wrapper struct which has the SharedFooTraitObject
as a field and implements the magic_and_then_some()
operation on top. One can then pass that wrapper struct around and clone the Arc<Mutex>
ed field for library code which expects only the trait object.
I was just curious whether this type of type coercion / casting is possible in Rust.
Kind Regards, RM