Hi, I have an object map that owns one boxed object per type, indexed by a tag. A simplified version of the code is this:
use std::any::Any;
use std::collections::HashMap;
trait Object {
fn tag() -> u8;
}
struct ObjectMap {
map: HashMap<u8, Box<dyn Any>>,
}
impl ObjectMap {
fn new() -> ObjectMap {
ObjectMap {
map: HashMap::default(),
}
}
fn register<OBJ: Object + 'static>(&mut self, o: Box<OBJ>) {
self.map.insert(OBJ::tag(), o);
}
fn get_by_tag<OBJ: Object + 'static>(&self, id: u8) -> Option<&OBJ> {
self.map.get(&id).map(|v| v.downcast_ref().unwrap())
}
fn get_mut_by_tag<OBJ: Object + 'static>(&mut self, id: u8) -> Option<&mut OBJ> {
self.map.get_mut(&id).map(|v| v.downcast_mut().unwrap())
}
fn get<OBJ: Object + 'static>(&self) -> Option<&OBJ> {
self.get_by_tag(OBJ::tag())
}
fn get_mut<OBJ: Object + 'static>(&mut self) -> Option<&mut OBJ> {
self.get_mut_by_tag(OBJ::tag())
}
}
struct Test1 {
val: String,
}
struct Test2 {
val: String,
}
impl Object for Test1 {
fn tag() -> u8 {
4
}
}
impl Object for Test2 {
fn tag() -> u8 {
15
}
}
fn main() {
let test1 = Box::new(Test1 {
val: "I am test1".into(),
});
let test2 = Box::new(Test2 {
val: "I am test2".into(),
});
let mut objmap = ObjectMap::new();
objmap.register(test1);
objmap.register(test2);
println!("{}", objmap.get::<Test1>().unwrap().val);
println!("{}", objmap.get::<Test2>().unwrap().val);
objmap.get_mut::<Test2>().unwrap().val = "Changed test2".into();
println!("{}", objmap.get::<Test1>().unwrap().val);
println!("{}", objmap.get::<Test2>().unwrap().val);
}
Output:
I am test1
I am test2
I am test1
Changed test2
I would like to change the object map to own pinned objects. Basically:
struct ObjectMap {
map: HashMap<u8, Pin<Box<dyn Any>>>,
}
I would expect this to work transparently (with just small changes), but in fact I cannot make it to compile or work. I get this:
error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/main.rs:30:39
|
30 | self.map.get_mut(&id).map(|v| v.downcast_mut().unwrap())
| ^ cannot borrow as mutable
(Playground for the slightly modified version that uses Pin)
I think I found out that it doesn't work because dyn Any
doesn't necessarily implement Unpin
. I've also tried declaring the map as dyn Any + Unpin
but at that point it seems that I can't call Any::downcast_ref
or Any::downcast_mut
anymore.
Can anybody shed some light on this?