use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BiMap<L: Hash + Eq, R: Hash + Eq> {
left_to_right: HashMap<L, R>,
right_to_left: HashMap<R, L>,
}
impl<L: Eq + Hash + Clone, R: Eq + Hash + Clone> BiMap<L, R> {
pub fn new() -> Self {
BiMap {
left_to_right: HashMap::new(),
right_to_left: HashMap::new(),
}
}
pub fn from<const N: usize>(pairs: [(L, R); N]) -> Self {
let mut this = BiMap::new();
for (left, right) in pairs {
this.insert(left, right);
}
this
}
pub fn len(&self) -> usize {
self.left_to_right.len()
}
pub fn into_inner(self) -> (HashMap<L, R>, HashMap<R, L>) {
(self.left_to_right, self.right_to_left)
}
pub fn into_reversed(self) -> BiMap<R, L> {
BiMap {
left_to_right: self.right_to_left,
right_to_left: self.left_to_right,
}
}
pub fn into_left_map(self) -> HashMap<L, R> {
self.left_to_right
}
pub fn into_right_map(self) -> HashMap<R, L> {
self.right_to_left
}
pub fn insert(&mut self, left: L, right: R) {
if self.left_to_right.contains_key(&left) || self.right_to_left.contains_key(&right) {
panic!("Cannot insert: left or right already exists in the map");
}
self.left_to_right.insert(left.clone(), right.clone());
self.right_to_left.insert(right, left);
}
pub fn get_left(&self, left: &L) -> Option<&R> {
self.left_to_right.get(left)
}
pub fn get_right(&self, right: &R) -> Option<&L> {
self.right_to_left.get(right)
}
pub fn contains_left(&self, left: &L) -> bool {
self.left_to_right.contains_key(left)
}
pub fn contains_right(&self, right: &R) -> bool {
self.right_to_left.contains_key(right)
}
pub fn remove_left(&mut self, left: &L) -> Option<R> {
if let Some(right) = self.left_to_right.remove(left) {
self.right_to_left.remove(&right);
Some(right)
} else {
None
}
}
pub fn remove_right(&mut self, right: &R) -> Option<L> {
if let Some(left) = self.right_to_left.remove(right) {
self.left_to_right.remove(&left);
Some(left)
} else {
None
}
}
pub fn right_values(&self) -> impl Iterator<Item = &R> {
self.left_to_right.values()
}
pub fn left_values(&self) -> impl Iterator<Item = &L> {
self.right_to_left.values()
}
pub fn iter(&self) -> impl Iterator<Item = (&L, &R)> {
self.left_to_right.iter()
}
}
impl<L: Eq + std::hash::Hash + Clone, R: Eq + std::hash::Hash + Clone> IntoIterator
for BiMap<L, R>
{
type Item = (L, R);
type IntoIter = std::collections::hash_map::IntoIter<L, R>;
fn into_iter(self) -> Self::IntoIter {
self.left_to_right.into_iter()
}
}