From 13221770a30d4bd56df9e8db6dc7fd95da56f8fc Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Thu, 21 Sep 2017 16:35:23 -0400 Subject: [PATCH 1/7] Implement TryFrom for array reference types There are many cases where a buffer with a static compile-time size is preferred over a slice with a dynamic size. This allows for performing a checked conversion from &[T] to &[T; N]. This may also lead to compile-time optimizations involving [T; N] such as loop unrolling. --- src/libcore/array.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 6a7926fecde38..5f222e249ea84 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -21,6 +21,7 @@ use borrow::{Borrow, BorrowMut}; use cmp::Ordering; +use convert::TryFrom; use fmt; use hash::{Hash, self}; use marker::Unsize; @@ -57,6 +58,11 @@ unsafe impl> FixedSizeArray for A { } } +/// The error type returned when a conversion from a slice to an array fails. +#[unstable(feature = "try_from", issue = "33417")] +#[derive(Debug, Copy, Clone)] +pub struct TryFromSliceError(()); + macro_rules! __impl_slice_eq1 { ($Lhs: ty, $Rhs: ty) => { __impl_slice_eq1! { $Lhs, $Rhs, Sized } @@ -123,6 +129,34 @@ macro_rules! array_impls { } } + #[unstable(feature = "try_from", issue = "33417")] + impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { + type Error = TryFromSliceError; + + fn try_from(slice: &[T]) -> Result<&[T; $N], TryFromSliceError> { + if slice.len() == $N { + let ptr = slice.as_ptr() as *const [T; $N]; + unsafe { Ok(&*ptr) } + } else { + Err(TryFromSliceError(())) + } + } + } + + #[unstable(feature = "try_from", issue = "33417")] + impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { + type Error = TryFromSliceError; + + fn try_from(slice: &mut [T]) -> Result<&mut [T; $N], TryFromSliceError> { + if slice.len() == $N { + let ptr = slice.as_mut_ptr() as *mut [T; $N]; + unsafe { Ok(&mut *ptr) } + } else { + Err(TryFromSliceError(())) + } + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Hash for [T; $N] { fn hash(&self, state: &mut H) { From 6570e4cd05f07994401b177d2692d1ae8429a92d Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Sun, 24 Sep 2017 12:35:37 -0400 Subject: [PATCH 2/7] Add TryFrom tests for array reference types --- src/libcore/tests/array.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs index 6af031dee5845..a3bd9220929a2 100644 --- a/src/libcore/tests/array.rs +++ b/src/libcore/tests/array.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use core::array::FixedSizeArray; +use core::convert::TryFrom; #[test] fn fixed_size_array() { @@ -26,3 +27,25 @@ fn fixed_size_array() { assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0); assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0); } + +#[test] +fn array_try_from() { + macro_rules! test { + ($($N:expr)+) => { + $({ + type Array = [u8; $N]; + let array: Array = [0; $N]; + let slice: &[u8] = &array[..]; + + let result = <&Array>::try_from(slice); + assert_eq!(Ok(&array), result); + })+ + } + } + test! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 + } +} From a6e70b5fb48ff6e0ecee12435df78ec91b91664d Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Sun, 24 Sep 2017 14:54:04 -0400 Subject: [PATCH 3/7] Try to fix array TryFrom tests --- src/libcore/tests/array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs index a3bd9220929a2..6278d5e23e0d6 100644 --- a/src/libcore/tests/array.rs +++ b/src/libcore/tests/array.rs @@ -38,7 +38,7 @@ fn array_try_from() { let slice: &[u8] = &array[..]; let result = <&Array>::try_from(slice); - assert_eq!(Ok(&array), result); + assert_eq!(&array, result.unwrap()); })+ } } From e45e8abec2302530d774aab1ca800081b60aa89e Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Fri, 29 Sep 2017 11:15:05 -0400 Subject: [PATCH 4/7] Implement Error trait for TryFromSliceError --- src/libcore/array.rs | 15 +++++++++++++++ src/libstd/error.rs | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 5f222e249ea84..3d13a84e23279 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -63,6 +63,21 @@ unsafe impl> FixedSizeArray for A { #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); +impl fmt::Display for TryFromSliceError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.__description()) + } +} + +impl TryFromSliceError { + #[inline] + #[doc(hidden)] + pub fn __description(&self) -> &str { + "could not convert slice to array" + } +} + macro_rules! __impl_slice_eq1 { ($Lhs: ty, $Rhs: ty) => { __impl_slice_eq1! { $Lhs, $Rhs, Sized } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 6d64ea0d50332..72d1946a28698 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -56,6 +56,7 @@ use any::TypeId; use borrow::Cow; use cell; use char; +use core::array; use fmt::{self, Debug, Display}; use mem::transmute; use num; @@ -281,6 +282,13 @@ impl Error for num::TryFromIntError { } } +#[unstable(feature = "try_from", issue = "33417")] +impl Error for array::TryFromSliceError { + fn description(&self) -> &str { + self.__description() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseFloatError { fn description(&self) -> &str { From e41610c5eda1dea31f7bf53b566ea850a6a9c8cc Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Fri, 29 Sep 2017 11:20:21 -0400 Subject: [PATCH 5/7] Make TryFromSliceError::__description unstable Enforces use of Error::description instead. --- src/libcore/array.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d13a84e23279..3d09424f8ba61 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -71,6 +71,10 @@ impl fmt::Display for TryFromSliceError { } impl TryFromSliceError { + #[unstable(feature = "array_error_internals", + reason = "available through Error trait and this method should not \ + be exposed publicly", + issue = "0")] #[inline] #[doc(hidden)] pub fn __description(&self) -> &str { From d2cf66b26c388293e5ad89c6a46e6e09a4052bb8 Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Fri, 29 Sep 2017 11:26:19 -0400 Subject: [PATCH 6/7] Pass formatter in TryFromSliceError Display impl --- src/libcore/array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d09424f8ba61..3d24f8902bd83 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -66,7 +66,7 @@ pub struct TryFromSliceError(()); impl fmt::Display for TryFromSliceError { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.__description()) + fmt::Display::fmt(self.__description(), f) } } From d9d877221f65b26e52f49bfc639ef705ff396deb Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Fri, 29 Sep 2017 13:30:03 -0400 Subject: [PATCH 7/7] Enable required features for core::array in libstd --- src/libstd/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9fc7e2c01aa19..05555d876a8d6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -243,6 +243,7 @@ #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(align_offset)] +#![feature(array_error_internals)] #![feature(asm)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] @@ -257,6 +258,7 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] +#![feature(fixed_size_array)] #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)]