Skip to content

Commit 4d3a31c

Browse files
committed
Add Box<[T; N]>: TryFrom<Vec<T>>
We have `[T; N]: TryFrom<Vec<T>>` and `Box<[T; N]>: TryFrom<Box<[T]>>`, but not the 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**
1 parent addacb5 commit 4d3a31c

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

Diff for: library/alloc/src/boxed.rs

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

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

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

0 commit comments

Comments
 (0)