use crate::error::ArgumentError;
use std::collections::HashMap;
use std::sync::Mutex;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Domain(usize);
pub fn get_unique_domain() -> Domain {
TRACKER
.lock()
.expect("Fatal error: internal mutex poisoned.")
.get_unique_domain()
}
pub fn resolve(name: &str) -> Result<Domain, ArgumentError> {
TRACKER
.lock()
.expect("Fatal error: internal mutex poisoned.")
.resolve(name)
}
pub fn try_reverse_resolve(domain: Domain) -> Option<String> {
TRACKER
.lock()
.expect("Fatal error: internal mutex poisoned.")
.try_reverse_resolve(domain)
}
lazy_static! {
static ref TRACKER: Mutex<DomainTracker> = Mutex::new(DomainTracker::new());
}
struct DomainTracker {
name_map: HashMap<String, Domain>,
reveres_name_map: HashMap<Domain, String>,
counter: usize,
}
impl DomainTracker {
fn resolve(&mut self, name: &str) -> Result<Domain, ArgumentError> {
if name.starts_with('@') {
return Err(ArgumentError::new(format!(
"The domain \"{}\" may not start with an @.",
name
)));
}
if name == "" {
return Err(ArgumentError::new("Domains may not be empty."));
}
Ok(match self.name_map.get(name) {
Some(&domain) => domain,
None => {
let new_domain = self.get_unique_domain();
self.name_map.insert(name.to_owned(), new_domain);
self.reveres_name_map.insert(new_domain, name.to_owned());
new_domain
}
})
}
fn try_reverse_resolve(&mut self, domain: Domain) -> Option<String> {
self.reveres_name_map.get(&domain).cloned()
}
fn get_unique_domain(&mut self) -> Domain {
let result = self.counter;
self.counter += 1;
Domain(result)
}
fn new() -> DomainTracker {
DomainTracker {
name_map: HashMap::new(),
reveres_name_map: HashMap::new(),
counter: 0,
}
}
}