1pub use inventory;
8
9use std::collections::HashMap;
10
11pub trait Registrable: 'static + Send + Sync {
17 fn registry_key(&self) -> &str;
19}
20
21pub struct Registry<T: Registrable> {
27 items: HashMap<String, &'static T>,
28}
29
30impl<T: Registrable> std::fmt::Debug for Registry<T> {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.debug_struct("Registry")
33 .field("len", &self.items.len())
34 .field("keys", &self.list())
35 .finish()
36 }
37}
38
39impl<T: Registrable> Registry<T> {
40 pub fn new() -> Self {
42 Self {
43 items: HashMap::new(),
44 }
45 }
46
47 pub fn auto_discover() -> Self
49 where
50 T: inventory::Collect,
51 {
52 let mut reg = Self::new();
53 for item in inventory::iter::<T> {
54 reg.register(item);
55 }
56 reg
57 }
58
59 pub fn register(&mut self, item: &'static T) {
62 self.items.insert(item.registry_key().to_string(), item);
63 }
64
65 pub fn get(&self, key: &str) -> Option<&'static T> {
67 self.items.get(key).copied()
68 }
69
70 pub fn list(&self) -> Vec<&str> {
72 self.items.keys().map(|k| k.as_str()).collect()
73 }
74
75 pub fn len(&self) -> usize {
77 self.items.len()
78 }
79
80 pub fn is_empty(&self) -> bool {
82 self.items.is_empty()
83 }
84
85 pub fn iter(&self) -> impl Iterator<Item = &'static T> + '_ {
87 self.items.values().copied()
88 }
89}
90
91impl<T: Registrable> Default for Registry<T> {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl<T: Registrable> Clone for Registry<T> {
98 fn clone(&self) -> Self {
99 Self {
100 items: self.items.clone(),
101 }
102 }
103}
104
105#[macro_export]
121macro_rules! define_registry {
122 (
123 $(#[$meta:meta])*
124 $vis:vis struct $Name:ident for $Item:ty;
125 ) => {
126 $(#[$meta])*
127 $vis struct $Name {
128 inner: $crate::Registry<$Item>,
129 }
130
131 impl $Name {
132 pub fn new() -> Self {
133 Self {
134 inner: $crate::Registry::new(),
135 }
136 }
137
138 pub fn auto_discover() -> Self {
139 Self {
140 inner: $crate::Registry::auto_discover(),
141 }
142 }
143
144 pub fn register(&mut self, item: &'static $Item) {
145 self.inner.register(item);
146 }
147 }
148
149 impl ::std::ops::Deref for $Name {
150 type Target = $crate::Registry<$Item>;
151
152 fn deref(&self) -> &Self::Target {
153 &self.inner
154 }
155 }
156
157 impl ::std::ops::DerefMut for $Name {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 &mut self.inner
160 }
161 }
162
163 impl ::std::fmt::Debug for $Name {
164 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
165 f.debug_struct(stringify!($Name))
166 .field("len", &self.inner.len())
167 .field("keys", &self.inner.list())
168 .finish()
169 }
170 }
171
172 impl Clone for $Name {
173 fn clone(&self) -> Self {
174 Self {
175 inner: self.inner.clone(),
176 }
177 }
178 }
179
180 impl Default for $Name {
181 fn default() -> Self {
182 Self::new()
183 }
184 }
185 };
186}