use std::collections::BTreeMap;
use std::sync::Mutex;
use crate::error::Error;
#[derive(Debug, Default)]
pub struct Aliases {
entries: Mutex<BTreeMap<String, String>>,
}
impl Aliases {
#[must_use]
pub const fn new() -> Self {
Self {
entries: Mutex::new(BTreeMap::new()),
}
}
pub fn add(&self, from: &str, to: &str) -> Result<(), Error> {
crate::layer::check_path(from)?;
crate::layer::check_path(to)?;
if from == to {
return Err(Error::new(
crate::ErrorKind::Type,
format!("`{from}` cannot be an alias for itself"),
));
}
self.lock().insert(from.to_owned(), to.to_owned());
Ok(())
}
pub fn clear(&self) {
self.lock().clear();
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.lock().is_empty()
}
#[must_use]
pub fn pairs(&self) -> Vec<(String, String)> {
self.lock()
.iter()
.map(|(from, to)| (from.clone(), to.clone()))
.collect()
}
#[must_use]
pub fn known_keys(&self) -> Vec<String> {
self.lock()
.keys()
.filter_map(|path| path.split('.').next().map(str::to_owned))
.collect()
}
fn lock(&self) -> std::sync::MutexGuard<'_, BTreeMap<String, String>> {
self.entries
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_path_that_names_nothing_is_refused() {
let aliases = Aliases::new();
assert!(aliases.add("", "pool.max_size").is_err());
assert!(aliases.add("pool..size", "pool.max_size").is_err());
assert!(aliases.add("pool.size", "").is_err());
}
#[test]
fn an_alias_to_itself_is_refused() {
let aliases = Aliases::new();
let error = aliases.add("pool.size", "pool.size").unwrap_err();
assert!(error.to_string().contains("itself"), "{error}");
}
#[test]
fn the_old_paths_top_level_key_counts_as_known() {
let aliases = Aliases::new();
aliases.add("legacy.size", "pool.max_size").unwrap();
aliases.add("host", "hostname").unwrap();
let known = aliases.known_keys();
assert!(known.contains(&"legacy".to_owned()));
assert!(known.contains(&"host".to_owned()));
}
#[test]
fn aliasing_the_same_path_twice_replaces_rather_than_layers() {
let aliases = Aliases::new();
aliases.add("old", "first").unwrap();
aliases.add("old", "second").unwrap();
assert_eq!(
aliases.pairs(),
vec![("old".to_owned(), "second".to_owned())]
);
}
}