1use std::{any::TypeId, collections::BTreeMap, fmt::Debug};
2
3use inventory::{Collect, Registry};
4use thiserror::Error;
5
6pub trait Factory<T: ?Sized> {
11 fn create(&self) -> Box<T>;
12}
13
14#[derive(Debug, Error)]
16pub enum FactoryError {
17 #[error("未找到 ID 为 '{0}' 的工厂")]
19 FactoryNotFound(String),
20
21 #[error("不允许回退时提供了空 ID")]
23 EmptyIdNoFallback,
24
25 #[error("没有可用的工厂")]
27 NoFactoriesAvailable,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum FactoryFallback {
33 First,
35
36 Last,
38
39 NoFallback,
41}
42
43pub struct SimpleFactory<T: ?Sized + 'static>(
52 BTreeMap<&'static str, &'static (dyn Factory<T> + Sync)>,
53);
54
55impl<T> SimpleFactory<T>
56where
57 T: ?Sized + 'static,
58{
59 pub fn create<'a>(
76 &self,
77 id: &'a str,
78 strategy: FactoryFallback,
79 ) -> Result<(&'a str, Box<T>), FactoryError> {
80 if !id.is_empty() {
81 return if let Some(factory) = self.0.get(id) {
82 Ok((id, factory.create()))
83 } else {
84 Err(FactoryError::FactoryNotFound(id.to_string()))
85 };
86 }
87
88 match strategy {
89 FactoryFallback::First => {
90 if let Some((id, factory)) = self.0.first_key_value() {
91 return Ok((id, factory.create()));
92 }
93 }
94 FactoryFallback::Last => {
95 if let Some((id, factory)) = self.0.last_key_value() {
96 return Ok((id, factory.create()));
97 }
98 }
99 FactoryFallback::NoFallback => return Err(FactoryError::EmptyIdNoFallback),
100 }
101
102 Err(FactoryError::NoFactoriesAvailable)
103 }
104}
105
106pub struct FactoryRegistry<T>
111where
112 T: ?Sized + 'static,
113{
114 id: &'static str,
119
120 factory: &'static (dyn Factory<T> + Sync),
125
126 type_id: TypeId,
131}
132
133impl<T> Collect for FactoryRegistry<T>
134where
135 T: ?Sized + 'static,
136{
137 fn registry() -> &'static Registry {
138 static REGISTRY: Registry = Registry::new();
139
140 ®ISTRY
141 }
142}
143
144impl<T> FactoryRegistry<T>
145where
146 T: ?Sized + 'static,
147{
148 #[inline]
154 pub const fn new(id: &'static str, factory: &'static (dyn Factory<T> + Sync)) -> Self {
155 Self {
156 id,
157 factory,
158 type_id: TypeId::of::<T>(),
159 }
160 }
161
162 pub fn simple_factory() -> SimpleFactory<T> {
173 let type_id = TypeId::of::<T>();
174 let factories = inventory::iter::<Self>()
175 .filter_map(|reg| (type_id == reg.type_id).then_some((reg.id, reg.factory)))
176 .collect();
177
178 SimpleFactory(factories)
179 }
180}
181
182#[macro_export]
186macro_rules! register_factory {
187 ($product:ty, $id:literal, $implement:ty) => {
188 $crate::const_assert!(!$id.is_empty());
189 $crate::assert_impl_one!($implement: Default);
190
191 const _: () = {
192 struct ConcreteFactory;
193
194 impl $crate::Factory<$product> for ConcreteFactory {
195 fn create(&self) -> Box<$product> {
196 Box::<$implement>::default()
197 }
198 }
199
200 $crate::submit! {
201 $crate::FactoryRegistry::new(
202 $id,
203 &ConcreteFactory as &'static (dyn $crate::Factory<$product> + Sync),
204 )
205 }
206 };
207 };
208}