Skip to content

Commit 06f049a

Browse files
committed
Auto merge of rust-lang#101837 - scottmcm:box-array-from-vec, r=m-ou-se
Add `Box<[T; N]>: TryFrom<Vec<T>>` We have `[T; N]: TryFrom<Vec<T>>` (rust-lang#76310) and `Box<[T; N]>: TryFrom<Box<[T]>>`, but not this combination. `vec.into_boxed_slice().try_into()` isn't quite a replacement for this, as that'll reallocate unnecessarily in the error case. **Insta-stable, so needs an FCP** (I tried to make this work with `, A`, but that's disallowed because of `#[fundamental]` rust-lang#29635 (comment))
2 parents 9c2797d + 4d3a31c commit 06f049a

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

library/alloc/src/boxed.rs

+50-1
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,22 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
16201620
}
16211621
}
16221622

1623+
/// Casts a boxed slice to a boxed array.
1624+
///
1625+
/// # Safety
1626+
///
1627+
/// `boxed_slice.len()` must be exactly `N`.
1628+
unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
1629+
boxed_slice: Box<[T], A>,
1630+
) -> Box<[T; N], A> {
1631+
debug_assert_eq!(boxed_slice.len(), N);
1632+
1633+
let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
1634+
// SAFETY: Pointer and allocator came from an existing box,
1635+
// and our safety condition requires that the length is exactly `N`
1636+
unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
1637+
}
1638+
16231639
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
16241640
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
16251641
type Error = Box<[T]>;
@@ -1635,13 +1651,46 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
16351651
/// `boxed_slice.len()` does not equal `N`.
16361652
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
16371653
if boxed_slice.len() == N {
1638-
Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })
1654+
Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
16391655
} else {
16401656
Err(boxed_slice)
16411657
}
16421658
}
16431659
}
16441660

1661+
#[cfg(not(no_global_oom_handling))]
1662+
#[stable(feature = "boxed_array_try_from_vec", since = "CURRENT_RUSTC_VERSION")]
1663+
impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
1664+
type Error = Vec<T>;
1665+
1666+
/// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
1667+
///
1668+
/// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
1669+
/// but will require a reallocation otherwise.
1670+
///
1671+
/// # Errors
1672+
///
1673+
/// Returns the original `Vec<T>` in the `Err` variant if
1674+
/// `boxed_slice.len()` does not equal `N`.
1675+
///
1676+
/// # Examples
1677+
///
1678+
/// This can be used with [`vec!`] to create an array on the heap:
1679+
///
1680+
/// ```
1681+
/// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
1682+
/// assert_eq!(state.len(), 100);
1683+
/// ```
1684+
fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
1685+
if vec.len() == N {
1686+
let boxed_slice = vec.into_boxed_slice();
1687+
Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
1688+
} else {
1689+
Err(vec)
1690+
}
1691+
}
1692+
}
1693+
16451694
impl<A: Allocator> Box<dyn Any, A> {
16461695
/// Attempt to downcast the box to a concrete type.
16471696
///

0 commit comments

Comments
 (0)