plugin_runtime/
lib.rs

1// plugin-system
2// Copyright (C) SOFe
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16pub 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}