concinnity_core/ecs/
mask.rs1#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
8pub struct ComponentId(u8);
10
11impl ComponentId {
12 pub const MAX: u8 = 127;
14
15 pub fn new(id: u8) -> ComponentId {
17 debug_assert!(id <= Self::MAX, "component id {id} exceeds {}", Self::MAX);
18 ComponentId(id)
19 }
20
21 pub fn get(self) -> u8 {
23 self.0
24 }
25}
26
27#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
28pub struct ComponentMask(u128);
30
31impl ComponentMask {
32 pub const EMPTY: ComponentMask = ComponentMask(0);
34
35 pub fn with(id: ComponentId) -> ComponentMask {
37 let mut mask = ComponentMask::EMPTY;
38 mask.insert(id);
39 mask
40 }
41
42 pub fn insert(&mut self, id: ComponentId) {
44 self.0 |= 1u128 << id.0;
45 }
46
47 pub fn remove(&mut self, id: ComponentId) {
49 self.0 &= !(1u128 << id.0);
50 }
51
52 pub fn contains(self, id: ComponentId) -> bool {
54 self.0 & (1u128 << id.0) != 0
55 }
56
57 pub(crate) fn contains_all(self, other: ComponentMask) -> bool {
59 self.0 & other.0 == other.0
60 }
61
62 pub(crate) fn is_disjoint(self, other: ComponentMask) -> bool {
64 self.0 & other.0 == 0
65 }
66
67 pub fn is_empty(self) -> bool {
69 self.0 == 0
70 }
71
72 pub fn merged(self, other: ComponentMask) -> ComponentMask {
74 ComponentMask(self.0 | other.0)
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn insert_remove_contains() {
84 let a = ComponentId::new(3);
85 let b = ComponentId::new(70);
86 let mut mask = ComponentMask::EMPTY;
87 assert!(mask.is_empty());
88 mask.insert(a);
89 mask.insert(b);
90 assert!(mask.contains(a));
91 assert!(mask.contains(b));
92 assert!(!mask.contains(ComponentId::new(4)));
93 mask.remove(a);
94 assert!(!mask.contains(a));
95 assert!(mask.contains(b));
96 }
97
98 #[test]
99 fn with_builds_single_bit_mask() {
100 let id = ComponentId::new(127);
101 let mask = ComponentMask::with(id);
102 assert!(mask.contains(id));
103 assert!(!mask.contains(ComponentId::new(0)));
104 }
105
106 #[test]
107 fn contains_all_is_superset() {
108 let mut have = ComponentMask::EMPTY;
109 have.insert(ComponentId::new(1));
110 have.insert(ComponentId::new(2));
111 have.insert(ComponentId::new(3));
112
113 let mut need = ComponentMask::EMPTY;
114 need.insert(ComponentId::new(1));
115 need.insert(ComponentId::new(3));
116 assert!(have.contains_all(need));
117
118 need.insert(ComponentId::new(9));
119 assert!(!have.contains_all(need));
120 assert!(have.contains_all(ComponentMask::EMPTY));
122 }
123
124 #[test]
125 fn is_disjoint_detects_overlap() {
126 let mut a = ComponentMask::EMPTY;
127 a.insert(ComponentId::new(1));
128 a.insert(ComponentId::new(2));
129 let mut b = ComponentMask::EMPTY;
130 b.insert(ComponentId::new(3));
131 assert!(a.is_disjoint(b));
132 b.insert(ComponentId::new(2));
133 assert!(!a.is_disjoint(b));
134 assert!(a.is_disjoint(ComponentMask::EMPTY));
135 }
136}