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}