@@ -165,6 +165,8 @@ use core::slice::Iter;
165165use core:: { fmt, mem, ptr, slice} ;
166166
167167use impl_details:: { assert_size, SizeType , MAX_CAP } ;
168+ #[ cfg( feature = "gecko-ffi" ) ]
169+ use impl_details:: { is_auto, pack_capacity, pack_capacity_and_auto, unpack_capacity} ;
168170
169171#[ cfg( feature = "malloc_size_of" ) ]
170172use malloc_size_of:: { MallocShallowSizeOf , MallocSizeOf , MallocSizeOfOps } ;
@@ -209,6 +211,8 @@ mod impl_details {
209211 // Hence we need some platform-specific CFGs for the necessary masking/shifting.
210212 //
211213 // Handling the auto bit mostly just means not freeing/reallocating the buffer.
214+ #[ cfg( feature = "gecko-ffi" ) ]
215+ use core:: convert:: TryFrom ;
212216
213217 pub type SizeType = u32 ;
214218
@@ -232,7 +236,7 @@ mod impl_details {
232236 }
233237 #[ cfg( target_endian = "little" ) ]
234238 pub fn pack_capacity_and_auto ( cap : SizeType , auto : bool ) -> SizeType {
235- cap | ( ( auto as SizeType ) << 31 )
239+ cap | ( SizeType :: from ( auto) << 31 )
236240 }
237241
238242 // Big endian: the auto bit is the low bit, and the capacity is
@@ -257,10 +261,9 @@ mod impl_details {
257261
258262 #[ inline]
259263 pub fn assert_size ( x : usize ) -> SizeType {
260- if x > MAX_CAP as usize {
264+ u32 :: try_from ( x ) . unwrap_or_else ( |_| {
261265 panic ! ( "nsTArray size may not exceed the capacity of a 32-bit sized int" ) ;
262- }
263- x as SizeType
266+ } )
264267 }
265268}
266269
@@ -329,22 +332,24 @@ impl Header {
329332#[ cfg( feature = "gecko-ffi" ) ]
330333impl Header {
331334 fn cap ( & self ) -> usize {
332- unpack_capacity ( self . _cap )
335+ unpack_capacity ( self . cap )
333336 }
334337
335338 fn set_cap ( & mut self , cap : usize ) {
339+ let cap_u32 = assert_size ( cap) ;
340+
336341 // debug check that our packing is working
337- debug_assert_eq ! ( unpack_capacity( pack_capacity( cap as SizeType ) ) , cap) ;
342+ debug_assert_eq ! ( unpack_capacity( pack_capacity( cap_u32 ) ) , cap) ;
338343 // FIXME: this assert is busted because it reads uninit memory
339344 // debug_assert!(!self.uses_stack_allocated_buffer());
340345
341346 // NOTE: this always stores a cleared auto bit, because set_cap
342347 // is only invoked by Rust, and Rust doesn't create auto arrays.
343- self . _cap = pack_capacity ( assert_size ( cap ) ) ;
348+ self . cap = pack_capacity ( cap_u32 ) ;
344349 }
345350
346351 fn uses_stack_allocated_buffer ( & self ) -> bool {
347- is_auto ( self . _cap )
352+ is_auto ( self . cap )
348353 }
349354}
350355
@@ -423,9 +428,11 @@ fn padding<T>() -> usize {
423428 let header_size = mem:: size_of :: < Header > ( ) ;
424429
425430 #[ cfg( feature = "gecko-ffi" ) ]
426- if alloc_align > header_size {
427- panic ! ( "nsTArray does not handle alignment above > {header_size} correctly" ) ;
428- }
431+ assert ! (
432+ alloc_align <= header_size,
433+ "nsTArray does not handle alignment above > {} correctly" ,
434+ header_size
435+ ) ;
429436
430437 alloc_align. saturating_sub ( header_size)
431438}
@@ -467,7 +474,7 @@ fn header_with_capacity<T>(cap: usize) -> NonNull<Header> {
467474 len : 0 ,
468475 cap : if mem:: size_of :: < T > ( ) == 0 {
469476 // "Infinite" capacity for zero-sized types:
470- MAX_CAP as SizeType
477+ MAX_CAP . try_into ( ) . unwrap ( )
471478 } else {
472479 assert_size ( cap)
473480 } ,
@@ -1136,6 +1143,10 @@ impl<T> ThinVec<T> {
11361143 ///
11371144 /// This method mimics the growth algorithm used by the C++ implementation
11381145 /// of nsTArray.
1146+ ///
1147+ /// # Panics
1148+ ///
1149+ /// This function will panic if the new capacity overflows `u32`.
11391150 #[ cfg( feature = "gecko-ffi" ) ]
11401151 pub fn reserve ( & mut self , additional : usize ) {
11411152 let elem_size = mem:: size_of :: < T > ( ) ;
@@ -1164,21 +1175,19 @@ impl<T> ThinVec<T> {
11641175 // Perform some checked arithmetic to ensure all of the numbers we
11651176 // compute will end up in range.
11661177 let will_fit = min_cap_bytes. checked_mul ( 2 ) . is_some ( ) ;
1167- if !will_fit {
1168- panic ! ( "Exceeded maximum nsTArray size" ) ;
1169- }
1178+ assert ! ( will_fit, "Exceeded maximum nsTArray size" ) ;
11701179
1171- const SLOW_GROWTH_THRESHOLD : usize = 8 * 1024 * 1024 ;
1180+ let slow_growth_threshold : usize = 8 * 1024 * 1024 ;
11721181
1173- let bytes = if min_cap > SLOW_GROWTH_THRESHOLD {
1182+ let bytes = if min_cap > slow_growth_threshold {
11741183 // Grow by a minimum of 1.125x
11751184 let old_cap_bytes = old_cap * elem_size + mem:: size_of :: < Header > ( ) ;
11761185 let min_growth = old_cap_bytes + ( old_cap_bytes >> 3 ) ;
11771186 let growth = max ( min_growth, min_cap_bytes as usize ) ;
11781187
11791188 // Round up to the next megabyte.
1180- const MB : usize = 1 << 20 ;
1181- MB * ( ( growth + MB - 1 ) / MB )
1189+ let megabyte = 1 << 20 ;
1190+ megabyte * ( ( growth + megabyte - 1 ) / megabyte )
11821191 } else {
11831192 // Try to allocate backing buffers in powers of two.
11841193 min_cap_bytes. next_power_of_two ( ) as usize
@@ -2670,6 +2679,7 @@ pub struct AutoThinVec<T, const N: usize> {
26702679impl < T , const N : usize > AutoThinVec < T , N > {
26712680 /// Implementation detail for the auto_thin_vec macro.
26722681 #[ inline]
2682+ #[ must_use]
26732683 #[ doc( hidden) ]
26742684 pub fn new_unpinned ( ) -> Self {
26752685 // This condition is hard-coded in nsTArray.h
@@ -2681,8 +2691,8 @@ impl<T, const N: usize> AutoThinVec<T, N> {
26812691 inner : ThinVec :: new ( ) ,
26822692 buffer : AutoBuffer {
26832693 header : Header {
2684- _len : 0 ,
2685- _cap : pack_capacity_and_auto ( N as SizeType , true ) ,
2694+ len : 0 ,
2695+ cap : pack_capacity_and_auto ( assert_size ( N ) , true ) ,
26862696 } ,
26872697 buffer : mem:: MaybeUninit :: uninit ( ) ,
26882698 } ,
@@ -2693,6 +2703,7 @@ impl<T, const N: usize> AutoThinVec<T, N> {
26932703 /// Returns a raw pointer to the inner ThinVec. Note that if you dereference it from rust, you
26942704 /// need to make sure not to move the ThinVec manually via something like
26952705 /// `std::mem::take(&mut auto_vec)`.
2706+ #[ must_use]
26962707 pub fn as_mut_ptr ( self : std:: pin:: Pin < & mut Self > ) -> * mut ThinVec < T > {
26972708 unsafe { & mut self . get_unchecked_mut ( ) . inner }
26982709 }
@@ -2721,13 +2732,13 @@ impl<T, const N: usize> AutoThinVec<T, N> {
27212732 let old_header = this. inner . ptr ( ) ;
27222733 let old_cap = this. inner . capacity ( ) ;
27232734 unsafe {
2724- ( this. buffer . buffer . as_mut_ptr ( ) as * mut T )
2725- . copy_from_nonoverlapping ( this. inner . data_raw ( ) , len) ;
2735+ let buffer = this. buffer . buffer . as_mut_ptr ( ) . cast :: < T > ( ) ;
2736+ buffer . copy_from_nonoverlapping ( this. inner . data_raw ( ) , len) ;
27262737 }
27272738 this. buffer . header . set_len ( len) ;
27282739 unsafe {
27292740 this. inner . ptr = NonNull :: new_unchecked ( & mut this. buffer . header ) ;
2730- dealloc ( old_header as * mut u8 , layout :: < T > ( old_cap) ) ;
2741+ dealloc ( old_header. cast :: < u8 > ( ) , layout :: < T > ( old_cap) ) ;
27312742 }
27322743 }
27332744}
@@ -2853,7 +2864,7 @@ mod tests {
28532864 }
28542865
28552866 #[ test]
2856- #[ cfg_attr( feature = "gecko-ffi" , should_panic) ]
2867+ #[ cfg_attr( feature = "gecko-ffi" , should_panic( expected = "" ) ) ]
28572868 fn test_overaligned_type_is_rejected_for_gecko_ffi_mode ( ) {
28582869 #[ repr( align( 16 ) ) ]
28592870 #[ allow( dead_code) ]
@@ -3996,7 +4007,10 @@ mod std_tests {
39964007 */
39974008
39984009 #[ test]
3999- #[ cfg_attr( feature = "gecko-ffi" , ignore) ]
4010+ #[ cfg_attr(
4011+ feature = "gecko-ffi" ,
4012+ ignore = "does not handle overaligned allocations"
4013+ ) ]
40004014 fn overaligned_allocations ( ) {
40014015 #[ repr( align( 256 ) ) ]
40024016 struct Foo ( usize ) ;
@@ -4417,7 +4431,7 @@ mod std_tests {
44174431 }
44184432
44194433 #[ test]
4420- #[ cfg_attr( feature = "gecko-ffi" , ignore) ]
4434+ #[ cfg_attr( feature = "gecko-ffi" , ignore = "header is different with gecko-ffi" ) ]
44214435 fn test_header_data ( ) {
44224436 macro_rules! assert_aligned_head_ptr {
44234437 ( $typename: ty) => { {
0 commit comments