/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use std::{borrow::Borrow, hash::Hash, rc::Rc}; use ahash::AHashMap; #[derive(Debug)] #[repr(transparent)] struct StringRef(Rc); #[derive(Debug)] #[repr(transparent)] struct IdRef(Rc); #[derive(Debug, Default)] pub struct IdBimap { id_to_name: AHashMap, Rc>, name_to_id: AHashMap, Rc>, } impl IdBimap { pub fn with_capacity(capacity: usize) -> Self { Self { id_to_name: AHashMap::with_capacity(capacity), name_to_id: AHashMap::with_capacity(capacity), } } pub fn insert(&mut self, item: T) { let item = Rc::new(item); self.id_to_name.insert(IdRef(item.clone()), item.clone()); self.name_to_id.insert(StringRef(item.clone()), item); } pub fn by_name(&self, name: &str) -> Option<&T> { self.name_to_id.get(name).map(|v| v.as_ref()) } pub fn by_id(&self, id: u32) -> Option<&T> { self.id_to_name.get(&id).map(|v| v.as_ref()) } pub fn iter(&self) -> impl Iterator { self.name_to_id.values().map(|v| v.as_ref()) } pub fn is_empty(&self) -> bool { self.name_to_id.is_empty() } } // SAFETY: Safe because Rc<> are never returned from the struct unsafe impl Send for IdBimap {} unsafe impl Sync for IdBimap {} pub trait IdBimapItem: std::fmt::Debug { fn id(&self) -> &u32; fn name(&self) -> &str; } impl Borrow for StringRef { fn borrow(&self) -> &str { self.0.name() } } impl Borrow for IdRef { fn borrow(&self) -> &u32 { self.0.id() } } impl PartialEq for StringRef { fn eq(&self, other: &Self) -> bool { self.0.name() == other.0.name() } } impl Eq for StringRef {} impl PartialEq for IdRef { fn eq(&self, other: &Self) -> bool { self.0.id() == other.0.id() } } impl Eq for IdRef {} impl Hash for StringRef { fn hash(&self, state: &mut H) { self.0.name().hash(state) } } impl Hash for IdRef { fn hash(&self, state: &mut H) { self.0.id().hash(state) } }