@@ -162,9 +162,16 @@ fn calculate_layout_for_struct(type_id: TypeId, schema: &mut Schema) -> Layout {
162162 layout. align = max ( layout. align , field_layout. align ) ;
163163
164164 // Update niche.
165- // Take the largest niche. Preference for earlier niche if 2 fields have niches of same size.
165+ // Take the largest niche. Preference for (in order):
166+ // * Largest single range of niche values.
167+ // * Largest number of niche values at start of range.
168+ // * Earlier field.
166169 if let Some ( field_niche) = & field_layout. niche {
167- if layout. niche . as_ref ( ) . is_none_or ( |niche| field_niche. count > niche. count ) {
170+ if layout. niche . as_ref ( ) . is_none_or ( |niche| {
171+ field_niche. count_max ( ) > niche. count_max ( )
172+ || ( field_niche. count_max ( ) == niche. count_max ( )
173+ && field_niche. count_start > niche. count_start )
174+ } ) {
168175 let mut niche = field_niche. clone ( ) ;
169176 niche. offset += offset;
170177 layout. niche = Some ( niche) ;
@@ -258,9 +265,7 @@ fn calculate_layout_for_enum(type_id: TypeId, schema: &mut Schema) -> Layout {
258265 let niches_end = Discriminant :: MAX - max_discriminant;
259266
260267 if niches_start != 0 || niches_end != 0 {
261- let is_range_start = niches_start >= niches_end;
262- let count = u32:: from ( if is_range_start { niches_start } else { niches_end } ) ;
263- let niche = Niche :: new ( 0 , 1 , is_range_start, count) ;
268+ let niche = Niche :: new ( 0 , 1 , u32:: from ( niches_start) , u32:: from ( niches_end) ) ;
264269 layout_64. niche = Some ( niche. clone ( ) ) ;
265270 layout_32. niche = Some ( niche) ;
266271 }
@@ -284,14 +289,18 @@ fn calculate_layout_for_option(type_id: TypeId, schema: &mut Schema) -> Layout {
284289 #[ expect( clippy:: items_after_statements) ]
285290 fn consume_niche ( layout : & mut PlatformLayout ) {
286291 if let Some ( niche) = & mut layout. niche {
287- if niche. count == 1 {
288- layout . niche = None ;
292+ if niche. count_start == 0 {
293+ niche. count_end -= 1 ;
289294 } else {
290- niche. count -= 1 ;
295+ niche. count_start -= 1 ;
296+ }
297+
298+ if niche. count_start == 0 && niche. count_end == 0 {
299+ layout. niche = None ;
291300 }
292301 } else {
293302 layout. size += layout. align ;
294- layout. niche = Some ( Niche :: new ( 0 , 1 , false , 254 ) ) ;
303+ layout. niche = Some ( Niche :: new ( 0 , 1 , 0 , 254 ) ) ;
295304 }
296305 }
297306
@@ -307,8 +316,8 @@ fn calculate_layout_for_option(type_id: TypeId, schema: &mut Schema) -> Layout {
307316/// `Box`es are pointer-sized, with a single niche (like `NonNull`).
308317fn calculate_layout_for_box ( ) -> Layout {
309318 Layout {
310- layout_64 : PlatformLayout :: from_size_align_niche ( 8 , 8 , Niche :: new ( 0 , 8 , true , 1 ) ) ,
311- layout_32 : PlatformLayout :: from_size_align_niche ( 4 , 4 , Niche :: new ( 0 , 4 , true , 1 ) ) ,
319+ layout_64 : PlatformLayout :: from_size_align_niche ( 8 , 8 , Niche :: new ( 0 , 8 , 1 , 0 ) ) ,
320+ layout_32 : PlatformLayout :: from_size_align_niche ( 4 , 4 , Niche :: new ( 0 , 4 , 1 , 0 ) ) ,
312321 }
313322}
314323
@@ -319,8 +328,8 @@ fn calculate_layout_for_box() -> Layout {
319328/// They have a single niche on the first field - the pointer which is `NonNull`.
320329fn calculate_layout_for_vec ( ) -> Layout {
321330 Layout {
322- layout_64 : PlatformLayout :: from_size_align_niche ( 32 , 8 , Niche :: new ( 0 , 8 , true , 1 ) ) ,
323- layout_32 : PlatformLayout :: from_size_align_niche ( 16 , 4 , Niche :: new ( 0 , 4 , true , 1 ) ) ,
331+ layout_64 : PlatformLayout :: from_size_align_niche ( 32 , 8 , Niche :: new ( 0 , 8 , 1 , 0 ) ) ,
332+ layout_32 : PlatformLayout :: from_size_align_niche ( 16 , 4 , Niche :: new ( 0 , 4 , 1 , 0 ) ) ,
324333 }
325334}
326335
@@ -343,8 +352,8 @@ fn calculate_layout_for_cell(type_id: TypeId, schema: &mut Schema) -> Layout {
343352fn calculate_layout_for_primitive ( primitive_def : & PrimitiveDef ) -> Layout {
344353 // `&str` and `Atom` are a `NonNull` pointer + `usize` pair. Niche for 0 on the pointer field
345354 let str_layout = Layout {
346- layout_64 : PlatformLayout :: from_size_align_niche ( 16 , 8 , Niche :: new ( 0 , 8 , true , 1 ) ) ,
347- layout_32 : PlatformLayout :: from_size_align_niche ( 8 , 4 , Niche :: new ( 0 , 4 , true , 1 ) ) ,
355+ layout_64 : PlatformLayout :: from_size_align_niche ( 16 , 8 , Niche :: new ( 0 , 8 , 1 , 0 ) ) ,
356+ layout_32 : PlatformLayout :: from_size_align_niche ( 8 , 4 , Niche :: new ( 0 , 4 , 1 , 0 ) ) ,
348357 } ;
349358 // `usize` and `isize` are pointer-sized, but with no niche
350359 let usize_layout = Layout {
@@ -353,13 +362,13 @@ fn calculate_layout_for_primitive(primitive_def: &PrimitiveDef) -> Layout {
353362 } ;
354363 // `NonZeroUsize` and `NonZeroIsize` are pointer-sized, with a single niche
355364 let non_zero_usize_layout = Layout {
356- layout_64 : PlatformLayout :: from_size_align_niche ( 8 , 8 , Niche :: new ( 0 , 8 , true , 1 ) ) ,
357- layout_32 : PlatformLayout :: from_size_align_niche ( 4 , 4 , Niche :: new ( 0 , 4 , true , 1 ) ) ,
365+ layout_64 : PlatformLayout :: from_size_align_niche ( 8 , 8 , Niche :: new ( 0 , 8 , 1 , 0 ) ) ,
366+ layout_32 : PlatformLayout :: from_size_align_niche ( 4 , 4 , Niche :: new ( 0 , 4 , 1 , 0 ) ) ,
358367 } ;
359368
360369 #[ expect( clippy:: match_same_arms) ]
361370 match primitive_def. name ( ) {
362- "bool" => Layout :: from_size_align_niche ( 1 , 1 , Niche :: new ( 0 , 1 , false , 254 ) ) ,
371+ "bool" => Layout :: from_size_align_niche ( 1 , 1 , Niche :: new ( 0 , 1 , 0 , 254 ) ) ,
363372 "u8" => Layout :: from_type :: < u8 > ( ) ,
364373 "u16" => Layout :: from_type :: < u16 > ( ) ,
365374 "u32" => Layout :: from_type :: < u32 > ( ) ,
0 commit comments