diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a390ff55..c38bbcb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,13 @@ jobs: features: serde experimental: false # doctest of `ArrayVec::spare_capacity_mut` has MSRV 1.55 - test-args: --skip spare_capacity_mut + # doctest of `ArrayVec::new_in_place` has MSRV 1.82 + test-args: --skip spare_capacity_mut --skip new_in_place - rust: 1.70.0 features: serde experimental: false + # doctest of `ArrayVec::new_in_place` has MSRV 1.82 + test-args: --skip new_in_place - rust: stable features: bench: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 056e6c0f..f74f6e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ Recent Changes (arrayvec) ========================= +- Enable in-place initialization [#304](https://github.com/bluss/arrayvec/pull/304) + ## 0.7.6 - Fix no-std build [#274](https://github.com/bluss/arrayvec/pull/274) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index e5ea52dc..52c9b04c 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -87,6 +87,47 @@ impl ArrayVec { } } + /// Initialize an empty `ArrayVec` in-place. + /// + /// Useful when you want to store a huge `ArrayVec` in some pre-initialized memory and + /// don't want to create and move it from the stack. + /// This is very cheap as all elements are uninitialized when the vec is empty. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// use std::mem::MaybeUninit; + /// + /// let mut place = MaybeUninit::>::uninit(); + /// let vec = ArrayVec::new_in_place(&mut place); + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// vec.push(42); + /// assert_eq!(vec, [42].as_slice()); + /// ``` + /// + /// ### Creating an `ArrayVec` on the Heap + /// + /// The return value is the same reference as passed to the function. Thus you can just + /// ignore that and assume that your [`MaybeUninit`] is initialized. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// use std::mem::MaybeUninit; + /// + /// let mut place = Box::new_uninit(); + /// ArrayVec::new_in_place(&mut place); + /// let vec: Box> = unsafe { place.assume_init() }; + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// ``` + #[inline] + pub fn new_in_place(uninit: &mut MaybeUninit) -> &mut Self { + let ptr = uninit.as_mut_ptr(); + unsafe { ptr::addr_of_mut!((*ptr).len).write(0); } + // XXX: Once MSRV >= 1.55 we can use: unsafe { uninit.assume_init_mut() } + unsafe { &mut *ptr } + } + /// Create a new empty `ArrayVec` (const fn). /// /// The maximum capacity is given by the generic parameter `CAP`.