MaybeUninit is also where I ended up writing this by hand. In fact, I came up with something almost identical to ArrayVec (which you should use instead):
#![feature(maybe_uninit_uninit_array)]
use std::mem::MaybeUninit;
/// Safety invariant:
/// self.data[i] is always initialized for all i < self.len
pub struct FooVector<T, const CAP:usize> {
data: [MaybeUninit<T>;CAP],
len: u8
}
impl<T, const CAP:usize> FooVector<T, CAP> {
pub fn new() -> Self {
FooVector {
data: MaybeUninit::uninit_array(),
len: 0
}
}
pub fn add(&mut self, e: T) {
assert!((self.len as usize) < self.data.len());
let slot = self.data[self.len as usize].as_mut_ptr();
unsafe { std::ptr::write(slot, e); }
self.len += 1
}
pub fn take(&mut self) -> Option<T> {
if self.len == 0 { None }
else {
self.len -= 1;
let slot = self.data[self.len as usize].as_ptr();
Some(unsafe{std::ptr::read(slot)})
}
}
}
impl<T, const CAP:usize> Drop for FooVector<T, CAP> {
fn drop(&mut self) {
// Drop all items in take() order
while let Some(_) = self.take() {}
}
}
Sure, but not everyone reading will have the same requirements. Best to mention subtle pitfalls when they crop up, for future readers. This case is also easy enough to prevent. Just check if length is u8::MAX and panic if it is.