@@ -163,10 +163,10 @@ mod fallible {
163
163
#[ cfg( feature = "mp4parse_fallible" ) ]
164
164
extern "C" {
165
165
fn malloc ( bytes : usize ) -> * mut u8 ;
166
+ fn realloc ( ptr : * mut u8 , bytes : usize ) -> * mut u8 ;
166
167
}
167
168
168
169
#[ cfg( feature = "mp4parse_fallible" ) ]
169
- use mp4parse_fallible:: FallibleVec ;
170
170
use std:: cmp:: PartialEq ;
171
171
use std:: convert:: TryInto as _;
172
172
use std:: hash:: Hash ;
@@ -236,20 +236,21 @@ mod fallible {
236
236
#[ cfg( feature = "mp4parse_fallible" ) ]
237
237
{
238
238
let size = std:: mem:: size_of :: < T > ( ) ;
239
- unsafe {
240
- let new_ptr = malloc ( size) as * mut T ;
241
- if new_ptr. is_null ( ) {
242
- return Err ( super :: Error :: OutOfMemory ) ;
243
- }
239
+ let new_ptr = unsafe { malloc ( size) as * mut T } ;
244
240
245
- // If we did a simple assignment: *new_ptr = x, then the
246
- // value pointed to by new_ptr would immediately be
247
- // dropped, but that would cause an invalid memory access.
248
- // Instead, we use replace() to avoid the immediate drop
249
- // and forget() to ensure that drop never happens.
250
- std:: mem:: forget ( std:: mem:: replace ( & mut * new_ptr, x) ) ;
251
- inner = Box :: from_raw ( new_ptr) ;
241
+ if new_ptr. is_null ( ) {
242
+ return Err ( super :: Error :: OutOfMemory ) ;
252
243
}
244
+
245
+ // If we did a simple assignment: *new_ptr = x, then the value
246
+ // pointed to by new_ptr would immediately be dropped, but
247
+ // that would cause an invalid memory access. Instead, we use
248
+ // replace() to avoid the immediate drop and forget() to
249
+ // ensure that drop never happens.
250
+ inner = unsafe {
251
+ std:: mem:: forget ( std:: mem:: replace ( & mut * new_ptr, x) ) ;
252
+ Box :: from_raw ( new_ptr)
253
+ } ;
253
254
}
254
255
#[ cfg( not( feature = "mp4parse_fallible" ) ) ]
255
256
{
@@ -393,8 +394,24 @@ mod fallible {
393
394
fn reserve ( & mut self , additional : usize ) -> Result < ( ) > {
394
395
#[ cfg( feature = "mp4parse_fallible" ) ]
395
396
{
396
- FallibleVec :: try_reserve ( & mut self . inner , additional)
397
- . map_err ( |_| super :: Error :: OutOfMemory )
397
+ let available = self
398
+ . inner
399
+ . capacity ( )
400
+ . checked_sub ( self . inner . len ( ) )
401
+ . expect ( "capacity >= len" ) ;
402
+ if additional > available {
403
+ let increase = additional
404
+ . checked_sub ( available)
405
+ . expect ( "additional > available" ) ;
406
+ let new_cap = self
407
+ . inner
408
+ . capacity ( )
409
+ . checked_add ( increase)
410
+ . ok_or ( super :: Error :: OutOfMemory ) ?;
411
+ self . try_extend ( new_cap) ?;
412
+ debug_assert ! ( self . inner. capacity( ) == new_cap) ;
413
+ }
414
+ Ok ( ( ) )
398
415
}
399
416
#[ cfg( not( feature = "mp4parse_fallible" ) ) ]
400
417
{
@@ -411,6 +428,39 @@ mod fallible {
411
428
self . inner . resize_with ( new_len, f) ;
412
429
Ok ( ( ) )
413
430
}
431
+
432
+ #[ cfg( feature = "mp4parse_fallible" ) ]
433
+ fn try_extend ( & mut self , new_cap : usize ) -> Result < ( ) > {
434
+ let old_ptr = self . as_mut_ptr ( ) ;
435
+ let old_len = self . inner . len ( ) ;
436
+
437
+ let old_cap: usize = self . inner . capacity ( ) ;
438
+
439
+ if old_cap >= new_cap {
440
+ return Ok ( ( ) ) ;
441
+ }
442
+
443
+ let new_size_bytes = new_cap
444
+ . checked_mul ( std:: mem:: size_of :: < T > ( ) )
445
+ . ok_or ( super :: Error :: OutOfMemory ) ?;
446
+
447
+ let new_ptr = unsafe {
448
+ if old_cap == 0 {
449
+ malloc ( new_size_bytes)
450
+ } else {
451
+ realloc ( old_ptr as * mut u8 , new_size_bytes)
452
+ }
453
+ } ;
454
+
455
+ if new_ptr. is_null ( ) {
456
+ return Err ( super :: Error :: OutOfMemory ) ;
457
+ }
458
+
459
+ let new_vec = unsafe { Vec :: from_raw_parts ( new_ptr as * mut T , old_len, new_cap) } ;
460
+
461
+ std:: mem:: forget ( std:: mem:: replace ( & mut self . inner , new_vec) ) ;
462
+ Ok ( ( ) )
463
+ }
414
464
}
415
465
416
466
impl < T : Clone > TryVec < TryVec < T > > {
@@ -432,6 +482,53 @@ mod fallible {
432
482
}
433
483
}
434
484
485
+ #[ test]
486
+ #[ cfg( feature = "mp4parse_fallible" ) ]
487
+ fn oom ( ) {
488
+ let mut vec: TryVec < char > = TryVec :: new ( ) ;
489
+ match vec. reserve ( std:: usize:: MAX ) {
490
+ Ok ( _) => panic ! ( "it should be OOM" ) ,
491
+ _ => ( ) ,
492
+ }
493
+ }
494
+
495
+ #[ test]
496
+ fn try_reserve ( ) {
497
+ let mut vec: TryVec < _ > = vec ! [ 1 ] . into ( ) ;
498
+ let old_cap = vec. inner . capacity ( ) ;
499
+ let new_cap = old_cap + 1 ;
500
+ vec. reserve ( new_cap) . unwrap ( ) ;
501
+ assert ! ( vec. inner. capacity( ) >= new_cap) ;
502
+ }
503
+
504
+ #[ test]
505
+ fn try_reserve_idempotent ( ) {
506
+ let mut vec: TryVec < _ > = vec ! [ 1 ] . into ( ) ;
507
+ let old_cap = vec. inner . capacity ( ) ;
508
+ let new_cap = old_cap + 1 ;
509
+ vec. reserve ( new_cap) . unwrap ( ) ;
510
+ let cap_after_reserve = vec. inner . capacity ( ) ;
511
+ vec. reserve ( new_cap) . unwrap ( ) ;
512
+ assert_eq ! ( cap_after_reserve, vec. inner. capacity( ) ) ;
513
+ }
514
+
515
+ #[ test]
516
+ #[ cfg( feature = "mp4parse_fallible" ) ]
517
+ fn capacity_overflow ( ) {
518
+ let mut vec: TryVec < _ > = vec ! [ 1 ] . into ( ) ;
519
+ match vec. reserve ( std:: usize:: MAX ) {
520
+ Ok ( _) => panic ! ( "capacity calculation should overflow" ) ,
521
+ _ => ( ) ,
522
+ }
523
+ }
524
+
525
+ #[ test]
526
+ fn extend_from_slice ( ) {
527
+ let mut vec: TryVec < u8 > = b"foo" . as_ref ( ) . try_into ( ) . unwrap ( ) ;
528
+ vec. extend_from_slice ( b"bar" ) . unwrap ( ) ;
529
+ assert_eq ! ( vec, b"foobar" . as_ref( ) ) ;
530
+ }
531
+
435
532
impl < T > IntoIterator for TryVec < T > {
436
533
type Item = T ;
437
534
type IntoIter = std:: vec:: IntoIter < T > ;
@@ -491,6 +588,16 @@ mod fallible {
491
588
}
492
589
}
493
590
591
+ impl < T : Clone > std:: convert:: TryFrom < & [ T ] > for TryVec < T > {
592
+ type Error = super :: Error ;
593
+
594
+ fn try_from ( value : & [ T ] ) -> Result < Self > {
595
+ let mut v = Self :: new ( ) ;
596
+ v. extend_from_slice ( value) ?;
597
+ Ok ( v)
598
+ }
599
+ }
600
+
494
601
impl std:: convert:: TryFrom < & str > for TryVec < u8 > {
495
602
type Error = super :: Error ;
496
603
0 commit comments