use core::{ops::RangeBounds, option::IntoIter};
use spacetimedb_sats::memory_usage::MemoryUsage;
use std::collections::btree_map::{BTreeMap, Entry, Range};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct UniqueMap<K, V> {
map: BTreeMap<K, V>,
}
impl<K, V> Default for UniqueMap<K, V> {
fn default() -> Self {
Self { map: BTreeMap::new() }
}
}
impl<K: MemoryUsage, V: MemoryUsage> MemoryUsage for UniqueMap<K, V> {
fn heap_usage(&self) -> usize {
let Self { map } = self;
map.heap_usage()
}
}
impl<K: Ord, V: Ord> UniqueMap<K, V> {
pub fn insert(&mut self, key: K, val: V) -> Result<(), &V> {
match self.map.entry(key) {
Entry::Vacant(e) => {
e.insert(val);
Ok(())
}
Entry::Occupied(e) => Err(e.into_mut()),
}
}
pub fn delete(&mut self, key: &K) -> bool {
self.map.remove(key).is_some()
}
pub fn values_in_range(&self, range: &impl RangeBounds<K>) -> UniqueMapRangeIter<'_, K, V> {
UniqueMapRangeIter {
iter: self.map.range((range.start_bound(), range.end_bound())),
}
}
pub fn values_in_point(&self, key: &K) -> UniqueMapPointIter<'_, V> {
let iter = self.map.get(key).into_iter();
UniqueMapPointIter { iter }
}
pub fn num_keys(&self) -> usize {
self.len()
}
pub fn len(&self) -> usize {
self.map.len()
}
#[allow(unused)] pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn clear(&mut self) {
self.map.clear();
}
pub(crate) fn can_merge(&self, other: &Self, ignore: impl Fn(&V) -> bool) -> Result<(), &V> {
let Some(found) = other
.map
.keys()
.find_map(|key| self.map.get(key).filter(|val| !ignore(val)))
else {
return Ok(());
};
Err(found)
}
}
pub struct UniqueMapPointIter<'a, V> {
iter: IntoIter<&'a V>,
}
impl<'a, V> Iterator for UniqueMapPointIter<'a, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
pub struct UniqueMapRangeIter<'a, K, V> {
iter: Range<'a, K, V>,
}
impl<'a, K, V> Iterator for UniqueMapRangeIter<'a, K, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(_, v)| v)
}
}