Add TryFrom<&'_ [A::Item]> for ArrayVec<A> (#134)

This commit is contained in:
Michael Morgan
2021-03-01 22:02:24 -05:00
committed by GitHub
parent 643a1707f5
commit 8d8ae29ba5
3 changed files with 56 additions and 14 deletions
+34 -1
View File
@@ -1,5 +1,5 @@
use super::*;
use core::convert::TryInto;
use core::convert::{TryInto, TryFrom};
#[cfg(feature = "serde")]
use core::marker::PhantomData;
@@ -1190,6 +1190,39 @@ impl<A: Array> From<A> for ArrayVec<A> {
}
}
/// The error type returned when a conversion from a slice to an [`ArrayVec`] fails.
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());
impl<T, A> TryFrom<&'_ [T]> for ArrayVec<A>
where
T: Clone + Default,
A: Array<Item = T>,
{
type Error = TryFromSliceError;
#[inline]
#[must_use]
/// The output has a length equal to that of the slice, with the same capacity as `A`.
fn try_from(slice: &[T]) -> Result<Self, Self::Error> {
if slice.len() > A::CAPACITY {
Err(TryFromSliceError(()))
} else {
let mut arr = ArrayVec::new();
// We do not use ArrayVec::extend_from_slice, because it looks like LLVM
// fails to deduplicate all the length-checking logic between the
// above if and the contents of that method, thus producing much
// slower code. Unlike many of the other optimizations in this
// crate, this one is worth keeping an eye on. I see no reason, for
// any element type, that these should produce different code. But
// they do. (rustc 1.51.0)
arr.set_len(slice.len());
arr.as_mut_slice().clone_from_slice(slice);
Ok(arr)
}
}
}
impl<A: Array> FromIterator<A::Item> for ArrayVec<A> {
#[inline]
#[must_use]
+4 -13
View File
@@ -3,6 +3,7 @@
use super::*;
use alloc::vec::{self, Vec};
use core::convert::TryFrom;
use tinyvec_macros::impl_mirrored;
#[cfg(feature = "serde")]
@@ -1114,20 +1115,10 @@ where
#[inline]
#[must_use]
fn from(slice: &[T]) -> Self {
if slice.len() > A::CAPACITY {
TinyVec::Heap(slice.into())
} else {
let mut arr = ArrayVec::new();
// We do not use ArrayVec::extend_from_slice, because it looks like LLVM
// fails to deduplicate all the length-checking logic between the
// above if and the contents of that method, thus producing much
// slower code. Unlike many of the other optimizations in this
// crate, this one is worth keeping an eye on. I see no reason, for
// any element type, that these should produce different code. But
// they do. (rustc 1.51.0)
arr.set_len(slice.len());
arr.as_mut_slice().clone_from_slice(slice);
if let Ok(arr) = ArrayVec::try_from(slice) {
TinyVec::Inline(arr)
} else {
TinyVec::Heap(slice.into())
}
}
}
+18
View File
@@ -445,3 +445,21 @@ fn ArrayVec_ser_de() {
],
);
}
#[test]
fn ArrayVec_try_from_slice() {
use std::convert::TryFrom;
let nums = [1, 2, 3, 4];
let empty: Result<ArrayVec<[i32; 2]>, _> = ArrayVec::try_from(&nums[..0]);
assert!(empty.is_ok());
assert_eq!(empty.unwrap().as_slice(), &[]);
let fits: Result<ArrayVec<[i32; 2]>, _> = ArrayVec::try_from(&nums[..2]);
assert!(fits.is_ok());
assert_eq!(fits.unwrap().as_slice(), &[1, 2]);
let doesnt_fit: Result<ArrayVec<[i32; 2]>, _> = ArrayVec::try_from(&nums[..4]);
assert!(doesnt_fit.is_err());
}