#![cfg(feature = "ordered")]
use std::borrow::Borrow;
use std::hash::Hash;
use heapless::LinearMap;
#[derive(Debug, Clone)]
pub struct HeaplessOrderedMap<K: Eq + Hash, V, const N: usize> {
map: LinearMap<K, V, N>,
}
impl<K: Eq + Hash, V, const N: usize> HeaplessOrderedMap<K, V, N> {
pub fn new() -> Self {
const {
assert!(
std::mem::size_of::<Self>() <= 16 * 1024,
"HeaplessOrderedMap is too large! The struct size exceeds the 16KB limit. Reduce N."
);
}
Self {
map: LinearMap::new(),
}
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn is_full(&self) -> bool {
self.map.len() == N
}
pub fn clear(&mut self) {
self.map.clear();
}
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, (K, V)> {
if self.map.len() == N && !self.map.contains_key(&key) {
return Err((key, value));
}
Ok(self.map.insert(key, value).ok().flatten())
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.map
.iter()
.find(|&(k, _)| <K as Borrow<Q>>::borrow(k) == key)
.map(|(_, v)| v)
}
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.map
.iter_mut()
.find(|(k, _)| <K as Borrow<Q>>::borrow(k) == key)
.map(|(_, v)| v)
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mut temp: LinearMap<K, V, N> = LinearMap::new();
let mut removed = None;
let old = core::mem::replace(&mut self.map, LinearMap::new());
for (k, v) in old.into_iter() {
if k.borrow() == key && removed.is_none() {
removed = Some(v);
} else {
let _ = temp.insert(k, v);
}
}
self.map = temp;
removed
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.get(key).is_some()
}
pub fn iter(&self) -> heapless::linear_map::Iter<'_, K, V> {
self.map.iter()
}
pub fn into_inner(self) -> LinearMap<K, V, N> {
self.map
}
}
impl<K, V, const N: usize> PartialEq for HeaplessOrderedMap<K, V, N>
where
K: Eq + Hash,
V: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().all(|(k, v)| other.get(k) == Some(v))
}
}
impl<K, V, const N: usize> Eq for HeaplessOrderedMap<K, V, N>
where
K: Eq + Hash,
V: Eq,
{
}
impl<K: Eq + Hash, V, const N: usize> Default for HeaplessOrderedMap<K, V, N> {
fn default() -> Self {
Self::new()
}
}
impl<K: Eq + Hash, V, const N: usize> IntoIterator for HeaplessOrderedMap<K, V, N> {
type Item = (K, V);
type IntoIter = heapless::linear_map::IntoIter<K, V, N>;
fn into_iter(self) -> Self::IntoIter {
self.map.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_heapless_ordered_map_stack_ops_insertion_order() {
let mut map: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
map.insert(3, 30).unwrap();
map.insert(1, 10).unwrap();
map.insert(2, 20).unwrap();
let keys: Vec<_> = map.iter().map(|(k, _)| *k).collect();
assert_eq!(keys, vec![3, 1, 2]);
}
#[test]
fn test_heapless_ordered_map_stack_ops_update() {
let mut map: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
assert_eq!(map.insert(1, 10), Ok(None));
assert_eq!(map.insert(1, 20), Ok(Some(10)));
assert_eq!(map.get(&1), Some(&20));
}
#[test]
fn test_heapless_ordered_map_stack_ops_remove() {
let mut map: HeaplessOrderedMap<String, i32, 4> = HeaplessOrderedMap::new();
map.insert("a".into(), 1).unwrap();
map.insert("b".into(), 2).unwrap();
assert_eq!(map.remove("a"), Some(1));
assert_eq!(map.len(), 1);
assert_eq!(map.get("b"), Some(&2));
}
#[test]
fn test_heapless_ordered_map_stack_ops_full_returns_err() {
let mut map: HeaplessOrderedMap<i32, i32, 2> = HeaplessOrderedMap::new();
map.insert(1, 10).unwrap();
map.insert(2, 20).unwrap();
assert!(map.is_full());
assert_eq!(map.insert(3, 30), Err((3, 30)));
}
#[test]
fn test_heapless_ordered_map_stack_ops_get_mut() {
let mut map: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
map.insert(1, 10).unwrap();
if let Some(v) = map.get_mut(&1) {
*v = 42;
}
assert_eq!(map.get(&1), Some(&42));
}
#[test]
fn test_heapless_ordered_map_stack_ops_contains_key() {
let mut map: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
map.insert(1, 10).unwrap();
assert!(map.contains_key(&1));
assert!(!map.contains_key(&2));
}
#[test]
fn test_heapless_ordered_map_traits_clone_default() {
let map1: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::default();
let mut map2 = map1.clone();
map2.insert(7, 70).unwrap();
assert_eq!(map1.len(), 0);
assert_eq!(map2.len(), 1);
}
#[test]
fn test_heapless_ordered_map_stack_ops_borrow_lookup() {
let mut map: HeaplessOrderedMap<String, i32, 4> = HeaplessOrderedMap::new();
map.insert("Apple".to_string(), 100).unwrap();
assert_eq!(map.get("Apple"), Some(&100));
assert_eq!(map.get_mut("Apple"), Some(&mut 100));
}
}
#[cfg(test)]
mod heapless_ordered_map_coverage_tests {
use super::*;
#[test]
fn test_is_empty_false() {
let mut map: HeaplessOrderedMap<i32, i32, 2> = HeaplessOrderedMap::new();
map.insert(1, 10).unwrap();
assert!(!map.is_empty());
}
#[test]
fn test_get_get_mut_missing() {
let mut map: HeaplessOrderedMap<i32, i32, 2> = HeaplessOrderedMap::new();
map.insert(1, 10).unwrap();
assert_eq!(map.get(&2), None);
assert_eq!(map.get_mut(&2), None);
}
#[test]
fn test_into_inner() {
let mut map: HeaplessOrderedMap<i32, i32, 2> = HeaplessOrderedMap::new();
map.insert(1, 10).unwrap();
let inner = map.into_inner();
assert_eq!(inner.len(), 1);
assert_eq!(inner.get(&1), Some(&10));
}
#[test]
fn test_partial_eq_variants() {
let mut m1: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
m1.insert(1, 10).unwrap();
let mut m2: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
m2.insert(1, 10).unwrap();
let mut m3: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
m3.insert(1, 10).unwrap();
m3.insert(2, 20).unwrap();
let mut m4: HeaplessOrderedMap<i32, i32, 4> = HeaplessOrderedMap::new();
m4.insert(1, 99).unwrap();
assert_eq!(m1, m2);
assert_ne!(m1, m3); assert_ne!(m1, m4); }
}