1pub use plugin_runtime_codegen::*;
17
18use std::any::TypeId;
19use std::collections::HashMap;
20use std::fmt::Debug;
21use std::iter::Iterator;
22use std::marker::PhantomData;
23
24use typemap::{DebugMap, Key};
25
26#[derive(Debug, Default)]
27pub struct PluginList(pub HashMap<TypeId, FeatureMap>);
28
29impl PluginList {
30 pub fn require<'a, 'b, T: 'static, F>(&'a mut self, f: F) -> &'b mut FeatureMap
31 where
32 F: FnOnce(&mut Self) -> FeatureMap,
33 'a: 'b,
34 {
35 let id = TypeId::of::<T>();
36 if !self.0.contains_key(&id) {
37 let map = f(self);
38 self.0.insert(id, map);
39 }
40 self.0.get_mut(&id).unwrap()
41 }
42
43 pub fn list<'a, B: Debug + 'static>(&'a mut self) -> impl Iterator<Item = &'a mut B> {
44 self.0
45 .iter_mut()
46 .filter_map(|(_, map)| map.list())
47 .flatten()
48 }
49}
50
51pub trait PluginManifest {
52 fn init(deps: &mut PluginList) -> FeatureMap;
53}
54
55#[macro_export]
56macro_rules! require_plugin {
57 ($list:expr, $name:ident) => {
58 $list.require::<'_, '_, $name::PluginManifestImpl, _>(|list| {
59 use plugin_runtime::PluginManifest;
60 $name::PluginManifestImpl::init(list)
61 })
62 };
63}
64
65#[derive(Debug)]
66pub struct FeatureMap(pub DebugMap);
67
68impl Default for FeatureMap {
69 fn default() -> Self {
70 FeatureMap(DebugMap::custom())
71 }
72}
73
74#[derive(Debug)]
75struct FeatureEntry<B>(PhantomData<B>);
76
77impl<B: 'static> Key for FeatureEntry<B> {
78 type Value = Vec<B>;
79}
80
81impl FeatureMap {
82 pub fn put<B: Debug + 'static>(&mut self, value: B) {
83 if !self.0.contains::<FeatureEntry<B>>() {
84 self.0.insert::<FeatureEntry<B>>(Vec::new());
85 }
86 self.0.get_mut::<FeatureEntry<B>>().unwrap().push(value);
87 }
88
89 pub fn list<'a, B: Debug + 'static>(&'a mut self) -> Option<impl Iterator<Item = &'a mut B>> {
90 self.0
91 .get_mut::<FeatureEntry<B>>()
92 .map_or(None, |vec| Some(vec.iter_mut()))
93 }
94}
95
96#[macro_export]
97macro_rules! put_feature {
98 ($map:expr, $trait:ty, $v:expr) => {
99 $map.put::<Box<dyn $trait>>(Box::new($v));
100 };
101}