Skip to content

Commit bac2f39

Browse files
authored
Rollup merge of #76310 - scottmcm:array-try_from-vec, r=dtolnay
Add `[T; N]: TryFrom<Vec<T>>` (insta-stable) This is very similar to the [existing](https://doc.rust-lang.org/nightly/std/convert/trait.TryFrom.html#impl-TryFrom%3CBox%3C%5BT%5D%3E%3E) `Box<[T; N]>: TryFrom<Box<[T]>>`, but allows avoiding the `shrink_to_fit` if you have a vector and not a boxed slice. Like the slice equivalents of this, it fails if the length of the vector is not exactly `N`. This uses `Vec<T>` as the `Error` type to return the input, like how the `Rc<[T]> -> Rc<[T; N]>` (and Arc) ones also reflect the input directly in the error type. ```rust #[stable(feature = "array_try_from_vec", since = "1.47.0")] impl<T, const N: usize> TryFrom<Vec<T>> for [T; N] { type Error = Vec<T>; fn try_from(mut vec: Vec<T>) -> Result<[T; N], Vec<T>>; } ``` Inspired by this zulip thread: https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/APIs.20for.20getting.20stuff.20from.20a.20Vec.20by.20owned/near/209048103
2 parents 3ebba83 + 3d89ee9 commit bac2f39

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

library/alloc/src/vec.rs

+52
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#![stable(feature = "rust1", since = "1.0.0")]
5656

5757
use core::cmp::{self, Ordering};
58+
use core::convert::TryFrom;
5859
use core::fmt;
5960
use core::hash::{Hash, Hasher};
6061
use core::intrinsics::{arith_offset, assume};
@@ -2754,6 +2755,57 @@ impl From<&str> for Vec<u8> {
27542755
}
27552756
}
27562757

2758+
#[stable(feature = "array_try_from_vec", since = "1.48.0")]
2759+
impl<T, const N: usize> TryFrom<Vec<T>> for [T; N] {
2760+
type Error = Vec<T>;
2761+
2762+
/// Gets the entire contents of the `Vec<T>` as an array,
2763+
/// if its size exactly matches that of the requested array.
2764+
///
2765+
/// # Examples
2766+
///
2767+
/// ```
2768+
/// use std::convert::TryInto;
2769+
/// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
2770+
/// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
2771+
/// ```
2772+
///
2773+
/// If the length doesn't match, the input comes back in `Err`:
2774+
/// ```
2775+
/// use std::convert::TryInto;
2776+
/// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
2777+
/// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
2778+
/// ```
2779+
///
2780+
/// If you're fine with just getting a prefix of the `Vec<T>`,
2781+
/// you can call [`.truncate(N)`](Vec::truncate) first.
2782+
/// ```
2783+
/// use std::convert::TryInto;
2784+
/// let mut v = String::from("hello world").into_bytes();
2785+
/// v.sort();
2786+
/// v.truncate(2);
2787+
/// let [a, b]: [_; 2] = v.try_into().unwrap();
2788+
/// assert_eq!(a, b' ');
2789+
/// assert_eq!(b, b'd');
2790+
/// ```
2791+
fn try_from(mut vec: Vec<T>) -> Result<[T; N], Vec<T>> {
2792+
if vec.len() != N {
2793+
return Err(vec);
2794+
}
2795+
2796+
// SAFETY: `.set_len(0)` is always sound.
2797+
unsafe { vec.set_len(0) };
2798+
2799+
// SAFETY: A `Vec`'s pointer is always aligned properly, and
2800+
// the alignment the array needs is the same as the items.
2801+
// We checked earlier that we have sufficient items.
2802+
// The items will not double-drop as the `set_len`
2803+
// tells the `Vec` not to also drop them.
2804+
let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) };
2805+
Ok(array)
2806+
}
2807+
}
2808+
27572809
////////////////////////////////////////////////////////////////////////////////
27582810
// Clone-on-write
27592811
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)