@@ -22,7 +22,10 @@ pub type Layer = usize;
22
22
/// Entities without this component belong to layer `0`.
23
23
#[ derive( Component , Clone , Reflect , PartialEq , Eq , PartialOrd , Ord ) ]
24
24
#[ reflect( Component , Default , PartialEq ) ]
25
- pub struct RenderLayers ( SmallVec < [ u64 ; 1 ] > ) ;
25
+ pub struct RenderLayers ( SmallVec < [ u64 ; INLINE_BLOCKS ] > ) ;
26
+
27
+ /// The number of memory blocks stored inline
28
+ const INLINE_BLOCKS : usize = 1 ;
26
29
27
30
impl Default for & RenderLayers {
28
31
fn default ( ) -> Self {
@@ -47,8 +50,7 @@ impl FromIterator<Layer> for RenderLayers {
47
50
impl Default for RenderLayers {
48
51
/// By default, this structure includes layer `0`, which represents the first layer.
49
52
fn default ( ) -> Self {
50
- let ( _, bit) = Self :: layer_info ( 0 ) ;
51
- RenderLayers ( SmallVec :: from_const ( [ bit] ) )
53
+ Self :: layer ( 0 )
52
54
}
53
55
}
54
56
@@ -57,15 +59,17 @@ impl RenderLayers {
57
59
pub const fn layer ( n : Layer ) -> Self {
58
60
let ( buffer_index, bit) = Self :: layer_info ( n) ;
59
61
assert ! (
60
- buffer_index < 1 ,
62
+ buffer_index < INLINE_BLOCKS ,
61
63
"layer is out of bounds for const construction"
62
64
) ;
63
- RenderLayers ( SmallVec :: from_const ( [ bit] ) )
65
+ let mut buffer = [ 0 ; INLINE_BLOCKS ] ;
66
+ buffer[ buffer_index] = bit;
67
+ RenderLayers ( SmallVec :: from_const ( buffer) )
64
68
}
65
69
66
70
/// Create a new `RenderLayers` that belongs to no layers.
67
71
pub const fn none ( ) -> Self {
68
- RenderLayers ( SmallVec :: from_const ( [ 0 ] ) )
72
+ RenderLayers ( SmallVec :: from_const ( [ 0 ; INLINE_BLOCKS ] ) )
69
73
}
70
74
71
75
/// Create a `RenderLayers` from a list of layers.
@@ -91,6 +95,11 @@ impl RenderLayers {
91
95
let ( buffer_index, bit) = Self :: layer_info ( layer) ;
92
96
if buffer_index < self . 0 . len ( ) {
93
97
self . 0 [ buffer_index] &= !bit;
98
+ // Drop trailing zero memory blocks.
99
+ // NOTE: This is not just an optimization, it is necessary for the derived PartialEq impl to be correct.
100
+ if buffer_index == self . 0 . len ( ) - 1 {
101
+ self = self . shrink ( ) ;
102
+ }
94
103
}
95
104
self
96
105
}
@@ -154,6 +163,81 @@ impl RenderLayers {
154
163
Some ( layer - 1 )
155
164
} )
156
165
}
166
+
167
+ /// Returns the set of [layers](Layer) shared by two instances of [`RenderLayers`].
168
+ ///
169
+ /// This corresponds to the `self & other` operation.
170
+ pub fn intersection ( & self , other : & Self ) -> Self {
171
+ self . combine_blocks ( other, |a, b| a & b) . shrink ( )
172
+ }
173
+
174
+ /// Returns all [layers](Layer) included in either instance of [`RenderLayers`].
175
+ ///
176
+ /// This corresponds to the `self | other` operation.
177
+ pub fn union ( & self , other : & Self ) -> Self {
178
+ self . combine_blocks ( other, |a, b| a | b) // doesn't need to be shrunk, if the inputs are nonzero then the result will be too
179
+ }
180
+
181
+ /// Returns all [layers](Layer) included in exactly one of the instances of [`RenderLayers`].
182
+ ///
183
+ /// This corresponds to the "exclusive or" (XOR) operation: `self ^ other`.
184
+ pub fn symmetric_difference ( & self , other : & Self ) -> Self {
185
+ self . combine_blocks ( other, |a, b| a ^ b) . shrink ( )
186
+ }
187
+
188
+ /// Deallocates any trailing-zero memory blocks from this instance
189
+ fn shrink ( mut self ) -> Self {
190
+ let mut any_dropped = false ;
191
+ while self . 0 . len ( ) > INLINE_BLOCKS && self . 0 . last ( ) == Some ( & 0 ) {
192
+ self . 0 . pop ( ) ;
193
+ any_dropped = true ;
194
+ }
195
+ if any_dropped && self . 0 . len ( ) <= INLINE_BLOCKS {
196
+ self . 0 . shrink_to_fit ( ) ;
197
+ }
198
+ self
199
+ }
200
+
201
+ /// Creates a new instance of [`RenderLayers`] by applying a function to the memory blocks
202
+ /// of self and another instance.
203
+ ///
204
+ /// If the function `f` might return `0` for non-zero inputs, you should call [`Self::shrink`]
205
+ /// on the output to ensure that there are no trailing zero memory blocks that would break
206
+ /// this type's equality comparison.
207
+ fn combine_blocks ( & self , other : & Self , mut f : impl FnMut ( u64 , u64 ) -> u64 ) -> Self {
208
+ let mut a = self . 0 . iter ( ) ;
209
+ let mut b = other. 0 . iter ( ) ;
210
+ let mask = std:: iter:: from_fn ( || {
211
+ let a = a. next ( ) . copied ( ) ;
212
+ let b = b. next ( ) . copied ( ) ;
213
+ if a. is_none ( ) && b. is_none ( ) {
214
+ return None ;
215
+ }
216
+ Some ( f ( a. unwrap_or_default ( ) , b. unwrap_or_default ( ) ) )
217
+ } ) ;
218
+ Self ( mask. collect ( ) )
219
+ }
220
+ }
221
+
222
+ impl std:: ops:: BitAnd for RenderLayers {
223
+ type Output = Self ;
224
+ fn bitand ( self , rhs : Self ) -> Self :: Output {
225
+ self . intersection ( & rhs)
226
+ }
227
+ }
228
+
229
+ impl std:: ops:: BitOr for RenderLayers {
230
+ type Output = Self ;
231
+ fn bitor ( self , rhs : Self ) -> Self :: Output {
232
+ self . union ( & rhs)
233
+ }
234
+ }
235
+
236
+ impl std:: ops:: BitXor for RenderLayers {
237
+ type Output = Self ;
238
+ fn bitxor ( self , rhs : Self ) -> Self :: Output {
239
+ self . symmetric_difference ( & rhs)
240
+ }
157
241
}
158
242
159
243
#[ cfg( test) ]
@@ -242,4 +326,33 @@ mod rendering_mask_tests {
242
326
let out = layers. iter ( ) . collect :: < Vec < _ > > ( ) ;
243
327
assert_eq ! ( tricky_layers, out, "tricky layers roundtrip" ) ;
244
328
}
329
+
330
+ const MANY : RenderLayers = RenderLayers ( SmallVec :: from_const ( [ u64:: MAX ] ) ) ;
331
+
332
+ #[ test]
333
+ fn render_layer_ops ( ) {
334
+ let a = RenderLayers :: from_layers ( & [ 2 , 4 , 6 ] ) ;
335
+ let b = RenderLayers :: from_layers ( & [ 1 , 2 , 3 , 4 , 5 ] ) ;
336
+
337
+ assert_eq ! (
338
+ a. clone( ) | b. clone( ) ,
339
+ RenderLayers :: from_layers( & [ 1 , 2 , 3 , 4 , 5 , 6 ] )
340
+ ) ;
341
+ assert_eq ! ( a. clone( ) & b. clone( ) , RenderLayers :: from_layers( & [ 2 , 4 ] ) ) ;
342
+ assert_eq ! ( a ^ b, RenderLayers :: from_layers( & [ 1 , 3 , 5 , 6 ] ) ) ;
343
+
344
+ assert_eq ! ( RenderLayers :: none( ) & MANY , RenderLayers :: none( ) ) ;
345
+ assert_eq ! ( RenderLayers :: none( ) | MANY , MANY ) ;
346
+ assert_eq ! ( RenderLayers :: none( ) ^ MANY , MANY ) ;
347
+ }
348
+
349
+ #[ test]
350
+ fn render_layer_shrink ( ) {
351
+ // Since it has layers greater than 64, the instance should take up two memory blocks
352
+ let layers = RenderLayers :: from_layers ( & [ 1 , 77 ] ) ;
353
+ assert ! ( layers. 0 . len( ) == 2 ) ;
354
+ // When excluding that layer, it should drop the extra memory block
355
+ let layers = layers. without ( 77 ) ;
356
+ assert ! ( layers. 0 . len( ) == 1 ) ;
357
+ }
245
358
}
0 commit comments