I have a struct pub struct PhysicalMapping<T>
that I want to store in a BTreeMap
, but I want to store any mapping (kind of forall T
if that makes sense). The obvious way (I thought) was to use Any
:
BTreeMap<PhysicalAddress, PhysicalMapping<Any>>
But this gives this error:
error[E0277]: the trait bound `core::any::Any + 'static: core::marker::Sized` is not satisfied
--> src/acpi_handler.rs:16:5
|
16 | mapped_regions : BTreeMap<PhysicalAddress, PhysicalMapping<Any>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `core::any::Any + 'sta
tic` does not have a constant size known at compile-time
|
= help: the trait `core::marker::Sized` is not implemented for `core::any::Any + 'static`
note: required by `memory::paging::mapper::PhysicalMapping`
--> src/memory/paging/mapper.rs:25:1
|
25 | pub struct PhysicalMapping<T>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Can I specify that T
can be any Sized
type, or is this not possible?
You would need to make a trait that defines the ways you intend to interact with the forall T
physical mappings after having placed them into the map.
use std::collections::BTreeMap;
struct PhysicalMapping<T> {
value: T,
}
trait AnyPhysicalMapping {}
impl<T> AnyPhysicalMapping for PhysicalMapping<T> {}
fn main() {
type PhysicalAddress = usize;
let mut map = BTreeMap::<PhysicalAddress, Box<AnyPhysicalMapping>>::new();
map.insert(1, Box::new(PhysicalMapping { value: "string" }));
map.insert(2, Box::new(PhysicalMapping { value: true }));
}
If the mapping is opaque and caller is to determine the type upon retrieval, you can do something with Any
like:
use std::any::Any;
use std::collections::BTreeMap;
#[derive(Debug)]
struct PhysicalMapping<T> {
value: T,
}
struct Mapping {
map: BTreeMap<usize, Box<Any>>,
}
impl Mapping {
fn insert<T: 'static>(&mut self, key: usize, val: PhysicalMapping<T>) {
self.map.insert(key, Box::new(val));
}
fn get<T: 'static>(&self, key: usize) -> Option<&PhysicalMapping<T>> {
self.map.get(&key).map_or(None, |a| a.downcast_ref())
}
}
fn main() {
let mut map = Mapping {
map: BTreeMap::new(),
};
map.insert(1, PhysicalMapping { value: "string" });
map.insert(2, PhysicalMapping { value: true });
println!("{:?}", map.get::<&str>(1));
println!("{:?}", map.get::<bool>(2));
}
The gist is you need to use trait objects to provide sizing - a raw trait isn't going to work. In the above it's using owned trait objects, but you can also use &Any
if you want to store references (Mapping
then gains a generic lifetime parameter, of course).