use core::mem::MaybeUninit;
pub(crate) struct ArrayMap<K, V, const N: usize> {
entries: [MaybeUninit<(K, V)>; N],
len: usize,
}
impl<K: Copy + Eq, V, const N: usize> ArrayMap<K, V, N> {
pub(crate) const fn new() -> Self {
Self {
entries: unsafe { MaybeUninit::uninit().assume_init() },
len: 0,
}
}
pub(crate) unsafe fn init_empty(dst: *mut Self) {
unsafe {
core::ptr::addr_of_mut!((*dst).len).write(0);
}
}
#[cfg(test)]
pub(crate) const fn len(&self) -> usize {
self.len
}
#[cfg(test)]
pub(crate) const fn is_empty(&self) -> bool {
self.len == 0
}
pub(crate) const fn is_full(&self) -> bool {
self.len >= N
}
pub(crate) fn insert(&mut self, key: K, value: V) -> Result<(), V> {
for i in 0..self.len {
let (k, _) = unsafe { self.entries[i].assume_init_ref() };
if *k == key {
unsafe {
self.entries[i].assume_init_drop();
self.entries[i].write((key, value));
}
return Ok(());
}
}
if self.is_full() {
return Err(value);
}
self.entries[self.len].write((key, value));
self.len += 1;
Ok(())
}
pub(crate) fn try_push_with<E>(
&mut self,
full_error: E,
init: impl FnOnce(&mut MaybeUninit<(K, V)>) -> Result<(), E>,
) -> Result<(), E> {
if self.is_full() {
return Err(full_error);
}
init(&mut self.entries[self.len])?;
self.len += 1;
Ok(())
}
pub(crate) fn get(&self, key: &K) -> Option<&V> {
for i in 0..self.len {
let (k, v) = unsafe { self.entries[i].assume_init_ref() };
if k == key {
return Some(v);
}
}
None
}
pub(crate) fn get_mut(&mut self, key: &K) -> Option<&mut V> {
let mut found_idx = None;
for i in 0..self.len {
let (k, _) = unsafe { self.entries[i].assume_init_ref() };
if k == key {
found_idx = Some(i);
break;
}
}
if let Some(idx) = found_idx {
let (_k, v) = unsafe { self.entries[idx].assume_init_mut() };
Some(v)
} else {
None
}
}
#[cfg(test)]
pub(crate) fn remove(&mut self, key: &K) -> Option<V> {
for i in 0..self.len {
let (k, _) = unsafe { self.entries[i].assume_init_ref() };
if k == key {
let (_k, v) = unsafe { self.entries[i].assume_init_read() };
for j in i..self.len - 1 {
unsafe {
let entry = self.entries[j + 1].assume_init_read();
self.entries[j].write(entry);
}
}
self.len -= 1;
return Some(v);
}
}
None
}
pub(crate) fn clear(&mut self) {
for i in 0..self.len {
unsafe {
self.entries[i].assume_init_drop();
}
}
self.len = 0;
}
pub(crate) fn contains_key(&self, key: &K) -> bool {
self.get(key).is_some()
}
}
impl<K, V, const N: usize> Drop for ArrayMap<K, V, N> {
fn drop(&mut self) {
for i in 0..self.len {
unsafe {
self.entries[i].assume_init_drop();
}
}
}
}
impl<K: Copy + Eq, V, const N: usize> Default for ArrayMap<K, V, N> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert_and_get() {
let mut map: ArrayMap<u8, u32, 4> = ArrayMap::new();
assert!(map.insert(1, 100).is_ok());
assert!(map.insert(2, 200).is_ok());
assert_eq!(map.get(&1), Some(&100));
assert_eq!(map.get(&2), Some(&200));
assert_eq!(map.get(&3), None);
assert_eq!(map.len(), 2);
}
#[test]
fn test_insert_full() {
let mut map: ArrayMap<u8, u32, 2> = ArrayMap::new();
assert!(map.insert(1, 100).is_ok());
assert!(map.insert(2, 200).is_ok());
assert_eq!(map.insert(3, 300), Err(300));
assert_eq!(map.len(), 2);
}
#[test]
fn test_replace_existing() {
let mut map: ArrayMap<u8, u32, 4> = ArrayMap::new();
assert!(map.insert(1, 100).is_ok());
assert!(map.insert(1, 999).is_ok());
assert_eq!(map.get(&1), Some(&999));
assert_eq!(map.len(), 1); }
#[test]
fn test_remove() {
let mut map: ArrayMap<u8, u32, 4> = ArrayMap::new();
map.insert(1, 100).unwrap();
map.insert(2, 200).unwrap();
map.insert(3, 300).unwrap();
assert_eq!(map.remove(&2), Some(200));
assert_eq!(map.len(), 2);
assert_eq!(map.get(&2), None);
assert_eq!(map.get(&1), Some(&100));
assert_eq!(map.get(&3), Some(&300));
}
#[test]
fn test_clear() {
let mut map: ArrayMap<u8, u32, 4> = ArrayMap::new();
map.insert(1, 100).unwrap();
map.insert(2, 200).unwrap();
assert_eq!(map.len(), 2);
map.clear();
assert_eq!(map.len(), 0);
assert!(map.is_empty());
}
#[test]
fn test_get_mut() {
let mut map: ArrayMap<u8, u32, 4> = ArrayMap::new();
map.insert(1, 100).unwrap();
if let Some(v) = map.get_mut(&1) {
*v = 999;
}
assert_eq!(map.get(&1), Some(&999));
}
}