Trait ContainEntity

Source
pub trait ContainEntity:
    RegisterComponent
    + BorrowComponent
    + AddEntity {
    // Required methods
    fn create_twin(&self) -> Box<dyn ContainEntity>;
    fn get_item_mut(&mut self, ci: usize, ri: usize) -> Option<NonNull<u8>>;
    fn len(&self) -> usize;
    fn capacity(&self) -> usize;
    fn reserve(&mut self, additional: usize);
    fn shrink_to_fit(&mut self);
    unsafe fn resize_column(
        &mut self,
        ci: usize,
        new_len: usize,
        val_ptr: NonNull<u8>,
    );
}
Expand description

A trait for collecting heterogeneous component types.

In this trait, each component type is gathered in each component column and all columns have the same length so that it looks like 2d matrix.

When it comes to in & out types, this trait has intentionally raw pointer parameters not to use generic for object safety. So that you can hold various sorts of entity container in a single variable.

§Index system

There are three index systems for this trait.

The first one is ‘column index’ which is for pointing a certain component column. When you add or remove component column from an entity container, you will get or need this column index. Column indices starts with 0 and increases by 1 as you put in a component column. To avoid confusion, column must be added in a sorted order by ComponentKey.

The second and third index systems are related to pointing a certain entity in an entity container. In other words, you need one of those index systems when you need access to a single entity.

Second one is ‘row index’ which is a kind of outer index for each entity. You will get this row index when you put your entity in an entity container. Also, you can remove an entity using the row index. Row indices may not be in order and not consecutive.

The last one is ‘value index’ which is inner index for each entity. In contrast to former one, value indices are in order and consecutive like indices on a slice. Plus, all component columns follows the same value indices in an entity container.

Take a look at example below.

             column index      0        1
--------------------------------------------
| row index | value index | comp_a | comp_b |
|     0     |      0      |    .   |    .   |
|     4     |      1      |    .   |    .   |
|     2     |      2      |    .   |    .   |

§Examples

use my_ecs::prelude::*;
use std::{hash::RandomState, ptr::NonNull};

#[derive(Entity)]
struct Entity {
    a: Ca,
    b: Cb,
}
#[derive(Component)]
struct Ca(i32);
#[derive(Component)]
struct Cb(i32);

let mut cont: SparseSet<RandomState> = SparseSet::new();

// Adds component columns.
let ci_a = cont.add_column(tinfo!(Ca)).unwrap();
let ci_b = cont.add_column(tinfo!(Cb)).unwrap();

// Adds component values for the entity.
cont.begin_add_row();
let ri = unsafe {
    let ptr = NonNull::new(&mut Ca(4) as *mut Ca as *mut u8).unwrap();
    cont.add_value(ci_a, ptr);
    let ptr = NonNull::new(&mut Cb(2) as *mut Cb as *mut u8).unwrap();
    cont.add_value(ci_b, ptr);
    cont.end_add_row()
};
assert_eq!(cont.len(), 1);

// Borrows component columns and test them if they are as we expected.
let col_a = cont.borrow_column(ci_a).unwrap();
let col_b = cont.borrow_column(ci_b).unwrap();
unsafe {
    let ptr = col_a.get(0).unwrap();
    assert_eq!(*ptr.as_ref(), 4);
    let ptr = col_b.get(0).unwrap();
    assert_eq!(*ptr.as_ref(), 2);
}
drop(col_a);
drop(col_b);

// Removes the entity we just put.
let is_removed = cont.remove_row(ri);
assert!(is_removed);
assert_eq!(cont.len(), 0);

Required Methods§

Source

fn create_twin(&self) -> Box<dyn ContainEntity>

Creates a new entity container that has the same component types without component values.

In other words, the copied container doesn’t have any entities in it. So it’s empty.

§Examples
use my_ecs::prelude::*;
use std::{hash::RandomState, ptr::NonNull, any::TypeId};

#[derive(Entity)]
struct Entity {
    a: Ca,
}
#[derive(Component)]
struct Ca(i32);

let mut cont: SparseSet<RandomState> = SparseSet::new();
let ci = cont.add_column(tinfo!(Ca)).unwrap();

// Adds component values for an entity.
cont.begin_add_row();
unsafe {
    let ptr = NonNull::new(&mut Ca(0) as *mut Ca as *mut u8).unwrap();
    cont.add_value(ci, ptr);
    cont.end_add_row();
}
assert_eq!(cont.len(), 1);

let twin = cont.create_twin();
assert_eq!(twin.len(), 0);
assert!(twin.contains_column(&TypeId::of::<Ca>()));
Source

fn get_item_mut(&mut self, ci: usize, ri: usize) -> Option<NonNull<u8>>

Retrieves an entity for the given component column index and row index from the entity container.

If one of two indices is out of bounds, returns None.

Source

fn len(&self) -> usize

Returns number of entities in the entity container.

§Examples

See ContainEntity document.

Source

fn capacity(&self) -> usize

Returns capacity of the entity container.

But if entity container doesn’t support getting capacity, it returns number of entities instead.

§Examples

See ContainEntity::reserve document.

Source

fn reserve(&mut self, additional: usize)

May reserve at least additional extra capacity.

This method doesn’t guarantee definite extension of capacity. It depends on implementations.

§Examples
use my_ecs::prelude::*;
use std::{hash::RandomState, ptr::NonNull, any::TypeId};

#[derive(Entity)]
struct Entity {
    a: Ca,
}
#[derive(Component)]
struct Ca(i32);

// SparseSet supports capacity.
let mut cont: SparseSet<RandomState> = SparseSet::new();
cont.add_column(tinfo!(Ca)).unwrap();
assert_eq!(cont.capacity(), 0);

cont.reserve(10);
assert!(cont.capacity() >= 10);

cont.shrink_to_fit();
assert_eq!(cont.capacity(), 0);
Source

fn shrink_to_fit(&mut self)

May shrink capacity of the entity container as much as possible.

This method doesn’t guarantee definite removal of extra capacity. It depends on implementations.

§Examples

See ContainEntity::reserve document.

Source

unsafe fn resize_column( &mut self, ci: usize, new_len: usize, val_ptr: NonNull<u8>, )

§Panics

Panics if

  • Column index ci is out of bounds.
  • Column type is not Clone.
§Safety

Undefined behavior if

  • Pointer to a value val_ptr is not a valid pointer for the column’s type.
  • After calling this method on columns in an entity container, any of columns doesn’t have the same length.

Implementors§

Source§

impl<S> ContainEntity for ChunkSparseSet<S>
where S: BuildHasher + Default + Clone + 'static,

Source§

impl<S> ContainEntity for SparseSet<S>
where S: BuildHasher + Default + Clone + 'static,