pub use inventory;
use std::collections::HashMap;
pub trait Registrable: 'static + Send + Sync {
fn registry_key(&self) -> &str;
}
pub struct Registry<T: Registrable> {
items: HashMap<String, &'static T>,
}
impl<T: Registrable> std::fmt::Debug for Registry<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Registry")
.field("len", &self.items.len())
.field("keys", &self.list())
.finish()
}
}
impl<T: Registrable> Registry<T> {
pub fn new() -> Self {
Self {
items: HashMap::new(),
}
}
pub fn auto_discover() -> Self
where
T: inventory::Collect,
{
let mut reg = Self::new();
for item in inventory::iter::<T> {
reg.register(item);
}
reg
}
pub fn register(&mut self, item: &'static T) {
self.items.insert(item.registry_key().to_string(), item);
}
pub fn get(&self, key: &str) -> Option<&'static T> {
self.items.get(key).copied()
}
pub fn list(&self) -> Vec<&str> {
self.items.keys().map(|k| k.as_str()).collect()
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &'static T> + '_ {
self.items.values().copied()
}
}
impl<T: Registrable> Default for Registry<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Registrable> Clone for Registry<T> {
fn clone(&self) -> Self {
Self {
items: self.items.clone(),
}
}
}
#[macro_export]
macro_rules! define_registry {
(
$(#[$meta:meta])*
$vis:vis struct $Name:ident for $Item:ty;
) => {
$(#[$meta])*
$vis struct $Name {
inner: $crate::Registry<$Item>,
}
impl $Name {
pub fn new() -> Self {
Self {
inner: $crate::Registry::new(),
}
}
pub fn auto_discover() -> Self {
Self {
inner: $crate::Registry::auto_discover(),
}
}
pub fn register(&mut self, item: &'static $Item) {
self.inner.register(item);
}
}
impl ::std::ops::Deref for $Name {
type Target = $crate::Registry<$Item>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl ::std::ops::DerefMut for $Name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl ::std::fmt::Debug for $Name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
f.debug_struct(stringify!($Name))
.field("len", &self.inner.len())
.field("keys", &self.inner.list())
.finish()
}
}
impl Clone for $Name {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl Default for $Name {
fn default() -> Self {
Self::new()
}
}
};
}