mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #101837 - scottmcm:box-array-from-vec, r=m-ou-se
Add `Box<[T; N]>: TryFrom<Vec<T>>` We have `[T; N]: TryFrom<Vec<T>>` (#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]` https://github.com/rust-lang/rust/issues/29635#issuecomment-1247598385)
This commit is contained in:
commit
06f049a355
@ -1620,6 +1620,22 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Casts a boxed slice to a boxed array.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `boxed_slice.len()` must be exactly `N`.
|
||||
unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
|
||||
boxed_slice: Box<[T], A>,
|
||||
) -> Box<[T; N], A> {
|
||||
debug_assert_eq!(boxed_slice.len(), N);
|
||||
|
||||
let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
|
||||
// SAFETY: Pointer and allocator came from an existing box,
|
||||
// and our safety condition requires that the length is exactly `N`
|
||||
unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
|
||||
}
|
||||
|
||||
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
|
||||
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
|
||||
type Error = Box<[T]>;
|
||||
@ -1635,13 +1651,46 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
|
||||
/// `boxed_slice.len()` does not equal `N`.
|
||||
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
|
||||
if boxed_slice.len() == N {
|
||||
Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })
|
||||
Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
|
||||
} else {
|
||||
Err(boxed_slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "boxed_array_try_from_vec", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
|
||||
type Error = Vec<T>;
|
||||
|
||||
/// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
|
||||
///
|
||||
/// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
|
||||
/// but will require a reallocation otherwise.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns the original `Vec<T>` in the `Err` variant if
|
||||
/// `boxed_slice.len()` does not equal `N`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This can be used with [`vec!`] to create an array on the heap:
|
||||
///
|
||||
/// ```
|
||||
/// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
|
||||
/// assert_eq!(state.len(), 100);
|
||||
/// ```
|
||||
fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
|
||||
if vec.len() == N {
|
||||
let boxed_slice = vec.into_boxed_slice();
|
||||
Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
|
||||
} else {
|
||||
Err(vec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Allocator> Box<dyn Any, A> {
|
||||
/// Attempt to downcast the box to a concrete type.
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user