use crate::{Prefix, XorName};
use serde::{Deserialize, Serialize};
use std::collections::{btree_map, BTreeMap};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct PrefixMap<T>(BTreeMap<Prefix, T>);
impl<T> PrefixMap<T> {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, prefix: Prefix, entry: T) -> bool {
if self.descendants(&prefix).next().is_some() {
return false;
}
let _ = self.0.insert(prefix, entry);
let parent_prefix = prefix.popped();
self.prune(parent_prefix);
true
}
pub fn get(&self, prefix: &Prefix) -> Option<(&Prefix, &T)> {
self.0.get_key_value(prefix)
}
pub fn get_matching(&self, name: &XorName) -> Option<(&Prefix, &T)> {
self.0
.iter()
.filter(|(prefix, _)| prefix.matches(name))
.max_by_key(|(prefix, _)| prefix.bit_count())
}
pub fn get_matching_prefix(&self, prefix: &Prefix) -> Option<(&Prefix, &T)> {
self.get_matching(&prefix.name())
}
pub fn iter(&self) -> impl Iterator<Item = (&Prefix, &T)> + Clone {
self.0.iter()
}
pub fn descendants<'a>(
&'a self,
prefix: &'a Prefix,
) -> impl Iterator<Item = (&'a Prefix, &'a T)> + Clone + 'a {
self.0
.iter()
.filter(move |(p, _)| p.is_extension_of(prefix))
}
pub fn prune(&mut self, mut prefix: Prefix) {
loop {
if prefix.is_covered_by(self.descendants(&prefix).map(|(prefix, _)| prefix)) {
let _ = self.0.remove(&prefix);
}
if prefix.is_empty() {
break;
} else {
prefix = prefix.popped();
}
}
}
}
impl<T> Default for PrefixMap<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T> PartialEq for PrefixMap<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.0.len() == other.0.len()
&& self
.0
.iter()
.zip(other.0.iter())
.all(|(lhs, rhs)| lhs.0 == rhs.0)
}
}
impl<T> Eq for PrefixMap<T> where T: Eq {}
impl<T> From<PrefixMap<T>> for BTreeMap<Prefix, T> {
fn from(map: PrefixMap<T>) -> Self {
map.0
}
}
impl<T> IntoIterator for PrefixMap<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter())
}
}
#[derive(Debug)]
pub struct IntoIter<T>(btree_map::IntoIter<Prefix, T>);
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(_, entry)| entry)
}
}
#[cfg(test)]
mod tests {
use super::*;
use eyre::Result;
use rand::Rng;
#[test]
fn insert_existing_prefix() {
let mut map = PrefixMap::new();
assert!(map.insert(prefix("0"), 1));
assert!(map.insert(prefix("0"), 2));
assert_eq!(map.get(&prefix("0")), Some((&prefix("0"), &2)));
}
#[test]
fn insert_direct_descendants_of_existing_prefix() {
let mut map = PrefixMap::new();
assert!(map.insert(prefix("0"), 0));
assert!(map.insert(prefix("00"), 1));
assert_eq!(map.get(&prefix("00")), Some((&prefix("00"), &1)));
assert_eq!(map.get(&prefix("01")), None);
assert_eq!(map.get(&prefix("0")), Some((&prefix("0"), &0)));
assert!(map.insert(prefix("01"), 2));
assert_eq!(map.get(&prefix("00")), Some((&prefix("00"), &1)));
assert_eq!(map.get(&prefix("01")), Some((&prefix("01"), &2)));
assert_eq!(map.get(&prefix("0")), None);
}
#[test]
fn insert_indirect_descendants_of_existing_prefix() {
let mut map = PrefixMap::new();
assert!(map.insert(prefix("0"), 0));
assert!(map.insert(prefix("000"), 1));
assert_eq!(map.get(&prefix("000")), Some((&prefix("000"), &1)));
assert_eq!(map.get(&prefix("001")), None);
assert_eq!(map.get(&prefix("00")), None);
assert_eq!(map.get(&prefix("01")), None);
assert_eq!(map.get(&prefix("0")), Some((&prefix("0"), &0)));
assert!(map.insert(prefix("001"), 2));
assert_eq!(map.get(&prefix("000")), Some((&prefix("000"), &1)));
assert_eq!(map.get(&prefix("001")), Some((&prefix("001"), &2)));
assert_eq!(map.get(&prefix("00")), None);
assert_eq!(map.get(&prefix("01")), None);
assert_eq!(map.get(&prefix("0")), Some((&prefix("0"), &0)));
assert!(map.insert(prefix("01"), 3));
assert_eq!(map.get(&prefix("000")), Some((&prefix("000"), &1)));
assert_eq!(map.get(&prefix("001")), Some((&prefix("001"), &2)));
assert_eq!(map.get(&prefix("00")), None);
assert_eq!(map.get(&prefix("01")), Some((&prefix("01"), &3)));
assert_eq!(map.get(&prefix("0")), None);
}
#[test]
fn insert_ancestor_of_existing_prefix() {
let mut map = PrefixMap::new();
let _ = map.insert(prefix("00"), 1);
assert!(!map.insert(prefix("0"), 2));
assert_eq!(map.get(&prefix("0")), None);
assert_eq!(map.get(&prefix("00")), Some((&prefix("00"), &1)));
}
#[test]
fn get_matching() {
let mut rng = rand::thread_rng();
let mut map = PrefixMap::new();
let _ = map.insert(prefix("0"), 0);
let _ = map.insert(prefix("1"), 1);
let _ = map.insert(prefix("10"), 10);
assert_eq!(
map.get_matching(&prefix("0").substituted_in(rng.gen())),
Some((&prefix("0"), &0))
);
assert_eq!(
map.get_matching(&prefix("11").substituted_in(rng.gen())),
Some((&prefix("1"), &1))
);
assert_eq!(
map.get_matching(&prefix("10").substituted_in(rng.gen())),
Some((&prefix("10"), &10))
);
}
#[test]
fn get_matching_prefix() {
let mut map = PrefixMap::new();
let _ = map.insert(prefix("0"), 0);
let _ = map.insert(prefix("1"), 1);
let _ = map.insert(prefix("10"), 10);
assert_eq!(
map.get_matching_prefix(&prefix("0")),
Some((&prefix("0"), &0))
);
assert_eq!(
map.get_matching_prefix(&prefix("11")),
Some((&prefix("1"), &1))
);
assert_eq!(
map.get_matching_prefix(&prefix("10")),
Some((&prefix("10"), &10))
);
assert_eq!(
map.get_matching_prefix(&prefix("101")),
Some((&prefix("10"), &10))
);
}
#[test]
fn test_iter() {
let mut map = PrefixMap::new();
let _ = map.insert(prefix("10"), 10);
let _ = map.insert(prefix("11"), 11);
let _ = map.insert(prefix("0"), 0);
let mut it = map.iter();
assert_eq!(it.next(), Some((&prefix("0"), &0)));
assert_eq!(it.next(), Some((&prefix("10"), &10)));
assert_eq!(it.next(), Some((&prefix("11"), &11)));
assert_eq!(it.next(), None);
}
#[test]
fn serialize_transparent() -> Result<()> {
let mut map = PrefixMap::new();
let _ = map.insert(prefix("0"), 0);
let _ = map.insert(prefix("1"), 1);
let _ = map.insert(prefix("10"), 10);
let copy_map: BTreeMap<_, _> = map.clone().into();
let serialized_copy_map = rmp_serde::to_vec(©_map)?;
assert_eq!(rmp_serde::to_vec(&map)?, serialized_copy_map);
let _ = rmp_serde::from_read::<_, PrefixMap<i32>>(&*serialized_copy_map)?;
Ok(())
}
fn prefix(s: &str) -> Prefix {
s.parse().expect("")
}
}