90 lines
2.2 KiB
Rust
90 lines
2.2 KiB
Rust
use std::{collections::HashMap, borrow::Borrow, hash::Hash, marker::PhantomData};
|
|
|
|
use serde::{de::Visitor, Deserialize, Deserializer};
|
|
|
|
use crate::supervisor::Link;
|
|
|
|
|
|
#[derive(Debug)]
|
|
pub struct Linkmap<T: Hash + Eq> {
|
|
to: HashMap<T, Link>,
|
|
from: HashMap<Link, Vec<T>>,
|
|
}
|
|
|
|
impl <T: Hash + Eq + Clone> Linkmap<T> {
|
|
pub fn with_capacity(capacity: usize) -> Self {
|
|
Self {
|
|
to: HashMap::with_capacity(capacity),
|
|
from: HashMap::with_capacity(capacity),
|
|
}
|
|
}
|
|
|
|
pub fn get_link<K>(&self, channel: &K) -> Option<&Link>
|
|
where T: Borrow<K>, K: Hash + Eq + ?Sized {
|
|
self.to.get(channel)
|
|
}
|
|
|
|
pub fn get_channels(&self, link: &Link) -> &[T] {
|
|
self.from.get(link).map_or(&[], Vec::as_slice)
|
|
}
|
|
|
|
pub fn insert(&mut self, link: Link, channel: T) {
|
|
self.to.insert(channel.clone(), link.clone());
|
|
self.from.entry(link)
|
|
.or_insert(Vec::with_capacity(1))
|
|
.push(channel);
|
|
}
|
|
|
|
pub fn iter_channels(&self) -> impl Iterator<Item=&T> {
|
|
self.to.keys()
|
|
}
|
|
}
|
|
|
|
impl <T: Hash + Eq + Clone> FromIterator<(T, Link)> for Linkmap<T> {
|
|
fn from_iter<I: IntoIterator<Item=(T, Link)>>(iter: I) -> Self {
|
|
let to: HashMap<T, Link> = iter.into_iter().collect();
|
|
let mut from = HashMap::with_capacity(to.len());
|
|
|
|
for (k, v) in &to {
|
|
from.entry(v.clone())
|
|
.or_insert(Vec::with_capacity(1))
|
|
.push(k.clone());
|
|
}
|
|
|
|
Self { to, from }
|
|
}
|
|
}
|
|
|
|
struct LinkmapVisitor<T> {
|
|
_phantom: PhantomData<T>,
|
|
}
|
|
|
|
impl <'de, T> Visitor<'de> for LinkmapVisitor<T>
|
|
where T: Eq + Hash + Clone + Deserialize<'de> {
|
|
type Value = Linkmap<T>;
|
|
|
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(formatter, "a linkmap")?;
|
|
Ok(())
|
|
}
|
|
|
|
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
|
|
where A: serde::de::MapAccess<'de>, {
|
|
let mut map = Linkmap::with_capacity(access.size_hint().unwrap_or(0));
|
|
|
|
while let Some((channel, link)) = access.next_entry()? {
|
|
map.insert(link, channel);
|
|
}
|
|
|
|
Ok(map)
|
|
}
|
|
}
|
|
|
|
impl <'de, T> Deserialize<'de> for Linkmap<T>
|
|
where T: Eq + Hash + Clone + Deserialize<'de> {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where D: Deserializer<'de> {
|
|
deserializer.deserialize_map(LinkmapVisitor { _phantom: PhantomData })
|
|
}
|
|
}
|