Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created October 17, 2025 21:42
Show Gist options
  • Select an option

  • Save rust-play/862fe7541fb5d626aa4463da0edc68cb to your computer and use it in GitHub Desktop.

Select an option

Save rust-play/862fe7541fb5d626aa4463da0edc68cb to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
// Creating a heapless vector type using MaybeUninit<T> safely for
// unintialized memory (useful in embedded systems where there's limited
// memory space for heap allocations).
#![no_std]
extern crate std;
use arrayvec::ArrayVec;
mod arrayvec {
use core::mem::MaybeUninit;
#[derive(Debug)]
pub struct ArrayVec<T, const N: usize> {
values: [MaybeUninit<T>; N],
len: usize,
}
impl<T, const N: usize> ArrayVec<T, N> {
/// Creates a new empty ArrayVec
pub fn new() -> Self {
// [MaybeUninit<T>; N] is zero-initialized to uninit by default.
// Meaning the array starts from a blank slate waiting to be
// initialized by `write()`; filling uninit elements with
// "garbage" bytes.
ArrayVec {
// values: unsafe { MaybeUninit::uninit().assume_init() },
// Same as the commented code above but safer.
values: [const { MaybeUninit::uninit() }; N],
len: 0,
}
}
/// Pushes a value if there's space, returning `Err(value)` if full.
/// Safe: `.write()` takes ownership and marks the slot as
/// initialized.
pub fn try_push(&mut self, value: T) -> Result<(), T> {
if self.len == N {
return Err(value);
}
self.values[self.len].write(value);
self.len += 1;
Ok(())
}
/// Returns a reference to the element at `index` if within bounds
/// and initialized.
/// SAFETY: Unsafe internally: Assumes first `len` slots are init.
pub fn get(&self, index: usize) -> Option<&T> {
if index >= self.len {
return None;
}
// Same as the commented code below
unsafe { Some(&*self.values[index].as_ptr()) }
// unsafe { Some(self.values[index].assume_init_ref()) }
}
/// Pops the last value if any, returning it (or `None` if empty).
/// SAFETY: Safe: Uses `.assume_init_read()` to extract and mark
/// as uninit.
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
Some(unsafe { self.values[self.len].assume_init_read() })
}
/// Return array of init and uninit elements in ArrayVec.
///
/// ASIDE: I don't actually need to add `'a` due to Lifetime Ellision
/// rules. I left it just to remind myself how far I've come to
/// perfectly understand lifetimes now.
///
/// Use `into_arr` as an associated function.
pub fn into_arr<'a>(arr_vec: &'a ArrayVec<T, N>)
-> [Option<&'a T>; N]
{
let mut arr: [Option<&T>; N] = [const { None }; N];
for i in 0..N {
let el = arr_vec.get(i);
arr[i] = el;
}
arr
}
/// Returns the current length.
pub fn len(&self) -> usize {
self.len
}
}
// Implement Drop trait to safely deallocate initialized elements.
impl<T, const N: usize> Drop for ArrayVec<T, N> {
fn drop(&mut self) {
// Explicity drop the first `len` initialized elements.
for i in 0..self.len {
unsafe {
self.values[i].assume_init_drop();
}
}
}
}
}
const CAP: usize = 5;
fn main() {
let mut arr_vec1 = ArrayVec::<i32, CAP>::new();
std::println!("{:?}", arr_vec1); // View init ArrayVec
let mut count;
// Push a few elements
for i in 0..(CAP - 2) {
count = 1 + i as i32;
arr_vec1.try_push(count).unwrap()
}
std::println!("{:?}", arr_vec1); // View pushed elements
// Return element in initialized index;
// if index is not initialized, return None.
let arr_els1 = ArrayVec::into_arr(&arr_vec1);
std::println!("---\nInit values: {:?}", arr_els1);
// Pop from MaybeUninit ArrayVec; if uninit, return None.
std::println!("---\nArrayVec `len` before pop: {}", arr_vec1.len());
std::println!("Popped value: {:?}", arr_vec1.pop());
std::println!("ArrayVec `len` after pop: {}", arr_vec1.len());
// TEST: Add more elements beyond `CAP` size for ArrayVec;
// `try_push` should escape and return with Err.
let arr_len = arr_vec1.len();
count = *arr_vec1.get(arr_len - 1).unwrap();
let mut arr_err_els: ArrayVec<Result<(), i32>, CAP> = ArrayVec::new();
for _ in arr_len..(CAP * 2) {
count += 1;
if let Err(value) = arr_vec1.try_push(count) {
arr_err_els.try_push(Err(value)).unwrap();
}
}
std::println!(
"---\nFilled ArrayVec: {:?}", ArrayVec::into_arr(&arr_vec1)
);
std::println!(
"Err beyond ArrayVec: {:?}", ArrayVec::into_arr(&arr_err_els)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment