@@ -293,6 +293,15 @@ struct RcBox<T: ?Sized> {
293
293
value : T ,
294
294
}
295
295
296
+ /// Calculate layout for `RcBox<T>` using the inner value's layout
297
+ fn rcbox_layout_for_value_layout ( layout : Layout ) -> Layout {
298
+ // Calculate layout using the given value layout.
299
+ // Previously, layout was calculated on the expression
300
+ // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
301
+ // reference (see #54908).
302
+ Layout :: new :: < RcBox < ( ) > > ( ) . extend ( layout) . unwrap ( ) . 0 . pad_to_align ( )
303
+ }
304
+
296
305
/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference
297
306
/// Counted'.
298
307
///
@@ -1334,11 +1343,7 @@ impl<T: ?Sized> Rc<T> {
1334
1343
allocate : impl FnOnce ( Layout ) -> Result < NonNull < [ u8 ] > , AllocError > ,
1335
1344
mem_to_rcbox : impl FnOnce ( * mut u8 ) -> * mut RcBox < T > ,
1336
1345
) -> * mut RcBox < T > {
1337
- // Calculate layout using the given value layout.
1338
- // Previously, layout was calculated on the expression
1339
- // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
1340
- // reference (see #54908).
1341
- let layout = Layout :: new :: < RcBox < ( ) > > ( ) . extend ( value_layout) . unwrap ( ) . 0 . pad_to_align ( ) ;
1346
+ let layout = rcbox_layout_for_value_layout ( value_layout) ;
1342
1347
unsafe {
1343
1348
Rc :: try_allocate_for_layout ( value_layout, allocate, mem_to_rcbox)
1344
1349
. unwrap_or_else ( |_| handle_alloc_error ( layout) )
@@ -1357,11 +1362,7 @@ impl<T: ?Sized> Rc<T> {
1357
1362
allocate : impl FnOnce ( Layout ) -> Result < NonNull < [ u8 ] > , AllocError > ,
1358
1363
mem_to_rcbox : impl FnOnce ( * mut u8 ) -> * mut RcBox < T > ,
1359
1364
) -> Result < * mut RcBox < T > , AllocError > {
1360
- // Calculate layout using the given value layout.
1361
- // Previously, layout was calculated on the expression
1362
- // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
1363
- // reference (see #54908).
1364
- let layout = Layout :: new :: < RcBox < ( ) > > ( ) . extend ( value_layout) . unwrap ( ) . 0 . pad_to_align ( ) ;
1365
+ let layout = rcbox_layout_for_value_layout ( value_layout) ;
1365
1366
1366
1367
// Allocate for the layout.
1367
1368
let ptr = allocate ( layout) ?;
@@ -1428,7 +1429,7 @@ impl<T> Rc<[T]> {
1428
1429
}
1429
1430
}
1430
1431
1431
- /// Copy elements from slice into newly allocated Rc<\[T\]>
1432
+ /// Copy elements from slice into newly allocated ` Rc<[T]>`
1432
1433
///
1433
1434
/// Unsafe because the caller must either take ownership or bind `T: Copy`
1434
1435
#[ cfg( not( no_global_oom_handling) ) ]
@@ -1440,6 +1441,48 @@ impl<T> Rc<[T]> {
1440
1441
}
1441
1442
}
1442
1443
1444
+ /// Create an `Rc<[T]>` by reusing the underlying memory
1445
+ /// of a `Vec<T>`. This will return the vector if the existing allocation
1446
+ /// is not large enough.
1447
+ #[ cfg( not( no_global_oom_handling) ) ]
1448
+ fn try_from_vec_in_place ( mut v : Vec < T > ) -> Result < Rc < [ T ] > , Vec < T > > {
1449
+ let layout_elements = Layout :: array :: < T > ( v. len ( ) ) . unwrap ( ) ;
1450
+ let layout_allocation = Layout :: array :: < T > ( v. capacity ( ) ) . unwrap ( ) ;
1451
+ let layout_rcbox = rcbox_layout_for_value_layout ( layout_elements) ;
1452
+ let mut ptr = NonNull :: new ( v. as_mut_ptr ( ) ) . expect ( "`Vec<T>` stores `NonNull<T>`" ) ;
1453
+ if layout_rcbox. size ( ) > layout_allocation. size ( )
1454
+ || layout_rcbox. align ( ) > layout_allocation. align ( )
1455
+ {
1456
+ // Can't fit - calling `grow` would involve `realloc`
1457
+ // (which copies the elements), followed by copying again.
1458
+ return Err ( v) ;
1459
+ }
1460
+ if layout_rcbox. size ( ) < layout_allocation. size ( )
1461
+ || layout_rcbox. align ( ) < layout_allocation. align ( )
1462
+ {
1463
+ // We need to shrink the allocation so that it fits
1464
+ // https://doc.rust-lang.org/nightly/std/alloc/trait.Allocator.html#memory-fitting
1465
+ // SAFETY:
1466
+ // - Vec allocates by requesting `Layout::array::<T>(capacity)`, so this capacity matches
1467
+ // - `layout_rcbox` is smaller
1468
+ // If this fails, the ownership has not been transferred
1469
+ if let Ok ( p) = unsafe { Global . shrink ( ptr. cast ( ) , layout_allocation, layout_rcbox) } {
1470
+ ptr = p. cast ( ) ;
1471
+ } else {
1472
+ return Err ( v) ;
1473
+ }
1474
+ }
1475
+ // Make sure the vec's memory isn't deallocated now
1476
+ let v = mem:: ManuallyDrop :: new ( v) ;
1477
+ let ptr: * mut RcBox < [ T ] > = ptr:: slice_from_raw_parts_mut ( ptr. as_ptr ( ) , v. len ( ) ) as _ ;
1478
+ unsafe {
1479
+ ptr:: copy ( ptr. cast :: < T > ( ) , & mut ( * ptr) . value as * mut [ T ] as * mut T , v. len ( ) ) ;
1480
+ ptr:: write ( & mut ( * ptr) . strong , Cell :: new ( 1 ) ) ;
1481
+ ptr:: write ( & mut ( * ptr) . weak , Cell :: new ( 1 ) ) ;
1482
+ Ok ( Self :: from_ptr ( ptr) )
1483
+ }
1484
+ }
1485
+
1443
1486
/// Constructs an `Rc<[T]>` from an iterator known to be of a certain size.
1444
1487
///
1445
1488
/// Behavior is undefined should the size be wrong.
@@ -1965,14 +2008,17 @@ impl<T> From<Vec<T>> for Rc<[T]> {
1965
2008
/// assert_eq!(vec![1, 2, 3], *shared);
1966
2009
/// ```
1967
2010
#[ inline]
1968
- fn from ( mut v : Vec < T > ) -> Rc < [ T ] > {
1969
- unsafe {
1970
- let rc = Rc :: copy_from_slice ( & v) ;
1971
-
1972
- // Allow the Vec to free its memory, but not destroy its contents
1973
- v. set_len ( 0 ) ;
1974
-
1975
- rc
2011
+ fn from ( v : Vec < T > ) -> Rc < [ T ] > {
2012
+ match Rc :: try_from_vec_in_place ( v) {
2013
+ Ok ( rc) => rc,
2014
+ Err ( mut v) => {
2015
+ unsafe {
2016
+ let rc = Rc :: copy_from_slice ( & v) ;
2017
+ // Allow the Vec to free its memory, but not destroy its contents
2018
+ v. set_len ( 0 ) ;
2019
+ rc
2020
+ }
2021
+ }
1976
2022
}
1977
2023
}
1978
2024
}
0 commit comments