use std::collections::BTreeMap;
use std::fmt;
use crate::contract::Identified;
use crate::error::{Error, Result};
pub struct Registry<T> {
kind: &'static str,
items: BTreeMap<String, T>,
}
impl<T: Identified> Registry<T> {
pub fn new(kind: &'static str) -> Self {
Self {
kind,
items: BTreeMap::new(),
}
}
pub fn register(&mut self, item: T) -> &mut Self {
let identifier = item.identifier().to_string();
self.items.insert(identifier, item);
self
}
pub fn has(&self, identifier: &str) -> bool {
self.items.contains_key(identifier)
}
pub fn get(&self, identifier: &str) -> Result<&T> {
self.items
.get(identifier)
.ok_or_else(|| Error::UnknownIdentifier {
kind: self.kind,
identifier: identifier.to_string(),
})
}
pub fn identifiers(&self) -> Vec<&str> {
self.items.keys().map(String::as_str).collect()
}
}
impl<T: Identified> fmt::Debug for Registry<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Registry")
.field("kind", &self.kind)
.field("identifiers", &self.identifiers())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug)]
struct Dummy(&'static str);
impl Identified for Dummy {
fn identifier(&self) -> &str {
self.0
}
}
#[test]
fn register_get_has_identifiers() {
let mut registry = Registry::new("dummy");
registry.register(Dummy("a")).register(Dummy("b"));
assert!(registry.has("a"));
assert_eq!(registry.get("a").unwrap().identifier(), "a");
assert_eq!(registry.identifiers(), vec!["a", "b"]);
}
#[test]
fn unknown_identifier_is_an_error() {
let registry: Registry<Dummy> = Registry::new("dummy");
let error = registry.get("missing").unwrap_err();
assert_eq!(
error,
Error::UnknownIdentifier {
kind: "dummy",
identifier: "missing".to_string()
}
);
}
#[test]
fn re_registering_same_identifier_overwrites() {
let mut registry = Registry::new("dummy");
registry.register(Dummy("a"));
registry.register(Dummy("a"));
assert_eq!(registry.identifiers(), vec!["a"]);
}
}