Repository: bluss/arrayvec (rust)

Issue:
Give ArrayVec a const-fn constructor
I'm not sure if this is even possible but it would be great if `ArrayVec::new()` would be a `const fn` and hence could be called in places where only constant expressions are allowed (of course behind some feature-flag since const-fn is still unstable).

The reason I'd like this feature is that I work on embedded systems where it's typical to have all memory allocated statically, i.e. for a large buffer one would have something like
```rust
static mut BUFFER: [u8; 4096] = [0; 4096];
```
This works fine for arrays (and Copy types) but it would be great if I could also use an `ArrayVec` there. Again, not sure if it's even possible since `mem::uninitialized()` seems to not be a const-fn (although it should, I think) but maybe/hopefully I'm wrong. :)

`lazy_static!` will not work AFAIK because on first invocation of the initialization code the value gets constructed on the stack which typically will not be large enough to hold that value, even temporarily.

Thanks for considering this! :)

Pull request description:
Made ArrayVec::new and ArrayString::new const fns
Followup to this comment: https://github.com/bluss/arrayvec/issues/93#issuecomment-808920790

Fixes #93 

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d73c4eb..65b6c53 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,9 +29,6 @@ jobs:
           - rust: nightly
             features: serde
             experimental: false
-          - rust: nightly
-            features: serde unstable-const-fn
-            experimental: true
 
     steps:
       - uses: actions/checkout@v2
diff --git a/src/array_string.rs b/src/array_string.rs
index 076544f..392ff4e 100644
--- a/src/array_string.rs
+++ b/src/array_string.rs
@@ -14,6 +14,7 @@ use std::str::Utf8Error;
 use crate::CapacityError;
 use crate::LenUint;
 use crate::char::encode_utf8;
+use crate::utils::MakeMaybeUninit;
 
 #[cfg(feature="serde")]
 use serde::{Serialize, Deserialize, Serializer, Deserializer};
@@ -58,20 +59,9 @@ impl<const CAP: usize> ArrayString<CAP>
     /// assert_eq!(&string[..], "foo");
     /// assert_eq!(string.capacity(), 16);
     /// ```
-    #[cfg(not(feature="unstable-const-fn"))]
-    pub fn new() -> ArrayString<CAP> {
-        assert_capacity_limit!(CAP);
-        unsafe {
-            ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
-        }
-    }
-
-    #[cfg(feature="unstable-const-fn")]
     pub const fn new() -> ArrayString<CAP> {
         assert_capacity_limit!(CAP);
-        unsafe {
-            ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
-        }
+        ArrayString { xs: MakeMaybeUninit::ARRAY, len: 0 }
     }
 
     /// Return the length of the string.
diff --git a/src/arrayvec.rs b/src/arrayvec.rs
index d46eddf..f00efeb 100644
--- a/src/arrayvec.rs
+++ b/src/arrayvec.rs
@@ -23,6 +23,7 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
 use crate::LenUint;
 use crate::errors::CapacityError;
 use crate::arrayvec_impl::ArrayVecImpl;
+use crate::utils::MakeMaybeUninit;
 
 /// A vector with a fixed capacity.
 ///
@@ -76,20 +77,9 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
     /// assert_eq!(&array[..], &[1, 2]);
     /// assert_eq!(array.capacity(), 16);
     /// ```
-    #[cfg(not(feature="unstable-const-fn"))]
-    pub fn new() -> ArrayVec<T, CAP> {
-        assert_capacity_limit!(CAP);
-        unsafe {
-            ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
-        }
-    }
-
-    #[cfg(feature="unstable-const-fn")]
     pub const fn new() -> ArrayVec<T, CAP> {
         assert_capacity_limit!(CAP);
-        unsafe {
-            ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
-        }
+        ArrayVec { xs: MakeMaybeUninit::ARRAY, len: 0 }
     }
 
     /// Return the number of elements in the `ArrayVec`.
diff --git a/src/lib.rs b/src/lib.rs
index e6d2ea3..af11a95 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,10 +12,8 @@
 //!   - Enable serialization for ArrayVec and ArrayString using serde 1.x
 //!
 //! - `unstable-const-fn`
-//!   - Optional
-//!   - Makes [`ArrayVec::new`] and [`ArrayString::new`] `const fn`s,
-//!     using the nightly `const_fn` feature.
-//!   - Unstable and requires nightly.
+//!   - **deprecated** (has no effect)
+//!   - Not needed, [`ArrayVec::new`] and [`ArrayString::new`] are always `const fn` now
 //!
 //! ## Rust Version
 //!
@@ -23,7 +21,6 @@
 //!
 #![doc(html_root_url="https://docs.rs/arrayvec/0.6/")]
 #![cfg_attr(not(feature="std"), no_std)]
-#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init, const_panic))]
 
 #[cfg(feature="serde")]
 extern crate serde;
@@ -37,7 +34,7 @@ macro_rules! assert_capacity_limit {
     ($cap:expr) => {
         if std::mem::size_of::<usize>() > std::mem::size_of::<LenUint>() {
             if $cap > LenUint::MAX as usize {
-                panic!("ArrayVec: largest supported capacity is u32::MAX")
+                [/*ArrayVec: largest supported capacity is u32::MAX*/][$cap]
             }
         }
     }
@@ -48,6 +45,7 @@ mod arrayvec;
 mod array_string;
 mod char;
 mod errors;
+mod utils;
 
 pub use crate::array_string::ArrayString;
 pub use crate::errors::CapacityError;
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..b8e5ddb
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,11 @@
+use std::marker::PhantomData;
+use std::mem::MaybeUninit;
+
+pub(crate) struct MakeMaybeUninit<T, const N: usize>(PhantomData<fn() -> T>);
+
+impl<T, const N: usize> MakeMaybeUninit<T, N> {
+    pub(crate) const VALUE: MaybeUninit<T> = MaybeUninit::uninit();
+
+    pub(crate) const ARRAY: [MaybeUninit<T>; N] = [Self::VALUE; N];
+}
+


Test patch:
diff --git a/tests/tests.rs b/tests/tests.rs
index f4698e0..662f5e4 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -718,12 +718,37 @@ fn allow_max_capacity_arrayvec_type() {
     let _v: ArrayVec<(), {usize::MAX}>;
 }
 
-#[should_panic(expected="ArrayVec: largest supported")]
+#[should_panic(expected="index out of bounds")]
 #[test]
 fn deny_max_capacity_arrayvec_value() {
     if mem::size_of::<usize>() <= mem::size_of::<u32>() {
-        panic!("This test does not work on this platform. 'ArrayVec: largest supported'");
+        panic!("This test does not work on this platform. 'index out of bounds'");
     }
     // this type is allowed to be used (but can't be constructed)
     let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new();
 }
+
+#[test]
+fn test_arrayvec_const_constructible() {
+    const OF_U8: ArrayVec<Vec<u8>, 10> = ArrayVec::new();
+
+    let mut var = OF_U8;
+    assert!(var.is_empty());
+    assert_eq!(var, ArrayVec::new());
+    var.push(vec![3, 5, 8]);
+    assert_eq!(var[..], [vec![3, 5, 8]]);
+}
+
+
+#[test]
+fn test_arraystring_const_constructible() {
+    const AS: ArrayString<10> = ArrayString::new();
+
+    let mut var = AS;
+    assert!(var.is_empty());
+    assert_eq!(var, ArrayString::new());
+    var.push_str("hello");
+    assert_eq!(var, *"hello");
+}
+
+