Option<Position>
необходимо хранить состояние (Some
или None
) где-то , а поскольку Position
уже содержит 12 байтов информации, вам нужно больше места для ее хранения. Обычно это означает, что он добавляет дополнительный байт (плюс заполнение) для сохранения состояния, хотя в некоторых случаях внутренний тип имеет известное неиспользуемое состояние. Например, ссылка может указывать на адрес 0
, поэтому Option<&'_ T>
может использовать 0
в качестве состояния None
и занимать то же количество байтов, что и &'_ T
. Однако для вашего Position
типа это не так.
Если вам абсолютно необходимо, чтобы ваша структура PoolItem
была как можно меньше, и если вы можете сэкономить один бит из поля entity_id
( скажем, старший бит, 2 31 ), вы можете использовать его для хранения состояния:
const COMPONENT_USED_BIT: u32 = (1u32 << 31);
struct PoolItem {
entity_id: u32, // lowest 31 bits = entity ID, highest bit = "component used"
component: Position,
}
Это может стать немного сложным, так как вам нужно убедиться, что вы ' обрабатывая этот бит специально, но вы можете написать пару простых методов доступа, чтобы гарантировать, что специальный бит обрабатывается правильно.
impl PoolItem {
/// Get entity ID, without the "component used" bit
fn entity_id(&self) -> u32 {
self.entity_id & !COMPONENT_USED_BIT
}
/// Set entity ID, keeping the existing "component used" bit
fn set_entity_id(&mut self, entity_id: u32) {
let component_used_bit = self.entity_id & COMPONENT_USED_BIT;
self.entity_id = (entity_id & !COMPONENT_USED_BIT) | component_used_bit;
}
/// Get component if "component used" bit is set
fn component(&self) -> Option<&Position> {
if self.entity_id & COMPONENT_USED_BIT != 0 {
Some(&self.component)
} else {
None
}
}
/// Set component, updating the "component used" bit
fn set_component(&mut self, component: Option<Position>) {
if let Some(component) = component {
self.component = component;
self.entity_id |= COMPONENT_USED_BIT;
} else {
self.entity_id &= !COMPONENT_USED_BIT;
}
}
}
Пример игровой площадки с тестами