diff --git a/src/array_string.rs b/src/array_string.rs index 227e01d..4a24b2d 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -21,7 +21,6 @@ use crate::utils::MakeMaybeUninit; #[cfg(feature="serde")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; - /// A string with a fixed capacity. /// /// The `ArrayString` is a string backed by a fixed size array. It keeps track @@ -111,6 +110,42 @@ impl ArrayString Ok(arraystr) } + /// Create a new `ArrayString` from a `str`, suitable for const context + /// + /// Capacity is inferred from the type parameter. + /// + /// **Panics** or causes a **const error** if the backing array is not large enough to fit the + /// string. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// const S: ArrayString<3> = ArrayString::from_str_const(""); + /// ``` + /// + /// A compile-time error will occur - in constants - if the input is too long: + /// + /// ```compile_fail + /// # use arrayvec::ArrayString; + /// const S1: ArrayString<3> = ArrayString::from_str_const("too long for the capacity"); + /// ``` + pub const fn from_str_const(s: &str) -> Self { + let bytes = s.as_bytes(); + let len = bytes.len(); + assert_length_lt_capacity_const!(len, CAP); + + let mut vec = Self::new_const(); + let mut i = 0; + while i < len { + vec.xs[i] = MaybeUninit::new(bytes[i]); + i += 1; + } + + // Safety: we know len <= CAP and elements < len are initialized + vec.len = len as LenUint; + vec + } + /// Create a new `ArrayString` from a byte string literal. /// /// **Errors** if the byte string literal is not valid UTF-8. diff --git a/src/lib.rs b/src/lib.rs index 5c4bcee..80d2665 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,14 @@ macro_rules! assert_capacity_limit_const { } } +macro_rules! assert_length_lt_capacity_const { + ($len:expr, $cap:expr) => { + if $len > 0 { + let _len_check = [(); $cap /*ArrayVec/ArrayString: insufficient capacity */][$len - 1]; + } + } +} + mod arrayvec_impl; mod arrayvec; mod array_string; diff --git a/tests/tests.rs b/tests/tests.rs index 309ceb8..4835b5b 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -814,6 +814,19 @@ 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() {