1use std::collections::BTreeMap;
6use std::fmt;
7
8use crate::contract::Identified;
9use crate::error::{Error, Result};
10
11pub struct Registry<T> {
16 kind: &'static str,
17 items: BTreeMap<String, T>,
18}
19
20impl<T: Identified> Registry<T> {
21 pub fn new(kind: &'static str) -> Self {
23 Self {
24 kind,
25 items: BTreeMap::new(),
26 }
27 }
28
29 pub fn register(&mut self, item: T) -> &mut Self {
31 let identifier = item.identifier().to_string();
32 self.items.insert(identifier, item);
33 self
34 }
35
36 pub fn has(&self, identifier: &str) -> bool {
37 self.items.contains_key(identifier)
38 }
39
40 pub fn get(&self, identifier: &str) -> Result<&T> {
41 self.items
42 .get(identifier)
43 .ok_or_else(|| Error::UnknownIdentifier {
44 kind: self.kind,
45 identifier: identifier.to_string(),
46 })
47 }
48
49 pub fn identifiers(&self) -> Vec<&str> {
51 self.items.keys().map(String::as_str).collect()
52 }
53}
54
55impl<T: Identified> fmt::Debug for Registry<T> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.debug_struct("Registry")
59 .field("kind", &self.kind)
60 .field("identifiers", &self.identifiers())
61 .finish()
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[derive(Debug)]
70 struct Dummy(&'static str);
71
72 impl Identified for Dummy {
73 fn identifier(&self) -> &str {
74 self.0
75 }
76 }
77
78 #[test]
79 fn register_get_has_identifiers() {
80 let mut registry = Registry::new("dummy");
81 registry.register(Dummy("a")).register(Dummy("b"));
82
83 assert!(registry.has("a"));
84 assert_eq!(registry.get("a").unwrap().identifier(), "a");
85 assert_eq!(registry.identifiers(), vec!["a", "b"]);
86 }
87
88 #[test]
89 fn unknown_identifier_is_an_error() {
90 let registry: Registry<Dummy> = Registry::new("dummy");
91 let error = registry.get("missing").unwrap_err();
92 assert_eq!(
93 error,
94 Error::UnknownIdentifier {
95 kind: "dummy",
96 identifier: "missing".to_string()
97 }
98 );
99 }
100
101 #[test]
102 fn re_registering_same_identifier_overwrites() {
103 let mut registry = Registry::new("dummy");
104 registry.register(Dummy("a"));
105 registry.register(Dummy("a"));
106 assert_eq!(registry.identifiers(), vec!["a"]);
107 }
108}