sklears_core/plugin/
factory_builder.rs

1//! Plugin Factory and Configuration Builder
2//!
3//! This module provides factory patterns and builders for creating plugin instances
4//! and configurations. It enables flexible plugin creation with configurable
5//! parameters and runtime settings.
6
7use super::core_traits::Plugin;
8use super::types_config::{LogLevel, PluginConfig, PluginMetadata, PluginParameter};
9use crate::error::Result;
10
11/// Factory for creating plugin instances
12///
13/// The PluginFactory trait provides a standardized interface for creating
14/// plugin instances with specific configurations. This enables dynamic
15/// plugin creation and configuration management.
16///
17/// # Examples
18///
19/// ```rust,no_run
20/// use sklears_core::plugin::{PluginFactory, Plugin, PluginConfig, PluginMetadata};
21/// use sklears_core::error::Result;
22///
23/// struct LinearRegressionFactory;
24///
25/// impl PluginFactory for LinearRegressionFactory {
26///     fn create_plugin(&self, config: &PluginConfig) -> Result<Box<dyn Plugin>> {
27///         // Create and configure the plugin based on the provided config
28///         // Box::new(LinearRegressionPlugin::new(config))
29///         todo!("Implement plugin creation")
30///     }
31///
32///     fn metadata(&self) -> PluginMetadata {
33///         PluginMetadata {
34///             name: "LinearRegression".to_string(),
35///             version: "1.0.0".to_string(),
36///             description: "Linear regression algorithm".to_string(),
37///             ..Default::default()
38///         }
39///     }
40///
41///     fn validate_config(&self, config: &PluginConfig) -> Result<()> {
42///         // Validate configuration parameters
43///         Ok(())
44///     }
45/// }
46/// ```
47pub trait PluginFactory: Send + Sync {
48    /// Create a new plugin instance
49    ///
50    /// This method creates a new plugin instance configured according to
51    /// the provided configuration. The factory should validate the configuration
52    /// and return an error if the plugin cannot be created with the given settings.
53    ///
54    /// # Arguments
55    ///
56    /// * `config` - The configuration for the plugin instance
57    ///
58    /// # Returns
59    ///
60    /// A boxed plugin instance, or an error if creation fails.
61    fn create_plugin(&self, config: &PluginConfig) -> Result<Box<dyn Plugin>>;
62
63    /// Get plugin metadata
64    ///
65    /// Returns metadata describing the plugins that this factory can create.
66    /// This includes information about capabilities, supported types, and
67    /// configuration requirements.
68    ///
69    /// # Returns
70    ///
71    /// Metadata for plugins created by this factory.
72    fn metadata(&self) -> PluginMetadata;
73
74    /// Validate configuration
75    ///
76    /// Validates that the provided configuration is suitable for creating
77    /// a plugin instance. This should check parameter types, ranges, and
78    /// any dependencies or requirements.
79    ///
80    /// # Arguments
81    ///
82    /// * `config` - The configuration to validate
83    ///
84    /// # Returns
85    ///
86    /// Ok(()) if the configuration is valid, or an error describing
87    /// what is invalid.
88    fn validate_config(&self, config: &PluginConfig) -> Result<()>;
89
90    /// Get default configuration
91    ///
92    /// Returns a default configuration that can be used to create a plugin
93    /// instance with sensible defaults. This provides a starting point for
94    /// configuration customization.
95    ///
96    /// # Returns
97    ///
98    /// A default plugin configuration.
99    fn default_config(&self) -> PluginConfig {
100        PluginConfig::default()
101    }
102
103    /// Get configuration schema
104    ///
105    /// Returns information about the configuration parameters that this
106    /// factory accepts, including their types, ranges, and descriptions.
107    /// This can be used for automatic UI generation or documentation.
108    ///
109    /// # Returns
110    ///
111    /// A map of parameter names to their descriptions and constraints.
112    fn config_schema(&self) -> std::collections::HashMap<String, String> {
113        std::collections::HashMap::new()
114    }
115}
116
117/// Builder for creating plugin configurations
118///
119/// The PluginConfigBuilder provides a fluent interface for constructing
120/// plugin configurations with various parameters and runtime settings.
121/// It ensures type safety and provides convenient methods for common
122/// configuration patterns.
123///
124/// # Examples
125///
126/// ```rust
127/// use sklears_core::plugin::{PluginConfigBuilder, PluginParameter, LogLevel};
128///
129/// let config = PluginConfigBuilder::new()
130///     .with_parameter("learning_rate", PluginParameter::Float(0.01))
131///     .with_parameter("max_iterations", PluginParameter::Int(1000))
132///     .with_parameter("use_bias", PluginParameter::Bool(true))
133///     .with_threads(4)
134///     .with_memory_limit(1024 * 1024 * 1024) // 1GB
135///     .with_timeout(30000) // 30 seconds
136///     .with_gpu(true)
137///     .with_log_level(LogLevel::Info)
138///     .with_setting("backend", "cuda")
139///     .build();
140/// ```
141#[derive(Debug, Clone)]
142pub struct PluginConfigBuilder {
143    /// The configuration being built
144    config: PluginConfig,
145}
146
147impl PluginConfigBuilder {
148    /// Create a new config builder
149    ///
150    /// Initializes a new builder with default configuration values.
151    ///
152    /// # Examples
153    ///
154    /// ```rust
155    /// use sklears_core::plugin::PluginConfigBuilder;
156    ///
157    /// let builder = PluginConfigBuilder::new();
158    /// let config = builder.build();
159    /// ```
160    pub fn new() -> Self {
161        Self {
162            config: PluginConfig::default(),
163        }
164    }
165
166    /// Add a parameter to the configuration
167    ///
168    /// Adds a named parameter with the specified value to the configuration.
169    /// This method can be chained to add multiple parameters.
170    ///
171    /// # Arguments
172    ///
173    /// * `key` - The parameter name
174    /// * `value` - The parameter value
175    ///
176    /// # Examples
177    ///
178    /// ```rust
179    /// use sklears_core::plugin::{PluginConfigBuilder, PluginParameter};
180    ///
181    /// let config = PluginConfigBuilder::new()
182    ///     .with_parameter("learning_rate", PluginParameter::Float(0.01))
183    ///     .with_parameter("regularization", PluginParameter::Float(0.001))
184    ///     .build();
185    /// ```
186    pub fn with_parameter(mut self, key: &str, value: PluginParameter) -> Self {
187        self.config.parameters.insert(key.to_string(), value);
188        self
189    }
190
191    /// Add multiple parameters at once
192    ///
193    /// Convenience method for adding multiple parameters from a map.
194    ///
195    /// # Arguments
196    ///
197    /// * `params` - Map of parameter names to values
198    pub fn with_parameters(
199        mut self,
200        params: std::collections::HashMap<String, PluginParameter>,
201    ) -> Self {
202        self.config.parameters.extend(params);
203        self
204    }
205
206    /// Set the number of threads to use
207    ///
208    /// Configures the number of threads that the plugin should use for
209    /// parallel processing. If not set, the plugin will use its default
210    /// threading behavior.
211    ///
212    /// # Arguments
213    ///
214    /// * `threads` - Number of threads to use
215    ///
216    /// # Examples
217    ///
218    /// ```rust
219    /// use sklears_core::plugin::PluginConfigBuilder;
220    ///
221    /// let config = PluginConfigBuilder::new()
222    ///     .with_threads(8)
223    ///     .build();
224    /// ```
225    pub fn with_threads(mut self, threads: usize) -> Self {
226        self.config.runtime_settings.num_threads = Some(threads);
227        self
228    }
229
230    /// Set memory limit in bytes
231    ///
232    /// Configures the maximum amount of memory that the plugin should use.
233    /// This can help prevent out-of-memory errors in resource-constrained
234    /// environments.
235    ///
236    /// # Arguments
237    ///
238    /// * `limit` - Memory limit in bytes
239    ///
240    /// # Examples
241    ///
242    /// ```rust
243    /// use sklears_core::plugin::PluginConfigBuilder;
244    ///
245    /// let config = PluginConfigBuilder::new()
246    ///     .with_memory_limit(2 * 1024 * 1024 * 1024) // 2GB
247    ///     .build();
248    /// ```
249    pub fn with_memory_limit(mut self, limit: usize) -> Self {
250        self.config.runtime_settings.memory_limit = Some(limit);
251        self
252    }
253
254    /// Set timeout in milliseconds
255    ///
256    /// Configures the maximum time that plugin operations should take
257    /// before timing out. This can help prevent hanging operations.
258    ///
259    /// # Arguments
260    ///
261    /// * `timeout_ms` - Timeout in milliseconds
262    ///
263    /// # Examples
264    ///
265    /// ```rust
266    /// use sklears_core::plugin::PluginConfigBuilder;
267    ///
268    /// let config = PluginConfigBuilder::new()
269    ///     .with_timeout(60000) // 1 minute
270    ///     .build();
271    /// ```
272    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
273        self.config.runtime_settings.timeout_ms = Some(timeout_ms);
274        self
275    }
276
277    /// Enable or disable GPU acceleration
278    ///
279    /// Configures whether the plugin should use GPU acceleration if available.
280    ///
281    /// # Arguments
282    ///
283    /// * `use_gpu` - Whether to use GPU acceleration
284    ///
285    /// # Examples
286    ///
287    /// ```rust
288    /// use sklears_core::plugin::PluginConfigBuilder;
289    ///
290    /// let config = PluginConfigBuilder::new()
291    ///     .with_gpu(true)
292    ///     .build();
293    /// ```
294    pub fn with_gpu(mut self, use_gpu: bool) -> Self {
295        self.config.runtime_settings.use_gpu = use_gpu;
296        self
297    }
298
299    /// Set logging level
300    ///
301    /// Configures the verbosity of logging output from the plugin.
302    ///
303    /// # Arguments
304    ///
305    /// * `level` - The logging level to use
306    ///
307    /// # Examples
308    ///
309    /// ```rust
310    /// use sklears_core::plugin::{PluginConfigBuilder, LogLevel};
311    ///
312    /// let config = PluginConfigBuilder::new()
313    ///     .with_log_level(LogLevel::Debug)
314    ///     .build();
315    /// ```
316    pub fn with_log_level(mut self, level: LogLevel) -> Self {
317        self.config.runtime_settings.log_level = level;
318        self
319    }
320
321    /// Add a plugin-specific setting
322    ///
323    /// Adds a custom setting that is specific to the plugin being configured.
324    /// These settings are typically used for plugin-specific configuration
325    /// that doesn't fit into the standard parameter system.
326    ///
327    /// # Arguments
328    ///
329    /// * `key` - The setting name
330    /// * `value` - The setting value
331    ///
332    /// # Examples
333    ///
334    /// ```rust
335    /// use sklears_core::plugin::PluginConfigBuilder;
336    ///
337    /// let config = PluginConfigBuilder::new()
338    ///     .with_setting("backend", "tensorflow")
339    ///     .with_setting("device", "/gpu:0")
340    ///     .build();
341    /// ```
342    pub fn with_setting(mut self, key: &str, value: &str) -> Self {
343        self.config
344            .plugin_settings
345            .insert(key.to_string(), value.to_string());
346        self
347    }
348
349    /// Add multiple settings at once
350    ///
351    /// Convenience method for adding multiple plugin-specific settings.
352    ///
353    /// # Arguments
354    ///
355    /// * `settings` - Map of setting names to values
356    pub fn with_settings(mut self, settings: std::collections::HashMap<String, String>) -> Self {
357        self.config.plugin_settings.extend(settings);
358        self
359    }
360
361    /// Build the final configuration
362    ///
363    /// Consumes the builder and returns the constructed configuration.
364    ///
365    /// # Returns
366    ///
367    /// The configured PluginConfig instance.
368    ///
369    /// # Examples
370    ///
371    /// ```rust
372    /// use sklears_core::plugin::{PluginConfigBuilder, PluginParameter};
373    ///
374    /// let config = PluginConfigBuilder::new()
375    ///     .with_parameter("learning_rate", PluginParameter::Float(0.01))
376    ///     .with_threads(4)
377    ///     .build();
378    /// ```
379    pub fn build(self) -> PluginConfig {
380        self.config
381    }
382
383    /// Get a reference to the current configuration
384    ///
385    /// Returns a reference to the configuration being built without
386    /// consuming the builder. This can be useful for inspecting the
387    /// current state during construction.
388    ///
389    /// # Returns
390    ///
391    /// A reference to the current configuration.
392    pub fn config(&self) -> &PluginConfig {
393        &self.config
394    }
395
396    /// Validate the current configuration
397    ///
398    /// Validates the current configuration state without building it.
399    /// This can be useful for checking configuration validity during
400    /// the building process.
401    ///
402    /// # Returns
403    ///
404    /// Ok(()) if the configuration is valid, or an error describing
405    /// what is invalid.
406    pub fn validate(&self) -> Result<()> {
407        // Basic validation - can be extended
408        if self.config.runtime_settings.num_threads == Some(0) {
409            return Err(crate::error::SklearsError::InvalidOperation(
410                "Number of threads cannot be zero".to_string(),
411            ));
412        }
413
414        if let Some(timeout) = self.config.runtime_settings.timeout_ms {
415            if timeout == 0 {
416                return Err(crate::error::SklearsError::InvalidOperation(
417                    "Timeout cannot be zero".to_string(),
418                ));
419            }
420        }
421
422        Ok(())
423    }
424
425    /// Clone the builder
426    ///
427    /// Creates a copy of the current builder state, allowing for
428    /// branching configuration construction.
429    ///
430    /// # Returns
431    ///
432    /// A cloned builder with the same configuration state.
433    pub fn clone_builder(&self) -> Self {
434        self.clone()
435    }
436}
437
438impl Default for PluginConfigBuilder {
439    fn default() -> Self {
440        Self::new()
441    }
442}
443
444/// Convenience functions for common plugin configurations
445impl PluginConfigBuilder {
446    /// Create a configuration optimized for CPU-intensive tasks
447    ///
448    /// Sets up a configuration with appropriate threading and resource
449    /// settings for CPU-bound algorithms.
450    pub fn cpu_optimized() -> Self {
451        Self::new()
452            .with_threads(num_cpus::get())
453            .with_gpu(false)
454            .with_log_level(LogLevel::Info)
455    }
456
457    /// Create a configuration optimized for GPU acceleration
458    ///
459    /// Sets up a configuration with GPU acceleration enabled and
460    /// appropriate resource settings.
461    pub fn gpu_optimized() -> Self {
462        Self::new()
463            .with_gpu(true)
464            .with_threads(2) // Fewer CPU threads when using GPU
465            .with_log_level(LogLevel::Info)
466    }
467
468    /// Create a configuration for development/debugging
469    ///
470    /// Sets up a configuration with verbose logging and longer timeouts
471    /// suitable for development environments.
472    pub fn development() -> Self {
473        Self::new()
474            .with_log_level(LogLevel::Debug)
475            .with_timeout(300000) // 5 minutes
476            .with_threads(1) // Single-threaded for easier debugging
477    }
478
479    /// Create a configuration for production environments
480    ///
481    /// Sets up a configuration with optimized settings for production use,
482    /// including appropriate resource limits and logging levels.
483    pub fn production() -> Self {
484        Self::new()
485            .with_log_level(LogLevel::Warn)
486            .with_timeout(30000) // 30 seconds
487            .with_memory_limit(4 * 1024 * 1024 * 1024) // 4GB
488            .with_threads(num_cpus::get())
489    }
490}