From 6092828d1f432bb313818e7cfab961c0e494f69e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 3 Sep 2020 19:59:51 -0700 Subject: [PATCH 1/3] Add `[T; N]: TryFrom>` This is very similar to the existing `Box<[T; N]>: TryFrom>`, but allows avoiding the `shrink_to_fit` if you have a vector and not a boxed slice. --- library/alloc/src/vec.rs | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 9013e3fc16a..b6d923daaf2 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -55,6 +55,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::cmp::{self, Ordering}; +use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; @@ -2771,6 +2772,57 @@ impl From<&str> for Vec { } } +#[stable(feature = "array_try_from_vec", since = "1.47.0")] +impl TryFrom> for [T; N] { + type Error = Vec; + + /// Gets the entire contents of the `Vec` as an array, + /// if its size exactly matches that of the requested array. + /// + /// # Examples + /// + /// ``` + /// use std::convert::TryInto; + /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3])); + /// assert_eq!(>::new().try_into(), Ok([])); + /// ``` + /// + /// If the length doesn't match, the input comes back in `Err`: + /// ``` + /// use std::convert::TryInto; + /// let r: Result<[i32; 4], _> = (0..10).collect::>().try_into(); + /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + /// ``` + /// + /// If you're fine with just getting a prefix of the `Vec`, + /// you can call [`.truncate(N)`](Vec::truncate) first. + /// ``` + /// use std::convert::TryInto; + /// let mut v = String::from("hello world").into_bytes(); + /// v.sort(); + /// v.truncate(2); + /// let [a, b]: [_; 2] = v.try_into().unwrap(); + /// assert_eq!(a, b' '); + /// assert_eq!(b, b'd'); + /// ``` + fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { + if vec.len() != N { + return Err(vec); + } + + // SAFETY: `.set_len(0)` is always sound. + unsafe { vec.set_len(0) }; + + // SAFETY: A `Vec`'s pointer is always aligned property, and + // the alignment the array needs is the same as the items. + // We checked earlier that we have sufficient items. + // The items will not double-drop as the `set_len` + // tells the `Vec` not to also drop them. + let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) }; + Ok(array) + } +} + //////////////////////////////////////////////////////////////////////////////// // Clone-on-write //////////////////////////////////////////////////////////////////////////////// From 2c8a4c8f73e8b36e72b15e7f97ef29ad36c15e17 Mon Sep 17 00:00:00 2001 From: scottmcm Date: Sat, 5 Sep 2020 19:02:21 +0000 Subject: [PATCH 2/3] Nightly is currently 1.48 --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b6d923daaf2..4a263829bd4 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2772,7 +2772,7 @@ impl From<&str> for Vec { } } -#[stable(feature = "array_try_from_vec", since = "1.47.0")] +#[stable(feature = "array_try_from_vec", since = "1.48.0")] impl TryFrom> for [T; N] { type Error = Vec; From 3d89ee9586354e736cfe4a472d8aaa507d10f77c Mon Sep 17 00:00:00 2001 From: scottmcm Date: Mon, 7 Sep 2020 02:30:42 +0000 Subject: [PATCH 3/3] Typo fix Thanks, Amanieu Co-authored-by: Amanieu d'Antras --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 4a263829bd4..ccba23f6848 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2813,7 +2813,7 @@ impl TryFrom> for [T; N] { // SAFETY: `.set_len(0)` is always sound. unsafe { vec.set_len(0) }; - // SAFETY: A `Vec`'s pointer is always aligned property, and + // SAFETY: A `Vec`'s pointer is always aligned properly, and // the alignment the array needs is the same as the items. // We checked earlier that we have sufficient items. // The items will not double-drop as the `set_len`