1use crate::app::info::AppInfo;
2use crate::app::update::UpdateManager;
3use crate::config::MayConfig;
4use crate::vgi::VectorGraphicsInterface;
5use maycoon_theme::theme::Theme;
6use rpds::HashTrieMap;
7use std::cell::RefCell;
8use std::ops::DerefMut;
9use std::rc::Rc;
10use std::sync::Arc;
11use std::time::Instant;
12use taffy::{NodeId, TaffyTree};
13use winit::event::WindowEvent;
14use winit::event_loop::{ActiveEventLoop, EventLoop};
15use winit::window::{Window, WindowAttributes};
16
17pub trait Plugin<T: Theme, V: VectorGraphicsInterface>: 'static {
24 fn name(&self) -> &'static str;
28
29 fn on_register(&mut self, _manager: &mut PluginManager<T, V>) {}
31
32 fn on_unregister(&mut self, _manager: &mut PluginManager<T, V>) {}
34
35 #[inline(always)]
37 fn init(
38 &mut self,
39 _event_loop: &mut EventLoop<()>,
40 _update: &UpdateManager,
41 _window: &mut WindowAttributes,
42 _config: &mut MayConfig<T, V>,
43 ) {
44 }
45
46 #[inline(always)]
51 fn on_resume(
52 &mut self,
53 _config: &mut MayConfig<T, V>,
54 _scene: &mut V::Scene,
55 _taffy: &mut TaffyTree,
56 _window_node: NodeId,
57 _info: &mut AppInfo,
58 _update: &UpdateManager,
59 _last_update: &mut Instant,
60 _event_loop: &ActiveEventLoop,
61 ) {
62 }
63
64 #[inline(always)]
67 fn on_update(
68 &mut self,
69 _config: &mut MayConfig<T, V>,
70 _window: &Arc<Window>,
71 _scene: &mut V::Scene,
72 _taffy: &mut TaffyTree,
73 _window_node: NodeId,
74 _info: &mut AppInfo,
75 _update: &UpdateManager,
76 _last_update: &mut Instant,
77 _event_loop: &ActiveEventLoop,
78 ) {
79 }
80
81 #[inline(always)]
83 fn on_window_event(
84 &mut self,
85 _event: &mut WindowEvent,
86 _config: &mut MayConfig<T, V>,
87 _window: &Arc<Window>,
88 _scene: &mut V::Scene,
89 _taffy: &mut TaffyTree,
90 _window_node: NodeId,
91 _info: &mut AppInfo,
92 _update: &UpdateManager,
93 _last_update: &mut Instant,
94 _event_loop: &ActiveEventLoop,
95 ) {
96 }
97
98 #[cold]
100 fn on_suspended(
101 &mut self,
102 _config: &mut MayConfig<T, V>,
103 _scene: &mut V::Scene,
104 _taffy: &mut TaffyTree,
105 _window_node: NodeId,
106 _info: &mut AppInfo,
107 _update: &UpdateManager,
108 _last_update: &mut Instant,
109 _event_loop: &ActiveEventLoop,
110 ) {
111 }
112}
113
114pub struct PluginManager<T: Theme, V: VectorGraphicsInterface> {
116 plugins: HashTrieMap<&'static str, Rc<RefCell<dyn Plugin<T, V>>>>,
117}
118
119impl<T: Theme, V: VectorGraphicsInterface> PluginManager<T, V> {
120 #[inline(always)]
122 pub fn new() -> Self {
123 Self {
124 plugins: HashTrieMap::new(),
125 }
126 }
127
128 #[inline(always)]
130 pub fn register(mut self, mut plugin: impl Plugin<T, V>) -> Self {
131 plugin.on_register(&mut self);
132
133 Self {
134 plugins: self
135 .plugins
136 .insert(plugin.name(), Rc::new(RefCell::new(plugin))),
137 }
138 }
139
140 #[cold]
142 pub fn unregister(mut self, name: &'static str) -> Self {
143 let plugins = self.plugins.clone();
144
145 plugins
146 .get(name)
147 .expect("Plugin not found")
148 .borrow_mut()
149 .on_unregister(&mut self);
150
151 Self {
152 plugins: self.plugins.remove(name),
153 }
154 }
155
156 #[cold]
158 pub fn clear(&mut self) {
159 let plugins = self.plugins.clone();
160
161 for (_, pl) in plugins.iter() {
162 pl.borrow_mut().on_unregister(self);
163 }
164
165 self.plugins = HashTrieMap::new();
166 }
167
168 #[inline(always)]
170 pub fn run<F>(&mut self, mut op: F)
171 where
172 F: FnMut(&mut dyn Plugin<T, V>),
173 {
174 for (_, plugin) in self.plugins.iter() {
175 let mut plugin = plugin.borrow_mut();
176
177 op(plugin.deref_mut());
178 }
179 }
180}
181
182impl<T: Theme, V: VectorGraphicsInterface> Default for PluginManager<T, V> {
183 #[inline(always)]
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189#[cfg(all(test, feature = "test"))]
190mod tests {
191 use crate::plugin::{Plugin, PluginManager};
192 use crate::vgi::dummy::DummyGraphics;
193 use maycoon_theme::theme::dummy::DummyTheme;
194 use std::sync::atomic::{AtomicU32, Ordering};
195
196 static A: AtomicU32 = AtomicU32::new(0);
197 static B: AtomicU32 = AtomicU32::new(0);
198 static C: AtomicU32 = AtomicU32::new(0);
199
200 #[test]
202 fn test_plugin_manager() {
203 let mut plugins = PluginManager::<DummyTheme, DummyGraphics>::new()
204 .register(TestPluginA)
205 .register(TestPluginB)
206 .register(TestPluginC);
207
208 let mut run_a = 0;
209 let mut run_b = 0;
210 let mut run_c = 0;
211
212 plugins.run(|pl| match pl.name() {
213 "Test Plugin A" => run_a += 1,
214 "Test Plugin B" => run_b += 1,
215 "Test Plugin C" => run_c += 1,
216 _ => panic!(),
217 });
218
219 assert_eq!(run_a, 1);
220 assert_eq!(run_b, 1);
221 assert_eq!(run_c, 1);
222
223 plugins
224 .unregister(<TestPluginA as Plugin<DummyTheme, DummyGraphics>>::name(
225 &TestPluginA,
226 ))
227 .unregister(<TestPluginB as Plugin<DummyTheme, DummyGraphics>>::name(
228 &TestPluginB,
229 ))
230 .unregister(<TestPluginC as Plugin<DummyTheme, DummyGraphics>>::name(
231 &TestPluginC,
232 ));
233
234 assert_eq!(A.load(Ordering::Relaxed), 11);
235 assert_eq!(B.load(Ordering::Relaxed), 11);
236 assert_eq!(C.load(Ordering::Relaxed), 11);
237 }
238
239 struct TestPluginA;
240
241 impl Plugin<DummyTheme, DummyGraphics> for TestPluginA {
242 fn name(&self) -> &'static str {
243 "Test Plugin A"
244 }
245
246 fn on_register(&mut self, _manager: &mut PluginManager<DummyTheme, DummyGraphics>) {
247 A.fetch_add(1, Ordering::Relaxed);
248 }
249
250 fn on_unregister(&mut self, _manager: &mut PluginManager<DummyTheme, DummyGraphics>) {
251 A.fetch_add(10, Ordering::Relaxed);
252 }
253 }
254
255 struct TestPluginB;
256
257 impl Plugin<DummyTheme, DummyGraphics> for TestPluginB {
258 fn name(&self) -> &'static str {
259 "Test Plugin B"
260 }
261
262 fn on_register(&mut self, _manager: &mut PluginManager<DummyTheme, DummyGraphics>) {
263 B.fetch_add(1, Ordering::Relaxed);
264 }
265
266 fn on_unregister(&mut self, _manager: &mut PluginManager<DummyTheme, DummyGraphics>) {
267 B.fetch_add(10, Ordering::Relaxed);
268 }
269 }
270
271 struct TestPluginC;
272
273 impl Plugin<DummyTheme, DummyGraphics> for TestPluginC {
274 fn name(&self) -> &'static str {
275 "Test Plugin C"
276 }
277
278 fn on_register(&mut self, _manager: &mut PluginManager<DummyTheme, DummyGraphics>) {
279 C.fetch_add(1, Ordering::Relaxed);
280 }
281
282 fn on_unregister(&mut self, _manager: &mut PluginManager<DummyTheme, DummyGraphics>) {
283 C.fetch_add(10, Ordering::Relaxed);
284 }
285 }
286}