Skip to content

Commit f3b900c

Browse files
committed
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.
2 parents 8b22e70 + 4c853ad commit f3b900c

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

src/libcore/array.rs

+53
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
use borrow::{Borrow, BorrowMut};
2323
use cmp::Ordering;
24+
use convert::TryFrom;
2425
use fmt;
2526
use hash::{Hash, self};
2627
use marker::Unsize;
@@ -57,6 +58,30 @@ unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
5758
}
5859
}
5960

61+
/// The error type returned when a conversion from a slice to an array fails.
62+
#[unstable(feature = "try_from", issue = "33417")]
63+
#[derive(Debug, Copy, Clone)]
64+
pub struct TryFromSliceError(());
65+
66+
impl fmt::Display for TryFromSliceError {
67+
#[inline]
68+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69+
fmt::Display::fmt(self.__description(), f)
70+
}
71+
}
72+
73+
impl TryFromSliceError {
74+
#[unstable(feature = "array_error_internals",
75+
reason = "available through Error trait and this method should not \
76+
be exposed publicly",
77+
issue = "0")]
78+
#[inline]
79+
#[doc(hidden)]
80+
pub fn __description(&self) -> &str {
81+
"could not convert slice to array"
82+
}
83+
}
84+
6085
macro_rules! __impl_slice_eq1 {
6186
($Lhs: ty, $Rhs: ty) => {
6287
__impl_slice_eq1! { $Lhs, $Rhs, Sized }
@@ -123,6 +148,34 @@ macro_rules! array_impls {
123148
}
124149
}
125150

151+
#[unstable(feature = "try_from", issue = "33417")]
152+
impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] {
153+
type Error = TryFromSliceError;
154+
155+
fn try_from(slice: &[T]) -> Result<&[T; $N], TryFromSliceError> {
156+
if slice.len() == $N {
157+
let ptr = slice.as_ptr() as *const [T; $N];
158+
unsafe { Ok(&*ptr) }
159+
} else {
160+
Err(TryFromSliceError(()))
161+
}
162+
}
163+
}
164+
165+
#[unstable(feature = "try_from", issue = "33417")]
166+
impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] {
167+
type Error = TryFromSliceError;
168+
169+
fn try_from(slice: &mut [T]) -> Result<&mut [T; $N], TryFromSliceError> {
170+
if slice.len() == $N {
171+
let ptr = slice.as_mut_ptr() as *mut [T; $N];
172+
unsafe { Ok(&mut *ptr) }
173+
} else {
174+
Err(TryFromSliceError(()))
175+
}
176+
}
177+
}
178+
126179
#[stable(feature = "rust1", since = "1.0.0")]
127180
impl<T: Hash> Hash for [T; $N] {
128181
fn hash<H: hash::Hasher>(&self, state: &mut H) {

src/libcore/tests/array.rs

+23
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010
use core::array::FixedSizeArray;
11+
use core::convert::TryFrom;
1112

1213
#[test]
1314
fn fixed_size_array() {
@@ -26,3 +27,25 @@ fn fixed_size_array() {
2627
assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0);
2728
assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0);
2829
}
30+
31+
#[test]
32+
fn array_try_from() {
33+
macro_rules! test {
34+
($($N:expr)+) => {
35+
$({
36+
type Array = [u8; $N];
37+
let array: Array = [0; $N];
38+
let slice: &[u8] = &array[..];
39+
40+
let result = <&Array>::try_from(slice);
41+
assert_eq!(&array, result.unwrap());
42+
})+
43+
}
44+
}
45+
test! {
46+
0 1 2 3 4 5 6 7 8 9
47+
10 11 12 13 14 15 16 17 18 19
48+
20 21 22 23 24 25 26 27 28 29
49+
30 31 32
50+
}
51+
}

src/libstd/error.rs

+8
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use borrow::Cow;
5757
use cell;
5858
use char;
5959
use convert;
60+
use core::array;
6061
use fmt::{self, Debug, Display};
6162
use mem::transmute;
6263
use num;
@@ -282,6 +283,13 @@ impl Error for num::TryFromIntError {
282283
}
283284
}
284285

286+
#[unstable(feature = "try_from", issue = "33417")]
287+
impl Error for array::TryFromSliceError {
288+
fn description(&self) -> &str {
289+
self.__description()
290+
}
291+
}
292+
285293
#[stable(feature = "rust1", since = "1.0.0")]
286294
impl Error for num::ParseFloatError {
287295
fn description(&self) -> &str {

src/libstd/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@
243243
#![feature(allow_internal_unsafe)]
244244
#![feature(allow_internal_unstable)]
245245
#![feature(align_offset)]
246+
#![feature(array_error_internals)]
246247
#![feature(asm)]
247248
#![feature(attr_literals)]
248249
#![feature(box_syntax)]
@@ -267,6 +268,7 @@
267268
#![feature(core_intrinsics)]
268269
#![feature(dropck_eyepatch)]
269270
#![feature(exact_size_is_empty)]
271+
#![feature(fixed_size_array)]
270272
#![feature(float_from_str_radix)]
271273
#![feature(fn_traits)]
272274
#![feature(fnbox)]

0 commit comments

Comments
 (0)