intuicio_framework_ecs/
entity.rs

1use intuicio_core::{registry::Registry, IntuicioStruct};
2use intuicio_derive::*;
3use serde::{Deserialize, Serialize};
4
5/// Entity ids start with 1, 0 is considered invalid.
6#[derive(
7    IntuicioStruct, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
8)]
9#[intuicio(module_name = "ecs_entity")]
10pub struct Entity {
11    #[intuicio(ignore)]
12    pub(crate) id: u32,
13    #[intuicio(ignore)]
14    pub(crate) generation: u32,
15}
16
17impl Default for Entity {
18    fn default() -> Self {
19        Self::INVALID
20    }
21}
22
23#[intuicio_methods(module_name = "ecs_entity")]
24impl Entity {
25    pub const INVALID: Self = unsafe { Self::new_unchecked(u32::MAX, 0) };
26
27    pub const fn new(id: u32, generation: u32) -> Option<Self> {
28        if id < u32::MAX {
29            Some(Self { id, generation })
30        } else {
31            None
32        }
33    }
34
35    /// # Safety
36    pub const unsafe fn new_unchecked(id: u32, generation: u32) -> Self {
37        Self { id, generation }
38    }
39
40    #[intuicio_method()]
41    pub const fn is_valid(self) -> bool {
42        self.id < u32::MAX
43    }
44
45    #[intuicio_method()]
46    pub const fn id(self) -> u32 {
47        self.id
48    }
49
50    #[intuicio_method()]
51    pub const fn generation(self) -> u32 {
52        self.generation
53    }
54
55    #[intuicio_method()]
56    pub const fn to_u64(self) -> u64 {
57        ((self.generation as u64) << 32) | self.id as u64
58    }
59
60    #[intuicio_method()]
61    pub const fn from_u64(value: u64) -> Self {
62        Self {
63            generation: (value >> 32) as u32,
64            id: value as u32,
65        }
66    }
67
68    pub(crate) const fn bump_generation(mut self) -> Self {
69        self.generation = self.generation.wrapping_add(1);
70        self
71    }
72}
73
74impl std::fmt::Display for Entity {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        write!(f, "@{}:#{}", self.id, self.generation)
77    }
78}
79
80impl Entity {
81    pub fn install(registry: &mut Registry) {
82        registry.add_type(Self::define_struct(registry));
83        registry.add_function(Self::is_valid__define_function(registry));
84        registry.add_function(Self::id__define_function(registry));
85        registry.add_function(Self::generation__define_function(registry));
86        registry.add_function(Self::to_u64__define_function(registry));
87        registry.add_function(Self::from_u64__define_function(registry));
88    }
89}
90
91#[derive(Debug, Default, Clone, PartialEq, Eq)]
92pub struct EntityDenseMap {
93    inner: Vec<Entity>,
94}
95
96impl EntityDenseMap {
97    pub fn with_capacity(mut capacity: usize) -> Self {
98        capacity = capacity.next_power_of_two().max(1);
99        Self {
100            inner: Vec::with_capacity(capacity),
101        }
102    }
103
104    pub fn clear(&mut self) {
105        self.inner.clear();
106    }
107
108    pub fn insert(&mut self, entity: Entity) -> Result<usize, usize> {
109        if let Some(index) = self.index_of(entity) {
110            Err(index)
111        } else {
112            if self.inner.len() == self.inner.capacity() {
113                self.inner.reserve_exact(self.inner.capacity());
114            }
115            let index = self.inner.len();
116            self.inner.push(entity);
117            Ok(index)
118        }
119    }
120
121    pub fn remove(&mut self, entity: Entity) -> Option<usize> {
122        let index = self.index_of(entity)?;
123        self.inner.swap_remove(index);
124        if self.inner.len() == self.inner.capacity() / 2 {
125            self.inner.shrink_to_fit();
126        }
127        Some(index)
128    }
129
130    pub fn contains(&self, entity: Entity) -> bool {
131        self.inner.contains(&entity)
132    }
133
134    pub fn index_of(&self, entity: Entity) -> Option<usize> {
135        self.inner.iter().position(|e| *e == entity)
136    }
137
138    pub fn get(&self, index: usize) -> Option<Entity> {
139        self.inner.get(index).copied()
140    }
141
142    pub fn iter(&self) -> impl Iterator<Item = Entity> + '_ {
143        self.inner.iter().copied()
144    }
145}