plux_rs/loader.rs
1use rayon::prelude::{
2 IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
3 IntoParallelRefMutIterator, ParallelIterator,
4};
5use semver::Version;
6
7use crate::{
8 Bundle, Info, LoaderContext, Manager, Plugin, PluginInfo, Registry, Requests,
9 utils::{
10 LoadPluginError, PluginCallRequestError, PluginOperationError, Ptr, RegisterManagerError,
11 RegisterPluginError, StopLoaderError, UnloadPluginError, UnregisterManagerError,
12 UnregisterPluginError,
13 },
14 variable::Variable,
15};
16
17/// Main loader for plugins and managers.
18///
19/// The Loader is the central component of Plux responsible for managing the entire plugin ecosystem.
20/// It handles plugin discovery, loading, unloading, and provides the interface for interacting
21/// with plugins and managers.
22///
23/// # Type Parameters
24///
25/// * `'a` - Lifetime parameter for references within the loader
26/// * `O` - Output type for plugin functions (must implement Send + Sync)
27/// * `I` - Plugin information type (must implement Info trait)
28///
29/// # Fields
30///
31/// * `managers` - Collection of registered plugin managers
32/// * `registry` - Registry of functions available to plugins
33/// * `requests` - Collection of function requests from the host for plugins
34/// * `plugins` - Collection of loaded plugins
35///
36/// # Example
37///
38/// ```rust,no_run,ignore
39/// use plux_rs::prelude::*;
40/// use plux_custom_manager::CustomManager;
41///
42/// let mut loader = Loader::new();
43/// loader.context(|mut ctx| {
44/// ctx.register_manager(CustomManager::new())?;
45/// // Register functions and requests here
46/// Ok(())
47/// });
48/// ```
49//TODO: Conduct a small code refactoring for comfortable use of the library by Rust programmers
50pub struct Loader<'a, O: Send + Sync, I: Info> {
51 pub(crate) managers: Vec<Box<dyn Manager<'a, O, I>>>,
52 pub(crate) registry: Registry<O>,
53 pub(crate) requests: Requests,
54 pub(crate) plugins: Vec<Plugin<'a, O, I>>,
55}
56
57impl<'a, O: Send + Sync, I: Info> Loader<'a, O, I> {
58 /// Creates a new plugin loader instance.
59 ///
60 /// Initializes an empty loader with no managers, plugins, or functions registered.
61 ///
62 /// # Returns
63 ///
64 /// Returns a new Loader instance ready for configuration.
65 pub const fn new() -> Self {
66 Self {
67 managers: vec![],
68 registry: vec![],
69 requests: vec![],
70 plugins: vec![],
71 }
72 }
73
74 /// Provides access to the loader context for configuration.
75 ///
76 /// This method creates a context that allows registering managers, functions, and requests
77 /// with the loader. The context ensures proper initialization order and provides a fluent
78 /// interface for loader setup.
79 ///
80 /// # Parameters
81 ///
82 /// * `f` - Closure that receives the loader context and returns a result
83 ///
84 /// # Returns
85 ///
86 /// Returns the result of the closure execution.
87 ///
88 /// # Example
89 ///
90 /// ```rust,no_run
91 /// use plux_rs::{Loader, StdInfo};
92 ///
93 /// let mut loader = Loader::<'_, (), StdInfo>::new();
94 /// loader.context(|mut ctx| {
95 /// // Register managers, functions, and requests here
96 /// Ok::<(), Box<dyn std::error::Error>>(())
97 /// });
98 /// ```
99 pub fn context<FO, R>(&mut self, f: FO) -> R
100 where
101 FO: FnOnce(LoaderContext<'a, '_, O, I>) -> R,
102 {
103 f(LoaderContext::new(self))
104 }
105
106 /// Stops the loader and cleans up all resources.
107 ///
108 /// This method unloads all plugins and unregisters all managers in the correct order,
109 /// ensuring proper cleanup of resources.
110 ///
111 /// # Returns
112 ///
113 /// Returns `Result<(), StopLoaderError>` indicating success or failure of the shutdown process.
114 pub fn stop(&mut self) -> Result<(), StopLoaderError> {
115 private_loader::stop_plugins(self)?;
116 private_loader::stop_managers(self)?;
117 Ok(())
118 }
119
120 /// Registers a plugin manager with the loader.
121 ///
122 /// This method registers a manager that can handle plugins of a specific format.
123 /// The manager will be used to load and manage plugins matching its format.
124 ///
125 /// # Parameters
126 ///
127 /// * `manager` - The manager instance to register
128 ///
129 /// # Returns
130 ///
131 /// Returns `Result<(), RegisterManagerError>` indicating success or failure.
132 /// Fails if a manager with the same format is already registered.
133 ///
134 /// # Type Parameters
135 ///
136 /// * `M` - Type of the manager (must implement Manager trait)
137 pub fn register_manager<M>(&mut self, manager: M) -> Result<(), RegisterManagerError>
138 where
139 M: Manager<'a, O, I> + 'static,
140 {
141 private_loader::register_manager(self, Box::new(manager))
142 }
143
144 /// Forcefully registers a plugin manager, bypassing safety checks.
145 ///
146 /// This unsafe method allows registering a manager without checking for format conflicts.
147 /// Use with caution as it may lead to undefined behavior.
148 ///
149 /// # Parameters
150 ///
151 /// * `manager` - The manager instance to register
152 ///
153 /// # Returns
154 ///
155 /// Returns `Result<(), RegisterManagerError>` indicating success or failure.
156 ///
157 /// # Safety
158 ///
159 /// This method is unsafe because it bypasses format conflict checks that prevent
160 /// multiple managers from handling the same plugin format.
161 pub unsafe fn forced_register_manager(
162 &mut self,
163 manager: Box<dyn Manager<'a, O, I>>,
164 ) -> Result<(), RegisterManagerError> {
165 private_loader::forced_register_manager(self, manager)
166 }
167
168 /// Registers multiple plugin managers with the loader.
169 ///
170 /// This method registers a collection of managers in sequence.
171 /// Stops at the first error encountered.
172 ///
173 /// # Parameters
174 ///
175 /// * `managers` - Iterator of manager instances to register
176 ///
177 /// # Returns
178 ///
179 /// Returns `Result<(), RegisterManagerError>` indicating success or failure.
180 pub fn register_managers<M>(&mut self, managers: M) -> Result<(), RegisterManagerError>
181 where
182 M: IntoIterator<Item = Box<dyn Manager<'a, O, I>>>,
183 {
184 managers
185 .into_iter()
186 .try_for_each(|manager| private_loader::register_manager(self, manager))?;
187
188 Ok(())
189 }
190
191 /// Registers multiple plugin managers in parallel.
192 ///
193 /// This method registers a collection of managers concurrently using parallel processing.
194 /// More efficient for large numbers of managers.
195 ///
196 /// # Parameters
197 ///
198 /// * `managers` - Parallel iterator of manager instances to register
199 ///
200 /// # Returns
201 ///
202 /// Returns `Result<(), RegisterManagerError>` indicating success or failure.
203 pub fn par_register_managers<M>(&mut self, managers: M) -> Result<(), RegisterManagerError>
204 where
205 M: IntoParallelIterator<Item = Box<dyn Manager<'a, O, I>>>,
206 {
207 let this = Ptr::new(self);
208 managers.into_par_iter().try_for_each(move |manager| {
209 private_loader::register_manager(this.as_mut(), manager)
210 })?;
211
212 Ok(())
213 }
214
215 /// Unregisters a plugin manager from the loader.
216 ///
217 /// This method removes a manager from the loader, first unloading any plugins
218 /// associated with that manager.
219 ///
220 /// # Parameters
221 ///
222 /// * `format` - The format of the manager to unregister
223 ///
224 /// # Returns
225 ///
226 /// Returns `Result<(), UnregisterManagerError>` indicating success or failure.
227 pub fn unregister_manager(&mut self, format: &str) -> Result<(), UnregisterManagerError> {
228 let index = self
229 .managers
230 .iter()
231 .enumerate()
232 .find_map(|(i, manager)| match manager.format() == format {
233 true => Some(i),
234 false => None,
235 })
236 .ok_or(UnregisterManagerError::NotFound)?;
237
238 private_loader::unregister_manager(self, index)
239 }
240
241 /// Forcefully unregisters a plugin manager, bypassing safety checks.
242 ///
243 /// This unsafe method allows unregistering a manager without checking if it exists.
244 /// Use with caution as it may lead to undefined behavior.
245 ///
246 /// # Parameters
247 ///
248 /// * `index` - Index of the manager to unregister
249 ///
250 /// # Returns
251 ///
252 /// Returns `Result<(), UnregisterManagerError>` indicating success or failure.
253 ///
254 /// # Safety
255 ///
256 /// This method is unsafe because it bypasses existence checks that prevent
257 /// accessing invalid memory or indices.
258 pub unsafe fn forced_unregister_manager(
259 &mut self,
260 index: usize,
261 ) -> Result<(), UnregisterManagerError> {
262 private_loader::forced_unregister_manager(&mut self.managers, index)
263 }
264
265 /*
266 TODO: Refactoring example: Add manager search by its type
267 * Example: let manager = loader.get_manager::<MyManager>();
268 */
269 /// Gets an immutable reference to a manager by format.
270 ///
271 /// Searches for a registered manager that handles the specified format.
272 ///
273 /// # Parameters
274 ///
275 /// * `format` - The plugin format to search for (e.g., "lua", "rs")
276 ///
277 /// # Returns
278 ///
279 /// Returns `Option<&Box<dyn Manager<'a, O, I>>>` containing the manager if found.
280 pub fn get_manager_ref(&self, format: &str) -> Option<&Box<dyn Manager<'a, O, I>>> {
281 self.managers.iter().find(|m| m.format() == format)
282 }
283
284 /// Gets an immutable reference to a manager by format (parallel version).
285 ///
286 /// Searches for a registered manager that handles the specified format using parallel processing.
287 ///
288 /// # Parameters
289 ///
290 /// * `format` - The plugin format to search for (e.g., "lua", "rs")
291 ///
292 /// # Returns
293 ///
294 /// Returns `Option<&Box<dyn Manager<'a, O, I>>>` containing the manager if found.
295 pub fn par_get_manager_ref(&self, format: &str) -> Option<&Box<dyn Manager<'a, O, I>>> {
296 self.managers
297 .par_iter()
298 .find_first(|m| m.format() == format)
299 }
300
301 /// Gets a mutable reference to a manager by format.
302 ///
303 /// Searches for a registered manager that handles the specified format.
304 ///
305 /// # Parameters
306 ///
307 /// * `format` - The plugin format to search for (e.g., "lua", "rs")
308 ///
309 /// # Returns
310 ///
311 /// Returns `Option<&mut Box<dyn Manager<'a, O, I>>>` containing the manager if found.
312 pub fn get_manager_mut(&mut self, format: &str) -> Option<&mut Box<dyn Manager<'a, O, I>>> {
313 self.managers.iter_mut().find(|m| m.format() == format)
314 }
315
316 /// Gets a mutable reference to a manager by format (parallel version).
317 ///
318 /// Searches for a registered manager that handles the specified format using parallel processing.
319 ///
320 /// # Parameters
321 ///
322 /// * `format` - The plugin format to search for (e.g., "lua", "rs")
323 ///
324 /// # Returns
325 ///
326 /// Returns `Option<&mut Box<dyn Manager<'a, O, I>>>` containing the manager if found.
327 pub fn par_get_manager_mut(&mut self, format: &str) -> Option<&mut Box<dyn Manager<'a, O, I>>> {
328 self.managers
329 .par_iter_mut()
330 .find_first(|m| m.format() == format)
331 }
332
333 //TODO: Add parallel version
334 /// Registers a plugin with the loader.
335 ///
336 /// This method registers a plugin from the specified path, using the appropriate
337 /// manager based on the plugin's format.
338 ///
339 /// # Parameters
340 ///
341 /// * `path` - Path to the plugin file or directory
342 ///
343 /// # Returns
344 ///
345 /// Returns `Result<Bundle, RegisterPluginError>` containing the plugin bundle on success.
346 pub fn register_plugin(&mut self, path: &str) -> Result<Bundle, RegisterPluginError> {
347 private_loader::register_plugin(self, path)
348 }
349
350 /// Forcefully registers a plugin, bypassing safety checks.
351 ///
352 /// This unsafe method allows registering a plugin without checking for duplicates.
353 /// Use with caution as it may lead to undefined behavior.
354 ///
355 /// # Parameters
356 ///
357 /// * `manager` - Reference to the manager that will handle this plugin
358 /// * `plugin_info` - Plugin information to register
359 ///
360 /// # Returns
361 ///
362 /// Returns `Result<Bundle, RegisterPluginError>` containing the plugin bundle on success.
363 ///
364 /// # Safety
365 ///
366 /// This method is unsafe because it bypasses duplicate checking that prevents
367 /// multiple plugins with the same ID and version from being registered.
368 pub unsafe fn forced_register_plugin(
369 &mut self,
370 manager: &mut Box<dyn Manager<'a, O, I>>,
371 plugin_info: PluginInfo<I>,
372 ) -> Result<Bundle, RegisterPluginError> {
373 private_loader::forced_register_plugin(&mut self.plugins, Ptr::new(manager), plugin_info)
374 }
375
376 /// Registers multiple plugins with the loader.
377 ///
378 /// This method registers multiple plugins from the specified paths in sequence.
379 ///
380 /// # Parameters
381 ///
382 /// * `paths` - Iterator of paths to plugin files or directories
383 ///
384 /// # Returns
385 ///
386 /// Returns `Result<Vec<Bundle>, RegisterPluginError>` containing the plugin bundles on success.
387 ///
388 /// # Type Parameters
389 ///
390 /// * `'b` - Lifetime of the path references
391 /// * `P` - Type of the iterator containing path references
392 pub fn register_plugins<'b, P>(&mut self, paths: P) -> Result<Vec<Bundle>, RegisterPluginError>
393 where
394 P: IntoIterator<Item = &'b str>,
395 {
396 paths
397 .into_iter()
398 .map(|path| private_loader::register_plugin(self, path))
399 .collect::<Result<Vec<_>, _>>()
400 }
401
402 /// Registers multiple plugins with the loader in parallel.
403 ///
404 /// This method registers multiple plugins from the specified paths concurrently.
405 ///
406 /// # Parameters
407 ///
408 /// * `paths` - Parallel iterator of paths to plugin files or directories
409 ///
410 /// # Returns
411 ///
412 /// Returns `Result<Vec<Bundle>, RegisterPluginError>` containing the plugin bundles on success.
413 ///
414 /// # Type Parameters
415 ///
416 /// * `'b` - Lifetime of the path references
417 /// * `P` - Type of the parallel iterator containing path references
418 pub fn par_register_plugins<'b, P>(
419 &mut self,
420 paths: P,
421 ) -> Result<Vec<Bundle>, RegisterPluginError>
422 where
423 P: IntoParallelIterator<Item = &'b str>,
424 {
425 let this = Ptr::new(self);
426
427 paths
428 .into_par_iter()
429 .map(move |path| private_loader::register_plugin(this.as_mut(), path))
430 .collect::<Result<Vec<_>, _>>()
431 }
432
433 /// Unregisters a plugin from the loader.
434 ///
435 /// This method removes a plugin from the loader by ID and version, first unloading it if necessary.
436 ///
437 /// # Parameters
438 ///
439 /// * `id` - Plugin identifier
440 /// * `version` - Plugin version
441 ///
442 /// # Returns
443 ///
444 /// Returns `Result<(), UnregisterPluginError>` indicating success or failure.
445 pub fn unregister_plugin(
446 &mut self,
447 id: &str,
448 version: &Version,
449 ) -> Result<(), UnregisterPluginError> {
450 let index = self
451 .plugins
452 .iter()
453 .position(|plugin| *plugin == (id, version))
454 .ok_or(UnregisterPluginError::NotFound)?;
455 private_loader::unregister_plugin(&mut self.plugins, index)
456 }
457
458 /// Unregisters a plugin from the loader by bundle.
459 ///
460 /// This method removes a plugin from the loader by bundle information, first unloading it if necessary.
461 ///
462 /// # Parameters
463 ///
464 /// * `bundle` - Plugin bundle information
465 ///
466 /// # Returns
467 ///
468 /// Returns `Result<(), UnregisterPluginError>` indicating success or failure.
469 pub fn unregister_plugin_by_bundle(
470 &mut self,
471 bundle: &Bundle,
472 ) -> Result<(), UnregisterPluginError> {
473 let index = self
474 .plugins
475 .iter()
476 .position(|plugin| *plugin == *bundle)
477 .ok_or(UnregisterPluginError::NotFound)?;
478 private_loader::unregister_plugin(&mut self.plugins, index)
479 }
480
481 /// Unregisters a plugin from the loader by bundle (parallel version).
482 ///
483 /// This method removes a plugin from the loader by bundle information using parallel processing,
484 /// first unloading it if necessary.
485 ///
486 /// # Parameters
487 ///
488 /// * `bundle` - Plugin bundle information
489 ///
490 /// # Returns
491 ///
492 /// Returns `Result<(), UnregisterPluginError>` indicating success or failure.
493 pub fn par_unregister_plugin_by_bundle(
494 &mut self,
495 bundle: &Bundle,
496 ) -> Result<(), UnregisterPluginError> {
497 let index = self
498 .plugins
499 .par_iter()
500 .position_first(|plugin| *plugin == *bundle)
501 .ok_or(UnregisterPluginError::NotFound)?;
502 private_loader::unregister_plugin(&mut self.plugins, index)
503 }
504
505 /// Forcefully unregisters a plugin, bypassing safety checks.
506 ///
507 /// This unsafe method allows unregistering a plugin without checking if it exists.
508 /// Use with caution as it may lead to undefined behavior.
509 ///
510 /// # Parameters
511 ///
512 /// * `index` - Index of the plugin to unregister
513 ///
514 /// # Returns
515 ///
516 /// Returns `Result<(), UnregisterPluginError>` indicating success or failure.
517 ///
518 /// # Safety
519 ///
520 /// This method is unsafe because it bypasses existence checks that prevent
521 /// accessing invalid memory or indices.
522 pub unsafe fn forced_unregister_plugin(
523 &mut self,
524 index: usize,
525 ) -> Result<(), UnregisterPluginError> {
526 private_loader::forced_unregister_plugin(&mut self.plugins, index)
527 }
528
529 /// Unloads a plugin from the execution environment.
530 ///
531 /// This method unloads a plugin by ID and version, making it unavailable for execution.
532 ///
533 /// # Parameters
534 ///
535 /// * `id` - Plugin identifier
536 /// * `version` - Plugin version
537 ///
538 /// # Returns
539 ///
540 /// Returns `Result<(), UnloadPluginError>` indicating success or failure.
541 pub fn unload_plugin(&mut self, id: &str, version: &Version) -> Result<(), UnloadPluginError> {
542 let index = self
543 .plugins
544 .iter()
545 .position(|plugin| *plugin == (id, version))
546 .ok_or(UnloadPluginError::NotFound)?;
547 private_loader::unload_plugin(&mut self.plugins, index)
548 }
549
550 /// Unloads a plugin from the execution environment (parallel version).
551 ///
552 /// This method unloads a plugin by ID and version using parallel processing.
553 ///
554 /// # Parameters
555 ///
556 /// * `id` - Plugin identifier
557 /// * `version` - Plugin version
558 ///
559 /// # Returns
560 ///
561 /// Returns `Result<(), UnloadPluginError>` indicating success or failure.
562 pub fn par_unload_plugin(
563 &mut self,
564 id: &str,
565 version: &Version,
566 ) -> Result<(), UnloadPluginError> {
567 let index = self
568 .plugins
569 .par_iter()
570 .position_first(|plugin| *plugin == (id, version))
571 .ok_or(UnloadPluginError::NotFound)?;
572 private_loader::unload_plugin(&mut self.plugins, index)
573 }
574
575 /// Unloads a plugin from the execution environment by bundle.
576 ///
577 /// This method unloads a plugin by bundle information, making it unavailable for execution.
578 ///
579 /// # Parameters
580 ///
581 /// * `bundle` - Plugin bundle information
582 ///
583 /// # Returns
584 ///
585 /// Returns `Result<(), UnloadPluginError>` indicating success or failure.
586 pub fn unload_plugin_by_bundle(&mut self, bundle: &Bundle) -> Result<(), UnloadPluginError> {
587 let index = self
588 .plugins
589 .iter()
590 .position(|plugin| *plugin == *bundle)
591 .ok_or(UnloadPluginError::NotFound)?;
592 private_loader::unload_plugin(&mut self.plugins, index)
593 }
594
595 /// Unloads a plugin from the execution environment by bundle (parallel version).
596 ///
597 /// This method unloads a plugin by bundle information using parallel processing.
598 ///
599 /// # Parameters
600 ///
601 /// * `bundle` - Plugin bundle information
602 ///
603 /// # Returns
604 ///
605 /// Returns `Result<(), UnloadPluginError>` indicating success or failure.
606 pub fn par_unload_plugin_by_bundle(
607 &mut self,
608 bundle: &Bundle,
609 ) -> Result<(), UnloadPluginError> {
610 let index = self
611 .plugins
612 .par_iter()
613 .position_first(|plugin| *plugin == *bundle)
614 .ok_or(UnloadPluginError::NotFound)?;
615 private_loader::unload_plugin(&mut self.plugins, index)
616 }
617
618 /// Forcefully unloads a plugin, bypassing safety checks.
619 ///
620 /// This unsafe method allows unloading a plugin without checking if it exists.
621 /// Use with caution as it may lead to undefined behavior.
622 ///
623 /// # Parameters
624 ///
625 /// * `index` - Index of the plugin to unload
626 ///
627 /// # Returns
628 ///
629 /// Returns `Result<(), UnloadPluginError>` indicating success or failure.
630 ///
631 /// # Safety
632 ///
633 /// This method is unsafe because it bypasses existence checks that prevent
634 /// accessing invalid memory or indices.
635 pub unsafe fn forced_unload_plugin(&mut self, index: usize) -> Result<(), UnloadPluginError> {
636 private_loader::forced_unload_plugin(&mut self.plugins, index)
637 }
638
639 /// Gets an immutable reference to a plugin by ID and version.
640 ///
641 /// Searches for a registered plugin matching the specified ID and version.
642 ///
643 /// # Parameters
644 ///
645 /// * `id` - Plugin identifier
646 /// * `version` - Plugin version
647 ///
648 /// # Returns
649 ///
650 /// Returns `Option<&Plugin<'a, O, I>>` containing the plugin if found.
651 pub fn get_plugin(&self, id: &str, version: &Version) -> Option<&Plugin<'a, O, I>> {
652 self.plugins.iter().find(|plugin| **plugin == (id, version))
653 }
654
655 /// Gets an immutable reference to a plugin by ID and version (parallel version).
656 ///
657 /// Searches for a registered plugin matching the specified ID and version using parallel processing.
658 ///
659 /// # Parameters
660 ///
661 /// * `id` - Plugin identifier
662 /// * `version` - Plugin version
663 ///
664 /// # Returns
665 ///
666 /// Returns `Option<&Plugin<'a, O, I>>` containing the plugin if found.
667 pub fn par_get_plugin(&self, id: &str, version: &Version) -> Option<&Plugin<'a, O, I>> {
668 self.plugins
669 .par_iter()
670 .find_first(|plugin| **plugin == (id, version))
671 }
672
673 /// Gets an immutable reference to a plugin by bundle.
674 ///
675 /// Searches for a registered plugin matching the specified bundle.
676 ///
677 /// # Parameters
678 ///
679 /// * `bundle` - Plugin bundle containing ID, version, and format
680 ///
681 /// # Returns
682 ///
683 /// Returns `Option<&Plugin<'a, O, I>>` containing the plugin if found.
684 pub fn get_plugin_by_bundle(&self, bundle: &Bundle) -> Option<&Plugin<'a, O, I>> {
685 self.plugins.iter().find(|plugin| *plugin == bundle)
686 }
687
688 /// Gets an immutable reference to a plugin by bundle (parallel version).
689 ///
690 /// Searches for a registered plugin matching the specified bundle using parallel processing.
691 ///
692 /// # Parameters
693 ///
694 /// * `bundle` - Plugin bundle containing ID, version, and format
695 ///
696 /// # Returns
697 ///
698 /// Returns `Option<&Plugin<'a, O, I>>` containing the plugin if found.
699 pub fn par_get_plugin_by_bundle(&self, bundle: &Bundle) -> Option<&Plugin<'a, O, I>> {
700 self.plugins
701 .par_iter()
702 .find_first(|plugin| *plugin == bundle)
703 }
704
705 /// Gets a mutable reference to a plugin by ID and version.
706 ///
707 /// This method searches for a registered plugin matching the specified ID and version.
708 ///
709 /// # Parameters
710 ///
711 /// * `id` - Plugin identifier
712 /// * `version` - Plugin version
713 ///
714 /// # Returns
715 ///
716 /// Returns `Option<&mut Plugin<'a, O, I>>` containing the plugin if found.
717 pub fn get_plugin_mut(&mut self, id: &str, version: &Version) -> Option<&mut Plugin<'a, O, I>> {
718 self.plugins
719 .iter_mut()
720 .find(|plugin| **plugin == (id, version))
721 }
722
723 /// Gets a mutable reference to a plugin by ID and version (parallel version).
724 ///
725 /// This method searches for a registered plugin matching the specified ID and version
726 /// using parallel processing.
727 ///
728 /// # Parameters
729 ///
730 /// * `id` - Plugin identifier
731 /// * `version` - Plugin version
732 ///
733 /// # Returns
734 ///
735 /// Returns `Option<&mut Plugin<'a, O, I>>` containing the plugin if found.
736 pub fn par_get_plugin_mut(
737 &mut self,
738 id: &str,
739 version: &Version,
740 ) -> Option<&mut Plugin<'a, O, I>> {
741 self.plugins
742 .par_iter_mut()
743 .find_first(|plugin| **plugin == (id, version))
744 }
745
746 /// Gets a mutable reference to a plugin by bundle.
747 ///
748 /// This method searches for a registered plugin matching the specified bundle.
749 ///
750 /// # Parameters
751 ///
752 /// * `bundle` - Plugin bundle containing ID, version, and format
753 ///
754 /// # Returns
755 ///
756 /// Returns `Option<&mut Plugin<'a, O, I>>` containing the plugin if found.
757 pub fn get_plugin_mut_by_bundle(&mut self, bundle: &Bundle) -> Option<&mut Plugin<'a, O, I>> {
758 self.plugins.iter_mut().find(|plugin| *plugin == bundle)
759 }
760
761 /// Gets a mutable reference to a plugin by bundle (parallel version).
762 ///
763 /// This method searches for a registered plugin matching the specified bundle
764 /// using parallel processing.
765 ///
766 /// # Parameters
767 ///
768 /// * `bundle` - Plugin bundle containing ID, version, and format
769 ///
770 /// # Returns
771 ///
772 /// Returns `Option<&mut Plugin<'a, O, I>>` containing the plugin if found.
773 pub fn par_get_plugin_mut_by_bundle(
774 &mut self,
775 bundle: &Bundle,
776 ) -> Option<&mut Plugin<'a, O, I>> {
777 self.plugins
778 .par_iter_mut()
779 .find_first(|plugin| *plugin == bundle)
780 }
781
782 /// Gets all plugins with the specified ID.
783 ///
784 /// Returns all versions of plugins matching the given ID.
785 ///
786 /// # Parameters
787 ///
788 /// * `id` - Plugin identifier to search for
789 ///
790 /// # Returns
791 ///
792 /// Returns `Vec<&Plugin<'a, O, I>>` containing all matching plugins.
793 pub fn get_plugins_by_id(&self, id: &str) -> Vec<&Plugin<'a, O, I>> {
794 self.plugins
795 .iter()
796 .filter(|plugin| plugin.info.bundle.id == id)
797 .collect()
798 }
799
800 /// Gets all plugins with the specified ID (parallel version).
801 ///
802 /// Returns all versions of plugins matching the given ID using parallel processing.
803 ///
804 /// # Parameters
805 ///
806 /// * `id` - Plugin identifier to search for
807 ///
808 /// # Returns
809 ///
810 /// Returns `Vec<&Plugin<'a, O, I>>` containing all matching plugins.
811 pub fn par_get_plugins_by_id(&self, id: &str) -> Vec<&Plugin<'a, O, I>> {
812 self.plugins
813 .par_iter()
814 .filter(|plugin| plugin.info.bundle.id == id)
815 .collect()
816 }
817
818 /// Gets mutable references to all plugins with the specified ID.
819 ///
820 /// Returns mutable references to all versions of plugins matching the given ID.
821 ///
822 /// # Parameters
823 ///
824 /// * `id` - Plugin identifier to search for
825 ///
826 /// # Returns
827 ///
828 /// Returns `Vec<&mut Plugin<'a, O, I>>` containing all matching plugins.
829 pub fn get_plugins_by_id_mut(&mut self, id: &str) -> Vec<&mut Plugin<'a, O, I>> {
830 self.plugins
831 .iter_mut()
832 .filter(|plugin| plugin.info.bundle.id == id)
833 .collect()
834 }
835
836 /// Gets mutable references to all plugins with the specified ID (parallel version).
837 ///
838 /// Returns mutable references to all versions of plugins matching the given ID using parallel processing.
839 ///
840 /// # Parameters
841 ///
842 /// * `id` - Plugin identifier to search for
843 ///
844 /// # Returns
845 ///
846 /// Returns `Vec<&mut Plugin<'a, O, I>>` containing all matching plugins.
847 pub fn par_get_plugins_by_id_mut(&mut self, id: &str) -> Vec<&mut Plugin<'a, O, I>> {
848 self.plugins
849 .par_iter_mut()
850 .filter(|plugin| plugin.info.bundle.id == id)
851 .collect()
852 }
853
854 //TODO: Add functions for tracking loading and unloading
855 // of managers or plugins
856
857 /// Gets a reference to all loaded plugins.
858 ///
859 /// Returns the complete list of plugins currently managed by the loader.
860 ///
861 /// # Returns
862 ///
863 /// Returns `&Vec<Plugin<'a, O, I>>` containing all loaded plugins.
864 pub const fn get_plugins(&self) -> &Vec<Plugin<'a, O, I>> {
865 &self.plugins
866 }
867
868 /// Gets a reference to the function registry.
869 ///
870 /// Returns the registry containing all functions available to plugins.
871 ///
872 /// # Returns
873 ///
874 /// Returns `&Registry<O>` containing the function registry.
875 pub const fn get_registry(&self) -> &Registry<O> {
876 &self.registry
877 }
878
879 /// Gets a reference to the function requests.
880 ///
881 /// Returns a set of queries that plugins implement for the host.
882 ///
883 /// # Returns
884 ///
885 /// Returns `&Requests` containing the function requests.
886 pub const fn get_requests(&self) -> &Requests {
887 &self.requests
888 }
889
890 /// Calls a function request across all eligible plugins.
891 ///
892 /// This method calls the specified function request on all plugins that have the highest
893 /// version for their ID (to avoid calling multiple versions of the same plugin).
894 ///
895 /// # Parameters
896 ///
897 /// * `name` - Name of the function request to call
898 /// * `args` - Arguments to pass to the function
899 ///
900 /// # Returns
901 ///
902 /// Returns `Result<Vec<O>, PluginCallRequestError>` containing results from all
903 /// eligible plugins that have the requested function.
904 pub fn call_request(
905 &self,
906 name: &str,
907 args: &[Variable],
908 ) -> Result<Vec<O>, PluginCallRequestError> {
909 self.plugins
910 .iter()
911 .filter_map(|plugin| {
912 let check_version = self.plugins.iter().find(|pl| {
913 pl.info.bundle.id == plugin.info.bundle.id
914 && pl.info.bundle.version > plugin.info.bundle.version
915 });
916
917 match check_version {
918 Some(_) => None,
919 None => Some(plugin.call_request(name, args)),
920 }
921 })
922 .collect()
923 }
924
925 /// Calls a function request across all eligible plugins (parallel version).
926 ///
927 /// This method calls the specified function request on all plugins that have the highest
928 /// version for their ID (to avoid calling multiple versions of the same plugin) using parallel processing.
929 ///
930 /// # Parameters
931 ///
932 /// * `name` - Name of the function request to call
933 /// * `args` - Arguments to pass to the function
934 ///
935 /// # Returns
936 ///
937 /// Returns `Result<Vec<O>, PluginCallRequestError>` containing results from all
938 /// eligible plugins that have the requested function.
939 pub fn par_call_request(
940 &self,
941 name: &str,
942 args: &[Variable],
943 ) -> Result<Vec<O>, PluginCallRequestError> {
944 let requests: Vec<_> = self
945 .plugins
946 .iter()
947 .filter_map(|plugin| {
948 let check_version = self.plugins.iter().find(|pl| {
949 pl.info.bundle.id == plugin.info.bundle.id
950 && pl.info.bundle.version > plugin.info.bundle.version
951 });
952
953 match check_version {
954 Some(_) => None,
955 None => Some(&plugin.requests),
956 }
957 })
958 .collect();
959
960 requests
961 .into_par_iter()
962 .map(|requests| {
963 requests
964 .par_iter()
965 .find_map_first(|request| match request.name() == name {
966 true => Some(request.call(args)),
967 false => None,
968 })
969 .ok_or(PluginCallRequestError::NotFound)
970 })
971 .collect()
972 }
973}
974
975impl<O: Send + Sync, I: Info> Loader<'static, O, I> {
976 /// Loads a plugin into the execution environment.
977 ///
978 /// This method loads a plugin by ID and version, making it available for execution.
979 ///
980 /// # Parameters
981 ///
982 /// * `id` - Plugin identifier
983 /// * `version` - Plugin version
984 ///
985 /// # Returns
986 ///
987 /// Returns `Result<(), LoadPluginError>` indicating success or failure.
988 pub fn load_plugin(&mut self, id: &str, version: &Version) -> Result<(), LoadPluginError> {
989 let index = self
990 .plugins
991 .iter()
992 .position(|plugin| *plugin == (id, version))
993 .ok_or(LoadPluginError::NotFound)?;
994 private_loader::load_plugin(self, index)
995 }
996
997 /// Loads a plugin into the execution environment (parallel version).
998 ///
999 /// This method loads a plugin by ID and version using parallel processing.
1000 ///
1001 /// # Parameters
1002 ///
1003 /// * `id` - Plugin identifier
1004 /// * `version` - Plugin version
1005 ///
1006 /// # Returns
1007 ///
1008 /// Returns `Result<(), LoadPluginError>` indicating success or failure.
1009 pub fn par_load_plugin(&mut self, id: &str, version: &Version) -> Result<(), LoadPluginError> {
1010 let index = self
1011 .plugins
1012 .par_iter()
1013 .position_first(|plugin| *plugin == (id, version))
1014 .ok_or(LoadPluginError::NotFound)?;
1015 private_loader::load_plugin(self, index)
1016 }
1017
1018 /// Loads a plugin into the execution environment by bundle.
1019 ///
1020 /// This method loads a plugin by bundle information, making it available for execution.
1021 ///
1022 /// # Parameters
1023 ///
1024 /// * `bundle` - Plugin bundle information
1025 ///
1026 /// # Returns
1027 ///
1028 /// Returns `Result<(), LoadPluginError>` indicating success or failure.
1029 pub fn load_plugin_by_bundle(&mut self, bundle: &Bundle) -> Result<(), LoadPluginError> {
1030 let index = self
1031 .plugins
1032 .iter()
1033 .position(|plugin| *plugin == *bundle)
1034 .ok_or(LoadPluginError::NotFound)?;
1035 private_loader::load_plugin(self, index)
1036 }
1037
1038 /// Loads a plugin into the execution environment by bundle (parallel version).
1039 ///
1040 /// This method loads a plugin by bundle information using parallel processing.
1041 ///
1042 /// # Parameters
1043 ///
1044 /// * `bundle` - Plugin bundle information
1045 ///
1046 /// # Returns
1047 ///
1048 /// Returns `Result<(), LoadPluginError>` indicating success or failure.
1049 pub fn par_load_plugin_by_bundle(&mut self, bundle: &Bundle) -> Result<(), LoadPluginError> {
1050 let index = self
1051 .plugins
1052 .par_iter()
1053 .position_first(|plugin| *plugin == *bundle)
1054 .ok_or(LoadPluginError::NotFound)?;
1055 private_loader::load_plugin(self, index)
1056 }
1057
1058 /// Forcefully loads a plugin, bypassing safety checks.
1059 ///
1060 /// This unsafe method allows loading a plugin without checking if it exists.
1061 /// Use with caution as it may lead to undefined behavior.
1062 ///
1063 /// # Parameters
1064 ///
1065 /// * `index` - Index of the plugin to load
1066 /// * `depends` - List of dependencies for this plugin
1067 ///
1068 /// # Returns
1069 ///
1070 /// Returns `Result<(), LoadPluginError>` indicating success or failure.
1071 ///
1072 /// # Safety
1073 ///
1074 /// This method is unsafe because it bypasses existence checks that prevent
1075 /// accessing invalid memory or indices.
1076 pub unsafe fn forced_load_plugin(
1077 &mut self,
1078 index: usize,
1079 depends: Vec<(Bundle, bool)>,
1080 ) -> Result<(), LoadPluginError> {
1081 private_loader::forced_load_plugin(self, index, depends)
1082 }
1083
1084 /// Loads a plugin immediately from the specified path.
1085 ///
1086 /// This convenience method registers and loads a plugin in a single operation.
1087 /// First registers the plugin, then loads it and all its dependencies.
1088 ///
1089 /// # Parameters
1090 ///
1091 /// * `path` - Path to the plugin file or directory
1092 ///
1093 /// # Returns
1094 ///
1095 /// Returns `Result<Bundle, PluginOperationError>`
1096 /// containing the plugin bundle on success, or an error from registration or loading.
1097 ///
1098 /// # Example
1099 ///
1100 /// ```rust,no_run
1101 /// use plux_rs::{Loader, StdInfo};
1102 ///
1103 /// let mut loader = Loader::<'_, (), StdInfo>::new();
1104 /// // Configure loader with managers...
1105 ///
1106 /// let bundle = match loader.load_plugin_now("my_plugin-v1.0.0.cst") {
1107 /// Ok(bundle) => bundle,
1108 /// Err(e) => return Err(e.into()),
1109 /// };
1110 ///
1111 /// println!("Loaded plugin: {}", bundle.id);
1112 /// # Ok::<(), Box<dyn std::error::Error>>(())
1113 /// ```
1114 pub fn load_plugin_now(
1115 &mut self,
1116 path: &str,
1117 ) -> Result<Bundle, crate::utils::PluginOperationError> {
1118 let bundle = private_loader::register_plugin(self, path)
1119 .map_err(|e| PluginOperationError::Registration(e))?;
1120
1121 self.load_plugin_by_bundle(&bundle)
1122 .map_err(|e| PluginOperationError::Loading(e))?;
1123
1124 Ok(bundle)
1125 }
1126
1127 /// Loads multiple plugins from the specified paths.
1128 ///
1129 /// This method registers and loads multiple plugins in sequence.
1130 ///
1131 /// # Parameters
1132 ///
1133 /// * `paths` - Iterator of paths to plugin files or directories
1134 ///
1135 /// # Returns
1136 ///
1137 /// Returns `Result<Vec<Bundle>, PluginOperationError>`
1138 /// containing the plugin bundles on success, or errors from registration or loading.
1139 ///
1140 /// # Type Parameters
1141 ///
1142 /// * `'b` - Lifetime of the path references
1143 /// * `P` - Type of the iterator containing path references
1144 pub fn load_plugins<'b, P>(&mut self, paths: P) -> Result<Vec<Bundle>, PluginOperationError>
1145 where
1146 P: IntoIterator<Item = &'b str>,
1147 {
1148 let bundles = self
1149 .register_plugins(paths)
1150 .map_err(|e| PluginOperationError::Registration(e))?;
1151
1152 // Find plugins that are not dependencies of other plugins
1153 let result: Vec<_> = self
1154 .plugins
1155 .iter()
1156 .enumerate()
1157 .filter_map(|(index, plugin)| {
1158 let find_plugin = self.plugins.iter().find(|pl| {
1159 pl.info
1160 .info
1161 .depends()
1162 .iter()
1163 .chain(pl.info.info.optional_depends().iter())
1164 .any(|d| {
1165 *d == plugin.info.bundle
1166 && self
1167 .plugins
1168 .iter()
1169 .find(|p| {
1170 d.version.matches(&p.info.bundle.version)
1171 && p.info.bundle.version > plugin.info.bundle.version
1172 })
1173 .is_none()
1174 })
1175 });
1176
1177 match find_plugin {
1178 Some(_) => None,
1179 None => Some(index),
1180 }
1181 })
1182 .collect();
1183
1184 result.into_iter().try_for_each(|index| {
1185 private_loader::load_plugin(self, index).map_err(|e| PluginOperationError::Loading(e))
1186 })?;
1187
1188 Ok(bundles)
1189 }
1190
1191 /// Loads multiple plugins from the specified paths (parallel version).
1192 ///
1193 /// This method registers and loads multiple plugins concurrently using parallel processing.
1194 ///
1195 /// # Parameters
1196 ///
1197 /// * `paths` - Parallel iterator of paths to plugin files or directories
1198 ///
1199 /// # Returns
1200 ///
1201 /// Returns `Result<Vec<Bundle>, PluginOperationError>`
1202 /// containing the plugin bundles on success, or errors from registration or loading.
1203 ///
1204 /// # Type Parameters
1205 ///
1206 /// * `'b` - Lifetime of the path references
1207 /// * `P` - Type of the parallel iterator containing path references
1208 pub fn par_load_plugins<'b, P>(&mut self, paths: P) -> Result<Vec<Bundle>, PluginOperationError>
1209 where
1210 P: IntoParallelIterator<Item = &'b str>,
1211 {
1212 let bundles = self
1213 .par_register_plugins(paths)
1214 .map_err(|e| PluginOperationError::Registration(e))?;
1215
1216 // Find plugins that are not dependencies of other plugins
1217 let result: Vec<_> = self
1218 .plugins
1219 .par_iter()
1220 .enumerate()
1221 .filter_map(|(index, plugin)| {
1222 let find_plugin = self.plugins.iter().find(|pl| {
1223 pl.info
1224 .info
1225 .depends()
1226 .iter()
1227 .chain(pl.info.info.optional_depends().iter())
1228 .any(|d| {
1229 *d == plugin.info.bundle
1230 && self
1231 .plugins
1232 .iter()
1233 .find(|p| {
1234 d.version.matches(&p.info.bundle.version)
1235 && p.info.bundle.version > plugin.info.bundle.version
1236 })
1237 .is_none()
1238 })
1239 });
1240
1241 match find_plugin {
1242 Some(_) => None,
1243 None => Some(index),
1244 }
1245 })
1246 .collect();
1247
1248 let this = Ptr::new(self);
1249 result.into_par_iter().try_for_each(move |index| {
1250 private_loader::load_plugin(this.as_mut(), index)
1251 .map_err(|e| PluginOperationError::Loading(e))
1252 })?;
1253
1254 Ok(bundles)
1255 }
1256
1257 /// Loads only the plugins that are used (not dependencies of other plugins).
1258 ///
1259 /// This method registers and loads only the plugins that are not dependencies of other plugins,
1260 /// and automatically unregisters unused plugins.
1261 ///
1262 /// # Parameters
1263 ///
1264 /// * `paths` - Iterator of paths to plugin files or directories
1265 ///
1266 /// # Returns
1267 ///
1268 /// Returns `Result<Vec<Bundle>, PluginOperationError>`
1269 /// containing the plugin bundles on success, or errors from registration, unregistration, or loading.
1270 ///
1271 /// # Type Parameters
1272 ///
1273 /// * `'b` - Lifetime of the path references
1274 /// * `P` - Type of the iterator containing path references
1275 pub fn load_only_used_plugins<'b, P>(
1276 &mut self,
1277 paths: P,
1278 ) -> Result<Vec<Bundle>, PluginOperationError>
1279 where
1280 P: IntoIterator<Item = &'b str>,
1281 {
1282 let mut bundles = self
1283 .register_plugins(paths)
1284 .map_err(|e| PluginOperationError::Registration(e))?;
1285
1286 // Find plugins that are not dependencies of other plugins
1287 let (used, unused): (Vec<_>, Vec<_>) = self
1288 .plugins
1289 .iter()
1290 .enumerate()
1291 .filter_map(|(index, plugin)| {
1292 let find_plugin = self.plugins.iter().find(|pl| {
1293 pl.info
1294 .info
1295 .depends()
1296 .iter()
1297 .chain(pl.info.info.optional_depends().iter())
1298 .any(|d| {
1299 *d == plugin.info.bundle
1300 && self
1301 .plugins
1302 .iter()
1303 .find(|p| {
1304 d.version.matches(&p.info.bundle.version)
1305 && p.info.bundle.version > plugin.info.bundle.version
1306 })
1307 .is_none()
1308 })
1309 });
1310
1311 match find_plugin {
1312 Some(_) => None,
1313 None => Some(index),
1314 }
1315 })
1316 .partition(|index| {
1317 let bundle = &self.plugins[*index].info.bundle;
1318
1319 // Find the highest version
1320 self.plugins
1321 .iter()
1322 .find(|pl| {
1323 pl.info.bundle.id == bundle.id && pl.info.bundle.version > bundle.version
1324 })
1325 .is_none()
1326 });
1327
1328 used.into_iter().try_for_each(|index| {
1329 private_loader::load_plugin(self, index).map_err(|e| PluginOperationError::Loading(e))
1330 })?;
1331
1332 let mut old_indexs = vec![];
1333 let mut unused = unused.into_iter();
1334
1335 while let Some(index) = unused.next() {
1336 let swap = old_indexs
1337 .iter()
1338 .fold(0, |acc, i| if index > *i { acc + 1 } else { acc });
1339
1340 let new_index = index - swap;
1341
1342 let bundle = &self.plugins[new_index].info.bundle;
1343 bundles.retain(|b| *b != *bundle);
1344
1345 private_loader::unregister_plugin(&mut self.plugins, new_index)
1346 .map_err(|e| PluginOperationError::Unregistration(e))?;
1347
1348 old_indexs.push(index);
1349 }
1350
1351 Ok(bundles)
1352 }
1353
1354 /// Loads only the plugins that are used (not dependencies of other plugins) (parallel version).
1355 ///
1356 /// This method registers and loads only the plugins that are not dependencies of other plugins
1357 /// using parallel processing, and automatically unregisters unused plugins.
1358 ///
1359 /// # Parameters
1360 ///
1361 /// * `paths` - Parallel iterator of paths to plugin files or directories
1362 ///
1363 /// # Returns
1364 ///
1365 /// Returns `Result<Vec<Bundle>, PluginOperationError>`
1366 /// containing the plugin bundles on success, or errors from registration, unregistration, or loading.
1367 ///
1368 /// # Type Parameters
1369 ///
1370 /// * `'b` - Lifetime of the path references
1371 /// * `P` - Type of the parallel iterator containing path references
1372 pub fn par_load_only_used_plugins<'b, P>(
1373 &mut self,
1374 paths: P,
1375 ) -> Result<Vec<Bundle>, PluginOperationError>
1376 where
1377 P: IntoParallelIterator<Item = &'b str>,
1378 {
1379 let bundles = self
1380 .par_register_plugins(paths)
1381 .map_err(|e| PluginOperationError::Registration(e))?;
1382
1383 // Find plugins that are not dependencies of other plugins
1384 let (used, unused): (Vec<_>, Vec<_>) = self
1385 .plugins
1386 .iter()
1387 .enumerate()
1388 .filter_map(|(index, plugin)| {
1389 let find_plugin = self.plugins.iter().find(|pl| {
1390 pl.info
1391 .info
1392 .depends()
1393 .iter()
1394 .chain(pl.info.info.optional_depends().iter())
1395 .any(|d| {
1396 *d == plugin.info.bundle
1397 && self
1398 .plugins
1399 .iter()
1400 .find(|p| {
1401 d.version.matches(&p.info.bundle.version)
1402 && p.info.bundle.version > plugin.info.bundle.version
1403 })
1404 .is_none()
1405 })
1406 });
1407
1408 match find_plugin {
1409 Some(_) => None,
1410 None => Some(index),
1411 }
1412 })
1413 .partition(|index| {
1414 let bundle = &self.plugins[*index].info.bundle;
1415
1416 // Find the highest version
1417 self.plugins
1418 .iter()
1419 .find(|pl| {
1420 pl.info.bundle.id == bundle.id && pl.info.bundle.version > bundle.version
1421 })
1422 .is_none()
1423 });
1424
1425 let this = Ptr::new(self);
1426 used.into_iter().try_for_each(|index| {
1427 private_loader::load_plugin(this.as_mut(), index)
1428 .map_err(|e| PluginOperationError::Loading(e))
1429 })?;
1430
1431 let mut old_indexs = vec![];
1432 let mut unused = unused.into_iter();
1433
1434 while let Some(index) = unused.next() {
1435 let swap = old_indexs
1436 .iter()
1437 .fold(0, |acc, i| if index > *i { acc + 1 } else { acc });
1438
1439 private_loader::unregister_plugin(&mut this.as_mut().plugins, index - swap)
1440 .map_err(|e| PluginOperationError::Unregistration(e))?;
1441
1442 old_indexs.push(index);
1443 }
1444
1445 Ok(bundles)
1446 }
1447}
1448
1449impl<O: Send + Sync, I: Info> Drop for Loader<'_, O, I> {
1450 fn drop(&mut self) {
1451 self.stop().unwrap();
1452 }
1453}
1454
1455mod private_loader {
1456 use std::path::Path;
1457
1458 use crate::{
1459 Api, Bundle, Depend, Info, LoadPluginContext, Manager, Plugin, PluginInfo,
1460 RegisterPluginContext,
1461 utils::{
1462 LoadPluginError, Ptr, RegisterManagerError, RegisterPluginError, StopLoaderError,
1463 UnloadPluginError, UnregisterManagerError, UnregisterPluginError,
1464 },
1465 };
1466
1467 pub fn stop_plugins<O: Send + Sync, I: Info>(
1468 loader: &mut super::Loader<'_, O, I>,
1469 ) -> Result<(), StopLoaderError> {
1470 // Sort plugins in order of their dependencies
1471 let sort_plugins = sort_plugins(
1472 &loader.plugins,
1473 loader
1474 .plugins
1475 .iter()
1476 .enumerate()
1477 .map(|(index, _)| index)
1478 .collect(),
1479 );
1480
1481 // Unload plugins
1482 let errors = sort_plugins
1483 .iter()
1484 .map(|index| {
1485 forced_unload_plugin(&mut loader.plugins, index.clone())
1486 .map_err(|e| UnregisterPluginError::UnloadError(e))
1487 })
1488 .partition::<Vec<_>, _>(|r| r.is_err())
1489 .0;
1490
1491 if !errors.is_empty() {
1492 return Err(StopLoaderError::UnregisterPluginFailed(
1493 errors.into_iter().map(|r| r.err().unwrap()).collect(),
1494 ));
1495 }
1496
1497 //TODO: Add debug output
1498 let errors = (0..loader.plugins.len())
1499 .map(|_| forced_unregister_plugin(&mut loader.plugins, 0_usize))
1500 .partition::<Vec<_>, _>(|r| r.is_err())
1501 .0;
1502
1503 match !errors.is_empty() {
1504 true => Err(StopLoaderError::UnregisterPluginFailed(
1505 errors.into_iter().map(|r| r.err().unwrap()).collect(),
1506 )),
1507 false => Ok(()),
1508 }
1509 }
1510
1511 pub fn stop_managers<'a, O: Send + Sync, I: Info>(
1512 loader: &'a mut super::Loader<'_, O, I>,
1513 ) -> Result<(), StopLoaderError> {
1514 // Detach plugin managers from the loader
1515 let mut errors = vec![];
1516 while !loader.managers.is_empty() {
1517 if let Err(e) = forced_unregister_manager(&mut loader.managers, 0_usize) {
1518 errors.push(e);
1519 }
1520 }
1521
1522 match !errors.is_empty() {
1523 true => Err(StopLoaderError::UnregisterManagerFailed(errors)),
1524 false => Ok(()),
1525 }
1526 }
1527
1528 /*
1529 TODO: Change plugin sorting.
1530 The function arguments must pass a list of all plugins
1531 and an optional set of plugin indexes for targeted sorting.
1532 The output should provide the index of the beginning of sorted plugins.
1533
1534 Mechanics of sorting consists in shifting to the end of the plugin list
1535 while sorting them.
1536 */
1537 // pub fn sort_plugins<'a, O: Send + Sync, I: Info>(
1538 // plugins: &mut Vec<Plugin<'a, O, I>>,
1539 // plugins_set: Option<Vec<usize>>,
1540 // ) -> usize
1541
1542 // Advanced tree sorting
1543 pub fn sort_plugins<'a, O: Send + Sync, I: Info>(
1544 plugins: &Vec<Plugin<'a, O, I>>,
1545 plugins_set: Vec<usize>,
1546 ) -> Vec<usize> {
1547 let mut result = vec![];
1548
1549 'outer: for index in plugins_set.iter() {
1550 let bundle = &plugins[*index].info.bundle;
1551
1552 let find_plugin = plugins.iter().enumerate().find_map(|(i, pl)| {
1553 pl.info
1554 .info
1555 .depends()
1556 .iter()
1557 .chain(pl.info.info.optional_depends().iter())
1558 .any(|d| {
1559 *d == *bundle
1560 && plugins
1561 .iter()
1562 .find(|p| {
1563 d.version.matches(&p.info.bundle.version)
1564 && p.info.bundle.version > bundle.version
1565 })
1566 .is_none()
1567 })
1568 .then_some(i)
1569 });
1570
1571 if find_plugin.is_some()
1572 && plugins_set
1573 .iter()
1574 .find(|i| **i == find_plugin.unwrap())
1575 .is_some()
1576 {
1577 continue 'outer;
1578 }
1579
1580 sort_pick(plugins, &plugins_set, index, &mut result);
1581 }
1582
1583 result
1584 }
1585
1586 pub fn sort_pick<'a, O: Send + Sync, I: Info>(
1587 plugins: &Vec<Plugin<'a, O, I>>,
1588 plugins_set: &Vec<usize>,
1589 index: &usize,
1590 result: &mut Vec<usize>,
1591 ) {
1592 result.push(index.clone());
1593
1594 let plugin_info = &plugins[*index].info;
1595 let depends = plugin_info
1596 .info
1597 .depends()
1598 .iter()
1599 .chain(plugin_info.info.optional_depends().iter());
1600 'outer: for depend in depends {
1601 if !result.iter().any(|inx| {
1602 *depend == plugins[*inx].info.bundle
1603 && plugins
1604 .iter()
1605 .find(|p| {
1606 depend.version.matches(&p.info.bundle.version)
1607 && p.info.bundle.version > plugins[*inx].info.bundle.version
1608 })
1609 .is_none()
1610 }) {
1611 let mut plugin = None;
1612
1613 for index in plugins_set.iter() {
1614 let plug_info = &plugins[*index].info;
1615 if *depend == plug_info.bundle
1616 && plugins
1617 .iter()
1618 .find(|p| {
1619 depend.version.matches(&p.info.bundle.version)
1620 && p.info.bundle.version > plug_info.bundle.version
1621 })
1622 .is_none()
1623 {
1624 plugin = Some(index);
1625 continue;
1626 }
1627
1628 if !result
1629 .iter()
1630 .any(|inx| plugins[*inx].info.bundle == plug_info.bundle)
1631 && (plug_info.info.depends().contains(depend)
1632 || plug_info.info.optional_depends().contains(depend))
1633 {
1634 continue 'outer;
1635 }
1636 }
1637
1638 if let Some(index) = plugin {
1639 sort_pick(plugins, plugins_set, index, result);
1640 }
1641 }
1642 }
1643 }
1644
1645 pub fn forced_register_manager<'a, O: Send + Sync, I: Info>(
1646 loader: &mut super::Loader<'a, O, I>,
1647 mut manager: Box<dyn Manager<'a, O, I>>,
1648 ) -> Result<(), RegisterManagerError> {
1649 manager.as_mut().register_manager()?;
1650 loader.managers.push(manager);
1651 Ok(())
1652 }
1653
1654 pub fn register_manager<'a, O: Send + Sync, I: Info>(
1655 loader: &mut super::Loader<'a, O, I>,
1656 manager: Box<dyn Manager<'a, O, I>>,
1657 ) -> Result<(), RegisterManagerError> {
1658 if let Some(_) = loader.managers.iter().find(|m| manager == **m) {
1659 return Err(RegisterManagerError::AlreadyOccupiedFormat(
1660 manager.format().to_string(),
1661 ));
1662 }
1663
1664 forced_register_manager(loader, manager)
1665 }
1666
1667 pub fn forced_unregister_manager<O: Send + Sync, I: Info>(
1668 managers: &mut Vec<Box<dyn Manager<'_, O, I>>>,
1669 index: usize,
1670 ) -> Result<(), UnregisterManagerError> {
1671 match managers.remove(index).unregister_manager() {
1672 Ok(_) => Ok(()),
1673 Err(e) => Err(UnregisterManagerError::UnregisterManagerByManager(e)),
1674 }
1675 }
1676
1677 pub fn unregister_manager<O: Send + Sync, I: Info>(
1678 loader: &mut super::Loader<'_, O, I>,
1679 index: usize,
1680 ) -> Result<(), UnregisterManagerError> {
1681 let manager = &loader.managers[index];
1682
1683 // Get all plugins related to the manager
1684 let plugins_from_manager = loader
1685 .plugins
1686 .iter()
1687 .enumerate()
1688 .filter_map(
1689 |(index, plugin)| match *plugin.manager.as_ref() == *manager {
1690 true => Some(index),
1691 false => None,
1692 },
1693 )
1694 .collect();
1695
1696 // Sort manager plugins in order of their dependencies
1697 let sort_plugins = sort_plugins(&loader.plugins, plugins_from_manager);
1698
1699 // Unload plugins
1700 for index in sort_plugins.iter() {
1701 unload_plugin(&mut loader.plugins, index.clone()).map_err(|e| {
1702 UnregisterManagerError::UnregisterPlugin(UnregisterPluginError::UnloadError(e))
1703 })?;
1704 }
1705
1706 let mut old_indexs = vec![];
1707 let mut sort_plugins = sort_plugins.into_iter();
1708
1709 while let Some(index) = sort_plugins.next() {
1710 let swap = old_indexs
1711 .iter()
1712 .fold(0, |acc, i| if index > *i { acc + 1 } else { acc });
1713
1714 forced_unregister_plugin(&mut loader.plugins, index - swap)
1715 .map_err(|e| UnregisterManagerError::UnregisterPlugin(e))?;
1716
1717 old_indexs.push(index);
1718 }
1719
1720 // Unload manager
1721 forced_unregister_manager(&mut loader.managers, index)
1722 }
1723
1724 pub fn forced_register_plugin<'a, O: Send + Sync, I: Info>(
1725 plugins: &mut Vec<Plugin<'a, O, I>>,
1726 manager: Ptr<'a, Box<dyn Manager<'a, O, I>>>,
1727 plugin_info: PluginInfo<I>,
1728 ) -> Result<Bundle, RegisterPluginError> {
1729 let bundle = plugin_info.bundle.clone();
1730 plugins.push(Plugin::<'a>::new(manager, plugin_info));
1731 Ok(bundle)
1732 }
1733
1734 pub fn register_plugin<'a, O: Send + Sync, I: Info>(
1735 loader: &mut super::Loader<'a, O, I>,
1736 path: &str,
1737 ) -> Result<Bundle, RegisterPluginError> {
1738 let path = Path::new(path).to_path_buf();
1739
1740 if !path.is_dir() {
1741 return Err(RegisterPluginError::NotFound);
1742 }
1743
1744 if let None = path.extension() {
1745 return Err(RegisterPluginError::UnknownManagerFormat("".to_string()));
1746 }
1747
1748 let bundle = Bundle::from_filename(path.file_name().unwrap())?;
1749
1750 // Check if such a plugin already exists
1751 if loader.get_plugin_by_bundle(&bundle).is_some() {
1752 return Err(RegisterPluginError::AlreadyExistsIDAndVersion(
1753 bundle.id.clone(),
1754 bundle.version.clone(),
1755 ));
1756 }
1757
1758 // Looking for a suitable manager
1759 let plugin_format = bundle.format.clone();
1760 let manager = loader
1761 .get_manager_mut(plugin_format.as_str())
1762 .ok_or(RegisterPluginError::UnknownManagerFormat(plugin_format))?;
1763
1764 // Manager registers plugin
1765 let info = manager.register_plugin(RegisterPluginContext {
1766 path: &path,
1767 bundle: &bundle,
1768 })?;
1769 let plugin_info = PluginInfo { path, bundle, info };
1770
1771 // Register plugin
1772 let manager = Ptr::<'a>::new(manager);
1773 forced_register_plugin(&mut loader.plugins, manager, plugin_info)
1774 }
1775
1776 pub fn forced_unregister_plugin<O: Send + Sync, I: Info>(
1777 plugins: &mut Vec<Plugin<'_, O, I>>,
1778 index: usize,
1779 ) -> Result<(), UnregisterPluginError> {
1780 let plugin = plugins.remove(index);
1781 plugin.manager.as_mut().unregister_plugin(&plugin)?;
1782 Ok(())
1783 }
1784
1785 pub fn unregister_plugin<'a, O: Send + Sync, I: Info>(
1786 plugins: &mut Vec<Plugin<'_, O, I>>,
1787 index: usize,
1788 ) -> Result<(), UnregisterPluginError> {
1789 unload_plugin(plugins, index)?;
1790 forced_unregister_plugin(plugins, index)
1791 }
1792
1793 pub fn forced_load_plugin<O: Send + Sync, I: Info>(
1794 loader: *mut super::Loader<'static, O, I>,
1795 index: usize,
1796 depends: Vec<(Bundle, bool)>,
1797 ) -> Result<(), LoadPluginError> {
1798 let manager = Ptr::new(unsafe { &*loader }.plugins[index].manager.as_ptr());
1799
1800 // Get plugin and its dependencies
1801 let plugin = &mut unsafe { &mut *loader }.plugins[index];
1802
1803 // Split dependencies
1804 let mut deps = vec![];
1805 let mut opt_deps = vec![];
1806
1807 for (bundle, is_depend) in depends {
1808 match is_depend {
1809 true => deps.push(bundle),
1810 false => opt_deps.push(bundle),
1811 }
1812 }
1813
1814 // Load plugin
1815 let bundle = plugin.info.bundle.clone();
1816
1817 manager.as_mut().load_plugin(
1818 LoadPluginContext::new(plugin, &unsafe { &*loader }.requests),
1819 Api::new(Ptr::new(loader), bundle, deps, opt_deps),
1820 )?;
1821
1822 plugin.is_load = true;
1823
1824 Ok(())
1825 }
1826
1827 fn load_depends<'a, O, I, IT>(
1828 loader: &'a mut super::Loader<'static, O, I>,
1829 depends_iter: IT,
1830 ) -> Result<(Vec<(Bundle, bool)>, Vec<Depend>), LoadPluginError>
1831 where
1832 O: Send + Sync,
1833 I: Info,
1834 IT: IntoIterator<Item = (bool, Depend)>,
1835 {
1836 let mut found_depends = vec![];
1837 let mut not_found_depends = vec![];
1838
1839 for (is_depend, depend) in depends_iter.into_iter() {
1840 if let Some((index, plugin)) = loader.plugins.iter().enumerate().find(|(_, plugin)| {
1841 depend == plugin.info.bundle
1842 && loader
1843 .plugins
1844 .iter()
1845 .find(|p| {
1846 depend.version.matches(&p.info.bundle.version)
1847 && p.info.bundle.version > plugin.info.bundle.version
1848 })
1849 .is_none()
1850 }) {
1851 found_depends.push((plugin.info.bundle.clone(), is_depend));
1852 load_plugin(loader, index).map_err(|e| LoadPluginError::LoadDependency {
1853 depend: depend,
1854 error: Box::new(e),
1855 })?;
1856 } else if is_depend {
1857 not_found_depends.push(depend);
1858 }
1859 }
1860 Ok((found_depends, not_found_depends))
1861 }
1862
1863 fn check_requests<O: Send + Sync, I: Info>(
1864 loader: &mut super::Loader<'static, O, I>,
1865 index: usize,
1866 ) -> Vec<String> {
1867 let mut plugin_requests = loader.plugins[index].requests.iter();
1868 loader
1869 .requests
1870 .iter()
1871 .filter_map(|req| match plugin_requests.any(|r| r.name() == req.name) {
1872 true => None,
1873 false => Some(req.name.clone()),
1874 })
1875 .collect()
1876 }
1877
1878 pub fn load_plugin<O: Send + Sync, I: Info>(
1879 loader: &mut super::Loader<'static, O, I>,
1880 index: usize,
1881 ) -> Result<(), LoadPluginError> {
1882 if loader.plugins[index].is_load {
1883 return Ok(());
1884 }
1885
1886 // Load dependencies
1887 let info = &loader.plugins[index].info;
1888 let depends_iter = info
1889 .info
1890 .depends()
1891 .clone()
1892 .into_iter()
1893 .map(|d| (true, d))
1894 .chain(
1895 info.info
1896 .optional_depends()
1897 .clone()
1898 .into_iter()
1899 .map(|d| (false, d)),
1900 );
1901 let (found_depends, not_found_depends) = load_depends(loader, depends_iter)?;
1902
1903 if !not_found_depends.is_empty() {
1904 return Err(LoadPluginError::NotFoundDependencies(not_found_depends));
1905 }
1906
1907 // Load plugin
1908 forced_load_plugin(loader, index, found_depends)?;
1909
1910 // Check for requested functions
1911 let not_found_requests = check_requests(loader, index);
1912
1913 if !not_found_requests.is_empty() {
1914 loader.plugins[index].is_load = false;
1915 return Err(LoadPluginError::RequestsNotFound(not_found_requests));
1916 }
1917
1918 Ok(())
1919 }
1920
1921 pub fn forced_unload_plugin<O: Send + Sync, I: Info>(
1922 plugins: &mut Vec<Plugin<'_, O, I>>,
1923 index: usize,
1924 ) -> Result<(), UnloadPluginError> {
1925 if plugins[index].is_load {
1926 plugins[index]
1927 .manager
1928 .as_mut()
1929 .unload_plugin(&plugins[index])?;
1930 }
1931
1932 plugins[index].is_load = false;
1933
1934 Ok(())
1935 }
1936
1937 pub fn unload_plugin<'a, O: Send + Sync, I: Info>(
1938 plugins: &mut Vec<Plugin<'_, O, I>>,
1939 index: usize,
1940 ) -> Result<(), UnloadPluginError> {
1941 if plugins[index].is_load {
1942 let bundle = &plugins[index].info.bundle;
1943
1944 // Check that the plugin is not used as a dependency by loaded plugins
1945 plugins.iter().try_for_each(|plug| {
1946 let plug_info = &plug.info;
1947
1948 let find_depend = plug_info
1949 .info
1950 .depends()
1951 .iter()
1952 .chain(plug_info.info.optional_depends().iter())
1953 .find(|depend| {
1954 **depend == *bundle
1955 && plugins
1956 .iter()
1957 .find(|p| {
1958 depend.version.matches(&p.info.bundle.version)
1959 && p.info.bundle.version > bundle.version
1960 })
1961 .is_none()
1962 })
1963 .is_some();
1964 match plug.is_load && find_depend {
1965 true => Err(UnloadPluginError::CurrentlyUsesDepend {
1966 plugin: plug_info.bundle.clone(),
1967 depend: bundle.clone(),
1968 }),
1969 false => Ok(()),
1970 }
1971 })?;
1972 }
1973
1974 forced_unload_plugin(plugins, index)
1975 }
1976}