bevy_ecs/identifier/
masks.rs1use std::num::NonZeroU32;
2
3use super::kinds::IdKind;
4
5pub(crate) const HIGH_MASK: u32 = 0x7FFF_FFFF;
9
10pub(crate) struct IdentifierMask;
12
13impl IdentifierMask {
14 #[inline(always)]
16 pub(crate) const fn get_low(value: u64) -> u32 {
17 value as u32
19 }
20
21 #[inline(always)]
23 pub(crate) const fn get_high(value: u64) -> u32 {
24 (value >> u32::BITS) as u32
26 }
27
28 #[inline(always)]
30 pub(crate) const fn pack_into_u64(low: u32, high: u32) -> u64 {
31 ((high as u64) << u32::BITS) | (low as u64)
32 }
33
34 #[inline(always)]
36 pub(crate) const fn pack_kind_into_high(value: u32, kind: IdKind) -> u32 {
37 value | ((kind as u32) << 24)
38 }
39
40 #[inline(always)]
42 pub(crate) const fn extract_value_from_high(value: u32) -> u32 {
43 value & HIGH_MASK
44 }
45
46 #[inline(always)]
48 pub(crate) const fn extract_kind_from_high(value: u32) -> IdKind {
49 let kind_mask = !HIGH_MASK;
51 let bit = value & kind_mask;
52
53 if bit == kind_mask {
54 IdKind::Placeholder
55 } else {
56 IdKind::Entity
57 }
58 }
59
60 #[inline(always)]
64 pub(crate) const fn inc_masked_high_by(lhs: NonZeroU32, rhs: u32) -> NonZeroU32 {
65 let lo = (lhs.get() & HIGH_MASK).wrapping_add(rhs & HIGH_MASK);
66 let overflowed = lo >> 31;
68
69 unsafe { NonZeroU32::new_unchecked(lo.wrapping_add(overflowed) & HIGH_MASK) }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn get_u64_parts() {
83 let value: u64 = 0x7FFF_FFFF_0000_000C;
85
86 assert_eq!(IdentifierMask::get_low(value), 0x0000_000C);
87 assert_eq!(IdentifierMask::get_high(value), 0x7FFF_FFFF);
88 }
89
90 #[test]
91 fn extract_kind() {
92 let high: u32 = 0xFFFF_FFFF;
94
95 assert_eq!(
96 IdentifierMask::extract_kind_from_high(high),
97 IdKind::Placeholder
98 );
99
100 let high: u32 = 0x4000_0002;
102
103 assert_eq!(IdentifierMask::extract_kind_from_high(high), IdKind::Entity);
104 }
105
106 #[test]
107 fn extract_high_value() {
108 let high: u32 = 0xFFFF_FFFF;
110
111 assert_eq!(IdentifierMask::extract_value_from_high(high), 0x7FFF_FFFF);
113
114 let high: u32 = 0x8000_0001;
116
117 assert_eq!(IdentifierMask::extract_value_from_high(high), 0x0000_0001);
118
119 let high: u32 = 0xDEAD_BEEF;
121
122 assert_eq!(IdentifierMask::extract_value_from_high(high), 0x5EAD_BEEF);
123 }
124
125 #[test]
126 fn pack_kind_bits() {
127 let high: u32 = 0x7FFF_FFFF;
129
130 assert_eq!(
131 IdentifierMask::pack_kind_into_high(high, IdKind::Placeholder),
132 0xFFFF_FFFF
133 );
134
135 let high: u32 = 0x00FF_FF00;
137
138 assert_eq!(
139 IdentifierMask::pack_kind_into_high(high, IdKind::Entity),
140 0x00FF_FF00
142 );
143
144 let high: u32 = 0x40FF_EEEE;
146
147 assert_eq!(
148 IdentifierMask::pack_kind_into_high(high, IdKind::Placeholder),
149 0xC0FF_EEEE );
151 }
152
153 #[test]
154 fn pack_into_u64() {
155 let high: u32 = 0x7FFF_FFFF;
156 let low: u32 = 0x0000_00CC;
157
158 assert_eq!(
159 IdentifierMask::pack_into_u64(low, high),
160 0x7FFF_FFFF_0000_00CC
161 );
162 }
163
164 #[test]
165 fn incrementing_masked_nonzero_high_is_safe() {
166 assert_eq!(
169 NonZeroU32::MIN,
170 IdentifierMask::inc_masked_high_by(NonZeroU32::MIN, 0)
171 );
172 assert_eq!(
173 NonZeroU32::new(2).unwrap(),
174 IdentifierMask::inc_masked_high_by(NonZeroU32::MIN, 1)
175 );
176 assert_eq!(
177 NonZeroU32::new(3).unwrap(),
178 IdentifierMask::inc_masked_high_by(NonZeroU32::MIN, 2)
179 );
180 assert_eq!(
181 NonZeroU32::MIN,
182 IdentifierMask::inc_masked_high_by(NonZeroU32::MIN, HIGH_MASK)
183 );
184 assert_eq!(
185 NonZeroU32::MIN,
186 IdentifierMask::inc_masked_high_by(NonZeroU32::MIN, u32::MAX)
187 );
188 assert_eq!(
191 NonZeroU32::new(HIGH_MASK).unwrap(),
192 IdentifierMask::inc_masked_high_by(NonZeroU32::MAX, 0)
193 );
194 assert_eq!(
195 NonZeroU32::MIN,
196 IdentifierMask::inc_masked_high_by(NonZeroU32::MAX, 1)
197 );
198 assert_eq!(
199 NonZeroU32::new(2).unwrap(),
200 IdentifierMask::inc_masked_high_by(NonZeroU32::MAX, 2)
201 );
202 assert_eq!(
203 NonZeroU32::new(HIGH_MASK).unwrap(),
204 IdentifierMask::inc_masked_high_by(NonZeroU32::MAX, HIGH_MASK)
205 );
206 assert_eq!(
207 NonZeroU32::new(HIGH_MASK).unwrap(),
208 IdentifierMask::inc_masked_high_by(NonZeroU32::MAX, u32::MAX)
209 );
210 assert_eq!(
213 NonZeroU32::new(HIGH_MASK).unwrap(),
214 IdentifierMask::inc_masked_high_by(NonZeroU32::new(HIGH_MASK).unwrap(), 0)
215 );
216 assert_eq!(
217 NonZeroU32::MIN,
218 IdentifierMask::inc_masked_high_by(NonZeroU32::new(HIGH_MASK).unwrap(), 1)
219 );
220 assert_eq!(
221 NonZeroU32::new(2).unwrap(),
222 IdentifierMask::inc_masked_high_by(NonZeroU32::new(HIGH_MASK).unwrap(), 2)
223 );
224 assert_eq!(
225 NonZeroU32::new(HIGH_MASK).unwrap(),
226 IdentifierMask::inc_masked_high_by(NonZeroU32::new(HIGH_MASK).unwrap(), HIGH_MASK)
227 );
228 assert_eq!(
229 NonZeroU32::new(HIGH_MASK).unwrap(),
230 IdentifierMask::inc_masked_high_by(NonZeroU32::new(HIGH_MASK).unwrap(), u32::MAX)
231 );
232 }
233}