plux_rs/context/
load_plugin_context.rs

1use crate::{Info, Plugin, Requests, function::Function, utils::RegisterRequestError};
2
3/// Context provided during plugin loading.
4///
5/// LoadPluginContext gives plugin managers access to the plugin being loaded and
6/// the system's function requests. It allows managers to register plugin functions
7/// and validate them against the expected interface.
8///
9/// # Type Parameters
10///
11/// * `'a` - Lifetime for references within the plugin
12/// * `'b` - Lifetime of the context references
13/// * `O` - Output type for plugin functions (must implement Send + Sync)
14/// * `I` - Plugin information type (must implement Info trait)
15///
16/// # Fields
17///
18/// * `plugin` - Mutable reference to the plugin being loaded
19/// * `requests` - Reference to the system's function requests
20///
21/// # Example
22///
23/// ```rust,no_run
24/// use plux_rs::{Manager, utils::ManagerResult, LoadPluginContext, RegisterPluginContext, Api, StdInfo};
25///
26/// struct MyManager;
27///
28/// impl Manager<'_, (), StdInfo> for MyManager {
29///     fn format(&self) -> &'static str { "my" }
30/// 
31///     fn register_plugin(&mut self, _context: RegisterPluginContext) -> ManagerResult<StdInfo> {
32///         Ok(StdInfo::new())
33///     }
34///
35///     fn load_plugin(
36///         &mut self,
37///         context: LoadPluginContext<'_, '_, (), StdInfo>,
38///         api: Api<(), StdInfo>
39///     ) -> ManagerResult<()> {
40///         // Register plugin functions that match the requests
41///         for request in context.requests() {
42///             // Register corresponding function in the plugin
43///         }
44///         Ok(())
45///     }
46/// }
47/// ```
48pub struct LoadPluginContext<'a, 'b, O: Send + Sync, I: Info> {
49    plugin: &'b mut Plugin<'a, O, I>,
50    requests: &'b Requests,
51}
52
53impl<'a, 'b, O: Send + Sync, I: Info> LoadPluginContext<'a, 'b, O, I> {
54    /// Creates a new load plugin context.
55    ///
56    /// This is an internal constructor used by the loader when loading plugins.
57    ///
58    /// # Parameters
59    ///
60    /// * `plugin` - Mutable reference to the plugin being loaded
61    /// * `requests` - Reference to the system's function requests
62    ///
63    /// # Returns
64    ///
65    /// Returns a new LoadPluginContext instance.
66    pub(crate) fn new(plugin: &'b mut Plugin<'a, O, I>, requests: &'b Requests) -> Self {
67        Self { plugin, requests }
68    }
69
70    /// Gets a reference to the plugin being loaded.
71    ///
72    /// # Returns
73    ///
74    /// Returns an immutable reference to the plugin.
75    pub const fn plugin(&'b self) -> &'b Plugin<'a, O, I> {
76        self.plugin
77    }
78
79    /// Gets a reference to the system's function requests.
80    ///
81    /// # Returns
82    ///
83    /// Returns a reference to the requests that plugins should implement.
84    pub const fn requests(&self) -> &'b Requests {
85        self.requests
86    }
87
88    /// Registers a function that implements a system request.
89    ///
90    /// This method validates that the provided function matches the signature of
91    /// a registered system request and then registers it with the plugin.
92    ///
93    /// # Parameters
94    ///
95    /// * `request` - The function that implements a system request
96    ///
97    /// # Returns
98    ///
99    /// Returns `Result<(), RegisterRequestError>` indicating success or failure.
100    /// Fails if the function doesn't match any registered request or has incorrect arguments.
101    ///
102    /// # Type Parameters
103    ///
104    /// * `F` - Type of the function (must implement Function trait)
105    pub fn register_request<F>(&mut self, request: F) -> Result<(), RegisterRequestError>
106    where
107        F: Function<Output = O> + 'static,
108    {
109        if let Some(req) = self.requests.iter().find(|req| *req.name == request.name()) {
110            for input in req.inputs.iter() {
111                request
112                    .inputs()
113                    .iter()
114                    .find(|arg| *input == arg.ty)
115                    .ok_or(RegisterRequestError::ArgumentsIncorrectly)?;
116            }
117
118            if req.output != request.output().map(|arg| arg.ty) {
119                return Err(RegisterRequestError::ArgumentsIncorrectly);
120            }
121        } else {
122            return Err(RegisterRequestError::NotFound);
123        }
124
125        self.plugin.requests.push(Box::new(request));
126
127        Ok(())
128    }
129}