1use std::{
4 any::TypeId,
5 collections::{HashMap, VecDeque},
6 sync::Arc,
7};
8
9use crate::event_bus::EventBus;
10
11use super::{Plugin, PluginContext, PluginId, PluginStateRegistry};
12
13#[derive(Debug)]
15pub enum PluginError {
16 MissingDependency {
18 plugin: PluginId,
20 dependency_name: &'static str,
22 },
23 CircularDependency(Vec<PluginId>),
25 AlreadyLoaded(PluginId),
27}
28
29impl std::fmt::Display for PluginError {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 Self::MissingDependency {
33 plugin,
34 dependency_name,
35 } => {
36 write!(
37 f,
38 "Plugin '{plugin}' requires dependency '{dependency_name}' which is not loaded"
39 )
40 }
41 Self::CircularDependency(cycle) => {
42 write!(f, "Circular dependency detected: ")?;
43 for (i, id) in cycle.iter().enumerate() {
44 if i > 0 {
45 write!(f, " -> ")?;
46 }
47 write!(f, "{id}")?;
48 }
49 Ok(())
50 }
51 Self::AlreadyLoaded(id) => {
52 write!(f, "Plugin '{id}' is already loaded")
53 }
54 }
55 }
56}
57
58impl std::error::Error for PluginError {}
59
60pub struct PluginLoader {
64 plugins: Vec<Box<dyn Plugin>>,
66 type_map: HashMap<TypeId, usize>,
68 type_names: HashMap<TypeId, &'static str>,
70}
71
72impl Default for PluginLoader {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl PluginLoader {
79 #[must_use]
81 pub fn new() -> Self {
82 Self {
83 plugins: Vec::new(),
84 type_map: HashMap::new(),
85 type_names: HashMap::new(),
86 }
87 }
88
89 pub fn add<P: Plugin>(&mut self, plugin: P) -> &mut Self {
93 let type_id = TypeId::of::<P>();
94 let idx = self.plugins.len();
95 self.type_names.insert(type_id, std::any::type_name::<P>());
96 self.plugins.push(Box::new(plugin));
97 self.type_map.insert(type_id, idx);
98 self
99 }
100
101 pub fn add_plugins<T: PluginTuple>(&mut self, plugins: T) -> &mut Self {
108 plugins.add_to(self);
109 self
110 }
111
112 pub fn load(self, ctx: &mut PluginContext) -> Result<(), PluginError> {
117 let order = self.resolve_order()?;
119
120 for idx in &order {
122 let plugin = &self.plugins[*idx];
123 let plugin_id = plugin.id();
124 tracing::debug!(plugin = %plugin_id, "Building plugin");
125 ctx.set_current_plugin(plugin_id.to_string());
126 plugin.build(ctx);
127 ctx.clear_current_plugin();
128 ctx.mark_loaded_by_id(self.type_id_for_index(*idx));
129 }
130
131 for idx in &order {
133 let plugin = &self.plugins[*idx];
134 plugin.finish(ctx);
135 }
136
137 Ok(())
138 }
139
140 pub fn load_with_state(
154 self,
155 ctx: &mut PluginContext,
156 state_registry: &Arc<PluginStateRegistry>,
157 event_bus: &Arc<EventBus>,
158 ) -> Result<Vec<Box<dyn Plugin>>, PluginError> {
159 let order = self.resolve_order()?;
161
162 for idx in &order {
164 let plugin = &self.plugins[*idx];
165 let plugin_id = plugin.id();
166 tracing::debug!(plugin = %plugin_id, "Building plugin");
167 ctx.set_current_plugin(plugin_id.to_string());
168 plugin.build(ctx);
169 ctx.clear_current_plugin();
170 ctx.mark_loaded_by_id(self.type_id_for_index(*idx));
171 }
172
173 for idx in &order {
175 let plugin = &self.plugins[*idx];
176 tracing::debug!(plugin = %plugin.id(), "Initializing plugin state");
177 plugin.init_state(state_registry);
178 }
179
180 for idx in &order {
182 let plugin = &self.plugins[*idx];
183 plugin.finish(ctx);
184 }
185
186 for idx in &order {
188 let plugin = &self.plugins[*idx];
189 tracing::debug!(plugin = %plugin.id(), "Subscribing plugin to events");
190 plugin.subscribe(event_bus, Arc::clone(state_registry));
191 }
192
193 let mut plugins: Vec<Option<Box<dyn Plugin>>> =
196 self.plugins.into_iter().map(Some).collect();
197 let mut ordered_plugins = Vec::with_capacity(order.len());
198
199 for idx in order {
200 if let Some(plugin) = plugins[idx].take() {
201 ordered_plugins.push(plugin);
202 }
203 }
204
205 Ok(ordered_plugins)
206 }
207
208 fn resolve_order(&self) -> Result<Vec<usize>, PluginError> {
210 let n = self.plugins.len();
211 let mut in_degree = vec![0usize; n];
212 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
213
214 for (idx, plugin) in self.plugins.iter().enumerate() {
216 for dep_type_id in plugin.dependencies() {
217 if let Some(&dep_idx) = self.type_map.get(&dep_type_id) {
218 adj[dep_idx].push(idx);
219 in_degree[idx] += 1;
220 } else {
221 let dep_name = self
222 .type_names
223 .get(&dep_type_id)
224 .copied()
225 .unwrap_or("unknown");
226 return Err(PluginError::MissingDependency {
227 plugin: plugin.id(),
228 dependency_name: dep_name,
229 });
230 }
231 }
232
233 for dep_type_id in plugin.optional_dependencies() {
235 if let Some(&dep_idx) = self.type_map.get(&dep_type_id) {
236 adj[dep_idx].push(idx);
237 in_degree[idx] += 1;
238 }
239 }
240 }
241
242 let mut queue: VecDeque<usize> = (0..n).filter(|&i| in_degree[i] == 0).collect();
244 let mut result = Vec::with_capacity(n);
245
246 while let Some(idx) = queue.pop_front() {
247 result.push(idx);
248 for &next in &adj[idx] {
249 in_degree[next] -= 1;
250 if in_degree[next] == 0 {
251 queue.push_back(next);
252 }
253 }
254 }
255
256 if result.len() != n {
257 let cycle = self.find_cycle(&in_degree);
259 return Err(PluginError::CircularDependency(cycle));
260 }
261
262 Ok(result)
263 }
264
265 fn type_id_for_index(&self, idx: usize) -> TypeId {
267 for (&type_id, &plugin_idx) in &self.type_map {
268 if plugin_idx == idx {
269 return type_id;
270 }
271 }
272 unreachable!("Index should always have a TypeId")
273 }
274
275 fn find_cycle(&self, in_degree: &[usize]) -> Vec<PluginId> {
277 let mut cycle_nodes: Vec<PluginId> = in_degree
279 .iter()
280 .enumerate()
281 .filter(|&(_, deg)| *deg > 0)
282 .map(|(idx, _)| self.plugins[idx].id())
283 .collect();
284
285 if cycle_nodes.is_empty() {
287 cycle_nodes = self.plugins.iter().map(|p| p.id()).collect();
288 }
289
290 cycle_nodes
291 }
292}
293
294pub trait PluginTuple {
296 fn add_to(self, loader: &mut PluginLoader);
298}
299
300impl<P: Plugin> PluginTuple for P {
302 fn add_to(self, loader: &mut PluginLoader) {
303 loader.add(self);
304 }
305}
306
307impl<P1: Plugin, P2: Plugin> PluginTuple for (P1, P2) {
309 fn add_to(self, loader: &mut PluginLoader) {
310 loader.add(self.0);
311 loader.add(self.1);
312 }
313}
314
315impl<P1: Plugin, P2: Plugin, P3: Plugin> PluginTuple for (P1, P2, P3) {
316 fn add_to(self, loader: &mut PluginLoader) {
317 loader.add(self.0);
318 loader.add(self.1);
319 loader.add(self.2);
320 }
321}
322
323impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin> PluginTuple for (P1, P2, P3, P4) {
324 fn add_to(self, loader: &mut PluginLoader) {
325 loader.add(self.0);
326 loader.add(self.1);
327 loader.add(self.2);
328 loader.add(self.3);
329 }
330}
331
332impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin, P5: Plugin> PluginTuple
333 for (P1, P2, P3, P4, P5)
334{
335 fn add_to(self, loader: &mut PluginLoader) {
336 loader.add(self.0);
337 loader.add(self.1);
338 loader.add(self.2);
339 loader.add(self.3);
340 loader.add(self.4);
341 }
342}
343
344impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin, P5: Plugin, P6: Plugin> PluginTuple
345 for (P1, P2, P3, P4, P5, P6)
346{
347 fn add_to(self, loader: &mut PluginLoader) {
348 loader.add(self.0);
349 loader.add(self.1);
350 loader.add(self.2);
351 loader.add(self.3);
352 loader.add(self.4);
353 loader.add(self.5);
354 }
355}
356
357impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin, P5: Plugin, P6: Plugin, P7: Plugin> PluginTuple
358 for (P1, P2, P3, P4, P5, P6, P7)
359{
360 fn add_to(self, loader: &mut PluginLoader) {
361 loader.add(self.0);
362 loader.add(self.1);
363 loader.add(self.2);
364 loader.add(self.3);
365 loader.add(self.4);
366 loader.add(self.5);
367 loader.add(self.6);
368 }
369}
370
371impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin, P5: Plugin, P6: Plugin, P7: Plugin, P8: Plugin>
372 PluginTuple for (P1, P2, P3, P4, P5, P6, P7, P8)
373{
374 fn add_to(self, loader: &mut PluginLoader) {
375 loader.add(self.0);
376 loader.add(self.1);
377 loader.add(self.2);
378 loader.add(self.3);
379 loader.add(self.4);
380 loader.add(self.5);
381 loader.add(self.6);
382 loader.add(self.7);
383 }
384}
385
386impl<
387 P1: Plugin,
388 P2: Plugin,
389 P3: Plugin,
390 P4: Plugin,
391 P5: Plugin,
392 P6: Plugin,
393 P7: Plugin,
394 P8: Plugin,
395 P9: Plugin,
396> PluginTuple for (P1, P2, P3, P4, P5, P6, P7, P8, P9)
397{
398 fn add_to(self, loader: &mut PluginLoader) {
399 loader.add(self.0);
400 loader.add(self.1);
401 loader.add(self.2);
402 loader.add(self.3);
403 loader.add(self.4);
404 loader.add(self.5);
405 loader.add(self.6);
406 loader.add(self.7);
407 loader.add(self.8);
408 }
409}
410
411impl<
412 P1: Plugin,
413 P2: Plugin,
414 P3: Plugin,
415 P4: Plugin,
416 P5: Plugin,
417 P6: Plugin,
418 P7: Plugin,
419 P8: Plugin,
420 P9: Plugin,
421 P10: Plugin,
422> PluginTuple for (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)
423{
424 fn add_to(self, loader: &mut PluginLoader) {
425 loader.add(self.0);
426 loader.add(self.1);
427 loader.add(self.2);
428 loader.add(self.3);
429 loader.add(self.4);
430 loader.add(self.5);
431 loader.add(self.6);
432 loader.add(self.7);
433 loader.add(self.8);
434 loader.add(self.9);
435 }
436}