Skip to content

Commit

Permalink
Add from_slice_const constructor for ArrayVec
Browse files Browse the repository at this point in the history
We can't make these generic, not even where T: Copy, so they are just
templated out with macros for the integer types, quite limited.
  • Loading branch information
bluss committed Nov 7, 2021
1 parent 1d1adae commit d2ab6da
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Expand Up @@ -35,9 +35,15 @@ name = "arraystring"
harness = false

[features]
default = ["std"]
default = ["std", "u128", "floats"]
# enable stdlib
std = []

# enable i128, u128 specific impls
u128 = []
# enable f32, f64 specific impls
floats = []

[profile.bench]
debug = true
[profile.release]
Expand Down
45 changes: 45 additions & 0 deletions src/arrayvec.rs
Expand Up @@ -760,6 +760,51 @@ impl<T, const CAP: usize> From<[T; CAP]> for ArrayVec<T, CAP> {
}
}

// Generic version of from_slice_const not possible at this time
macro_rules! impl_from_const {
($($t:ty)+) => {
$(
impl<const CAP: usize> ArrayVec<$t, CAP> {
/// Create a new `ArrayVec` from a slice, suitable for const context
///
/// Capacity is inferred from the type parameter.
///
/// **Panics** if the backing array is not large enough to fit the slice.
///
/// ```
/// use arrayvec::ArrayVec;
///
/// const V: ArrayVec<u8, 3> = ArrayVec::<u8, 3>::from_slice_const(&[1, 2, 3]);
/// ```
pub const fn from_slice_const(values: &[$t]) -> Self {
let len = values.len();
if len > CAP {
panic!("ArrayVec::from_slice_const: insufficient capacity");
}

let mut vec = Self::new_const();
let mut i = 0;
while i < len {
vec.xs[i] = MaybeUninit::new(values[i]);
i += 1;
}

// Safety: we know len <= CAP and elements < len are initialized
vec.len = len as u32;
vec
}
}
)+

};
}

impl_from_const!(u8 u16 u32 u64 usize i8 i16 i32 i64 isize char);
#[cfg(feature = "floats")]
impl_from_const!(f32 f64);
#[cfg(feature = "u128")]
impl_from_const!(u128 i128);


/// Try to create an `ArrayVec` from a slice. This will return an error if the slice was too big to
/// fit.
Expand Down
28 changes: 27 additions & 1 deletion tests/tests.rs
Expand Up @@ -773,6 +773,19 @@ fn test_arrayvec_const_constructible() {
assert_eq!(var[..], [vec![3, 5, 8]]);
}

#[test]
fn test_arrayvec_from_slice_const() {
const V: ArrayVec<u8, 10> = ArrayVec::<u8, 10>::from_slice_const(b"0123456789");

let mut var = V;
assert_eq!(&*var, b"0123456789");
assert!(var.try_push(0).is_err());
var.clear();
var.push(1);
var.push(2);
assert_eq!(&*var, &[1, 2]);
}

#[test]
fn test_arraystring_const_constructible() {
const AS: ArrayString<10> = ArrayString::new_const();
Expand All @@ -784,10 +797,23 @@ fn test_arraystring_const_constructible() {
assert_eq!(var, *"hello");
}

#[test]
fn test_arraystring_from_str_const() {
const AS: ArrayString<10> = ArrayString::from_str_const("0123456789");

let mut var = AS;
assert_eq!(&*var, "0123456789");
assert!(var.try_push_str("1").is_err());

var.clear();
var.push_str("9876543210");
assert_eq!(&*var, "9876543210");
}


#[test]
fn test_arraystring_zero_filled_has_some_sanity_checks() {
let string = ArrayString::<4>::zero_filled();
assert_eq!(string.as_str(), "\0\0\0\0");
assert_eq!(string.len(), 4);
}
}

0 comments on commit d2ab6da

Please sign in to comment.