#Seeking for advice when working with Vec<Box<dyn Any>> in an ECS.
36 messages · Page 1 of 1 (latest)
Each Unique archetype has a Table
struct Table {
data: IndexMap<ComponentId, Vec<Box<dyn Any>>>,
}
When I go to Query<T> the ECS, I need to be able to access all the Tables associated with the Query.
what I'd like to do is return an Box<dyn Iterator<Item=T>>
but I'm having some trouble
I'd like to be able to have a function like this:
impl Table {
pub fn get<T>(&mut self) -> IterMut<T>
where
T: Any,
{
// cast Vec<Box<dyn Any>> into Vec<T> and return its iterator
}
but that kind of cast is obviously impossible, so I thought to try:
struct Table {
data: IndexMap<ComponentId, Box<dyn Any>>,
}
but then I dont have any way to initialize Box<dyn Any> as Vec<T>
So I'm a bit stumped as to how to iterate this elegantly
(that is to say, and be able to have type annotations in the query iterator)
Well it is possible technically, such like
fn get<T: 'static>(vec: &mut Vec<Box<dyn Any>>) -> impl Iterator<Item = &mut T> {
vec.iter_mut().map(|x| x.downcast_mut::<T>().unwrap())
}
However I wouldn't really say this gets any benefit from ECS architecture if you store every component as boxed object.
It's not data-oriented.
This would make things better as you only store vector as boxed (though you could have better trait than Any)
I'd suggest look into other open source ECS implementation
whats ComponentId
I apologize, ComponentId = TypeId
How would you initialize the Vec as Box<dyn Any>?
given just the Typeid?
The solution I found is to create a Box<Vec<T>> when the component is added to the entity, then push it once we get to that function
But this means I have to make a vec for every component, for every entity.
this is the correct solution
for the naive impl of an ECS anyways
it's fine to have a HashMap<TypeId, Vec<Box<dyn Any>>> when starting out
Yes, but I don't like heap allocating every component, since I have to iterate over the vecs
to answer the question of heap alloc, you need to delve into unsafe
bevy solves this via bevy_ptr
bevy_ptr
Type-erased Box-like pointer to some unknown type chosen when constructing this type. Conceptually represents ownership of whatever data is being pointed to and so is responsible for calling its Drop impl. This pointer is not responsible for freeing the memory pointed to by this pointer as it may be pointing to an element in a Vec or to a lo...
which has
pub struct OwningPtr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
internally
also, bevy also does not use Vec<T> internally, but Vec<u8>
try grepping in the bevy repo the term BlobVec
DUDE THATS SICK
Bro thanks for the link, I'll check it out when I get home
🙂
also be aware of bevy_ecs internals