Auto merge of #44764 - nvzqz:master, r=alexcrichton

Implement TryFrom<&[T]> for &[T; N]

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.

This is my first PR to Rust, so I'm not sure if discussion of this change should happen here or does it need its own RFC? I figured these changes would be a subset of #33417.
This commit is contained in:
bors 2017-10-31 23:06:37 +00:00
commit f3b900cc3b
4 changed files with 86 additions and 0 deletions

View File

@ -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,30 @@ unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> 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(());
impl fmt::Display for TryFromSliceError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.__description(), f)
}
}
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 {
"could not convert slice to array"
}
}
macro_rules! __impl_slice_eq1 {
($Lhs: ty, $Rhs: ty) => {
__impl_slice_eq1! { $Lhs, $Rhs, Sized }
@ -123,6 +148,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<T: Hash> Hash for [T; $N] {
fn hash<H: hash::Hasher>(&self, state: &mut H) {

View File

@ -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!(&array, result.unwrap());
})+
}
}
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
}
}

View File

@ -57,6 +57,7 @@ use borrow::Cow;
use cell;
use char;
use convert;
use core::array;
use fmt::{self, Debug, Display};
use mem::transmute;
use num;
@ -282,6 +283,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 {

View File

@ -243,6 +243,7 @@
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
#![feature(align_offset)]
#![feature(array_error_internals)]
#![feature(asm)]
#![feature(attr_literals)]
#![feature(box_syntax)]
@ -267,6 +268,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)]