use std::ops::Index;
use microcad_core::hash::HashMap;
pub trait OrdMapValue<K>
where
K: std::cmp::Eq + std::hash::Hash + Clone,
{
fn key(&self) -> Option<K>;
}
#[derive(Clone, PartialEq)]
pub struct OrdMap<K, V>
where
V: OrdMapValue<K>,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
vec: Vec<V>,
map: HashMap<K, usize>,
}
impl<K, V> Default for OrdMap<K, V>
where
V: OrdMapValue<K>,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
fn default() -> Self {
Self {
vec: Default::default(),
map: Default::default(),
}
}
}
impl<K, V> std::fmt::Debug for OrdMap<K, V>
where
V: OrdMapValue<K> + std::fmt::Debug,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OrdMap").field("vec", &self.vec).finish()
}
}
impl<K, V> From<Vec<V>> for OrdMap<K, V>
where
V: OrdMapValue<K>,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
fn from(vec: Vec<V>) -> Self {
Self {
map: vec
.iter()
.enumerate()
.filter_map(|(i, item)| item.key().map(|key| (key, i)))
.collect(),
vec,
}
}
}
impl<K, V> OrdMap<K, V>
where
V: OrdMapValue<K>,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
pub fn iter(&self) -> std::slice::Iter<'_, V> {
self.vec.iter()
}
pub fn len(&self) -> usize {
self.vec.len()
}
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
pub fn try_push(&mut self, item: V) -> Result<(), (K, K)> {
if let Some(key) = item.key() {
match self.map.entry(key) {
std::collections::hash_map::Entry::Vacant(entry) => entry.insert(self.vec.len()),
std::collections::hash_map::Entry::Occupied(entry) => {
return Err((entry.key().clone(), item.key().expect("ord_map error")));
}
};
}
self.vec.push(item);
Ok(())
}
pub fn get(&self, key: &K) -> Option<&V> {
self.map.get(key).map(|index| &self.vec[*index])
}
pub fn keys(&self) -> std::collections::hash_map::Keys<'_, K, usize> {
self.map.keys()
}
pub fn first(&self) -> Option<&V> {
self.vec.first()
}
}
impl<K, V> Index<usize> for OrdMap<K, V>
where
V: OrdMapValue<K>,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
type Output = V;
fn index(&self, index: usize) -> &Self::Output {
&self.vec[index]
}
}
impl<K, V> Index<&K> for OrdMap<K, V>
where
V: OrdMapValue<K>,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
type Output = V;
fn index(&self, key: &K) -> &Self::Output {
&self.vec[*self.map.get(key).expect("key not found")]
}
}