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