@@ -22,7 +22,10 @@ pub type Layer = usize;
2222/// Entities without this component belong to layer `0`.
2323#[ derive( Component , Clone , Reflect , PartialEq , Eq , PartialOrd , Ord ) ]
2424#[ 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 ;
2629
2730impl Default for & RenderLayers {
2831 fn default ( ) -> Self {
@@ -47,8 +50,7 @@ impl FromIterator<Layer> for RenderLayers {
4750impl Default for RenderLayers {
4851 /// By default, this structure includes layer `0`, which represents the first layer.
4952 fn default ( ) -> Self {
50- let ( _, bit) = Self :: layer_info ( 0 ) ;
51- RenderLayers ( SmallVec :: from_const ( [ bit] ) )
53+ Self :: layer ( 0 )
5254 }
5355}
5456
@@ -57,15 +59,17 @@ impl RenderLayers {
5759 pub const fn layer ( n : Layer ) -> Self {
5860 let ( buffer_index, bit) = Self :: layer_info ( n) ;
5961 assert ! (
60- buffer_index < 1 ,
62+ buffer_index < INLINE_BLOCKS ,
6163 "layer is out of bounds for const construction"
6264 ) ;
63- RenderLayers ( SmallVec :: from_const ( [ bit] ) )
65+ let mut buffer = [ 0 ; INLINE_BLOCKS ] ;
66+ buffer[ buffer_index] = bit;
67+ RenderLayers ( SmallVec :: from_const ( buffer) )
6468 }
6569
6670 /// Create a new `RenderLayers` that belongs to no layers.
6771 pub const fn none ( ) -> Self {
68- RenderLayers ( SmallVec :: from_const ( [ 0 ] ) )
72+ RenderLayers ( SmallVec :: from_const ( [ 0 ; INLINE_BLOCKS ] ) )
6973 }
7074
7175 /// Create a `RenderLayers` from a list of layers.
@@ -91,6 +95,11 @@ impl RenderLayers {
9195 let ( buffer_index, bit) = Self :: layer_info ( layer) ;
9296 if buffer_index < self . 0 . len ( ) {
9397 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+ }
94103 }
95104 self
96105 }
@@ -154,6 +163,81 @@ impl RenderLayers {
154163 Some ( layer - 1 )
155164 } )
156165 }
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+ }
157241}
158242
159243#[ cfg( test) ]
@@ -242,4 +326,33 @@ mod rendering_mask_tests {
242326 let out = layers. iter ( ) . collect :: < Vec < _ > > ( ) ;
243327 assert_eq ! ( tricky_layers, out, "tricky layers roundtrip" ) ;
244328 }
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+ }
245358}
0 commit comments