Skip to main content

trustformers_core/patterns/
mod.rs

1//! Design patterns and standardized utilities for TrustformeRS Core
2//!
3//! This module provides standardized design patterns that should be used
4//! consistently across the entire codebase for better maintainability
5//! and developer experience.
6
7pub mod builder;
8pub mod config_unification;
9
10pub use builder::{
11    Buildable, Builder, BuilderError, BuilderResult, ConfigBuilder, ConfigBuilderImpl,
12    ConfigSerializable, StandardBuilder, StandardConfig, ValidatedBuilder,
13};
14
15pub use config_unification::{
16    merge_unified_configs, AccessControlConfig, AccessControlModel, AuthenticationConfig,
17    AuthenticationMethod, BenchmarkConfig, BenchmarkFrequency, CacheConfig, CacheEvictionPolicy,
18    ConfigManager, ConfigMetadata, ConfigSource, CpuLimits, DebugConfig, DebugLevel,
19    DebugOutputFormat, EncryptionConfig, EnvironmentConfig, EnvironmentType, GpuLimits,
20    KeyManagementConfig, KeyStorageLocation, LogFormat, LogLevel, LogOutput, LogRotation,
21    LoggingConfig, MemoryLimits, NetworkLimits, OptimizationConfig, OptimizationLevel,
22    PerformanceConfig, PrecisionConfig, PrecisionType, ProfilingLevel, ResourceConfig,
23    SecurityConfig, SecurityLevel, StorageLimits, TimeoutConfig, UnifiedConfig,
24};
25
26/// Re-export macros for convenience
27pub use crate::{builder_methods, quick_builder};
28
29/// Standard result type for pattern operations
30pub type PatternResult<T> = std::result::Result<T, PatternError>;
31
32/// Errors that can occur in pattern implementations
33#[derive(Debug, thiserror::Error)]
34pub enum PatternError {
35    #[error("Builder error: {0}")]
36    Builder(#[from] BuilderError),
37    #[error("Validation error: {reason}")]
38    Validation { reason: String },
39    #[error("Configuration error: {reason}")]
40    Configuration { reason: String },
41    #[error("Serialization error: {0}")]
42    Serialization(#[from] serde_json::Error),
43    #[error("IO error: {0}")]
44    Io(#[from] std::io::Error),
45}
46
47/// Common validation functions that can be used across builders
48pub mod validators {
49
50    use crate::errors::Result;
51
52    /// Validate that a string is not empty
53    pub fn non_empty_string(value: &str, field_name: &str) -> Result<()> {
54        if value.trim().is_empty() {
55            return Err(crate::errors::TrustformersError::invalid_config(format!(
56                "Field '{}' cannot be empty",
57                field_name
58            )));
59        }
60        Ok(())
61    }
62
63    /// Validate that a numeric value is within a range
64    pub fn numeric_range<T: PartialOrd + std::fmt::Display>(
65        value: T,
66        min: T,
67        max: T,
68        field_name: &str,
69    ) -> Result<()> {
70        if value < min || value > max {
71            return Err(crate::errors::TrustformersError::invalid_config(format!(
72                "Field '{}' value {} must be between {} and {}",
73                field_name, value, min, max
74            )));
75        }
76        Ok(())
77    }
78
79    /// Validate that a value is positive
80    pub fn positive<T: PartialOrd + Default + std::fmt::Display>(
81        value: T,
82        field_name: &str,
83    ) -> Result<()> {
84        if value <= T::default() {
85            return Err(crate::errors::TrustformersError::invalid_config(format!(
86                "Field '{}' value {} must be positive",
87                field_name, value
88            )));
89        }
90        Ok(())
91    }
92
93    /// Validate that a collection is not empty
94    pub fn non_empty_collection<T>(collection: &[T], field_name: &str) -> Result<()> {
95        if collection.is_empty() {
96            return Err(crate::errors::TrustformersError::invalid_config(format!(
97                "Field '{}' cannot be empty",
98                field_name
99            )));
100        }
101        Ok(())
102    }
103
104    /// Validate that a path exists
105    pub fn path_exists(path: &std::path::Path, field_name: &str) -> Result<()> {
106        if !path.exists() {
107            return Err(crate::errors::TrustformersError::invalid_config(format!(
108                "Path '{}' for field '{}' does not exist",
109                path.display(),
110                field_name
111            )));
112        }
113        Ok(())
114    }
115}
116
117/// Common configuration patterns
118pub mod config_patterns {
119    use super::*;
120    use serde::{Deserialize, Serialize};
121
122    /// Standard configuration base that all configs should inherit from
123    #[derive(Debug, Clone, Serialize, Deserialize)]
124    pub struct BaseConfig {
125        /// Configuration name/identifier
126        pub name: Option<String>,
127        /// Human-readable description
128        pub description: Option<String>,
129        /// Version of the configuration format
130        pub version: String,
131        /// Tags for categorization
132        pub tags: Vec<String>,
133        /// Whether this configuration is enabled
134        pub enabled: bool,
135        /// Timestamp when configuration was created
136        #[serde(default = "chrono::Utc::now")]
137        pub created_at: chrono::DateTime<chrono::Utc>,
138        /// Timestamp when configuration was last modified
139        #[serde(default = "chrono::Utc::now")]
140        pub modified_at: chrono::DateTime<chrono::Utc>,
141    }
142
143    impl Default for BaseConfig {
144        fn default() -> Self {
145            let now = chrono::Utc::now();
146            Self {
147                name: None,
148                description: None,
149                version: "1.0.0".to_string(),
150                tags: Vec::new(),
151                enabled: true,
152                created_at: now,
153                modified_at: now,
154            }
155        }
156    }
157
158    impl StandardConfig for BaseConfig {
159        fn validate(&self) -> crate::errors::Result<()> {
160            if let Some(name) = &self.name {
161                validators::non_empty_string(name, "name")?;
162            }
163            Ok(())
164        }
165    }
166
167    /// Resource limits configuration
168    #[derive(Debug, Clone, Serialize, Deserialize)]
169    pub struct ResourceLimits {
170        /// Maximum memory usage in bytes
171        pub max_memory_bytes: Option<usize>,
172        /// Maximum CPU percentage (0-100)
173        pub max_cpu_percent: Option<f64>,
174        /// Maximum GPU memory in bytes
175        pub max_gpu_memory_bytes: Option<usize>,
176        /// Timeout in milliseconds
177        pub timeout_ms: Option<u64>,
178        /// Maximum concurrent operations
179        pub max_concurrent: Option<usize>,
180    }
181
182    impl Default for ResourceLimits {
183        fn default() -> Self {
184            Self {
185                max_memory_bytes: None,
186                max_cpu_percent: Some(80.0),
187                max_gpu_memory_bytes: None,
188                timeout_ms: Some(300_000), // 5 minutes
189                max_concurrent: Some(4),
190            }
191        }
192    }
193
194    impl StandardConfig for ResourceLimits {
195        fn validate(&self) -> crate::errors::Result<()> {
196            if let Some(cpu) = self.max_cpu_percent {
197                validators::numeric_range(cpu, 0.0, 100.0, "max_cpu_percent")?;
198            }
199            if let Some(concurrent) = self.max_concurrent {
200                validators::positive(concurrent, "max_concurrent")?;
201            }
202            Ok(())
203        }
204    }
205
206    /// Logging configuration
207    #[derive(Debug, Clone, Serialize, Deserialize)]
208    pub struct LoggingConfig {
209        /// Log level
210        pub level: String,
211        /// Log format (json, text, etc.)
212        pub format: String,
213        /// Log output destination
214        pub output: String,
215        /// Whether to include timestamps
216        pub include_timestamps: bool,
217        /// Whether to include source file information
218        pub include_source: bool,
219        /// Maximum log file size in bytes
220        pub max_file_size_bytes: Option<usize>,
221        /// Maximum number of log files to keep
222        pub max_files: Option<usize>,
223    }
224
225    impl Default for LoggingConfig {
226        fn default() -> Self {
227            Self {
228                level: "info".to_string(),
229                format: "text".to_string(),
230                output: "stdout".to_string(),
231                include_timestamps: true,
232                include_source: false,
233                max_file_size_bytes: Some(10 * 1024 * 1024), // 10 MB
234                max_files: Some(5),
235            }
236        }
237    }
238
239    impl StandardConfig for LoggingConfig {
240        fn validate(&self) -> crate::errors::Result<()> {
241            let valid_levels = ["trace", "debug", "info", "warn", "error"];
242            if !valid_levels.contains(&self.level.as_str()) {
243                return Err(crate::errors::TrustformersError::invalid_config(format!(
244                    "Invalid log level '{}'. Must be one of: {}",
245                    self.level,
246                    valid_levels.join(", ")
247                )));
248            }
249
250            let valid_formats = ["json", "text", "pretty"];
251            if !valid_formats.contains(&self.format.as_str()) {
252                return Err(crate::errors::TrustformersError::invalid_config(format!(
253                    "Invalid log format '{}'. Must be one of: {}",
254                    self.format,
255                    valid_formats.join(", ")
256                )));
257            }
258
259            Ok(())
260        }
261    }
262}
263
264/// Example usage and documentation
265pub mod examples {
266    use super::*;
267    use serde::{Deserialize, Serialize};
268
269    #[derive(Debug, Clone, Default, Serialize, Deserialize)]
270    pub struct ExampleConfig {
271        pub base: config_patterns::BaseConfig,
272        pub resources: config_patterns::ResourceLimits,
273        pub logging: config_patterns::LoggingConfig,
274        pub custom_setting: String,
275    }
276
277    impl StandardConfig for ExampleConfig {
278        fn validate(&self) -> crate::errors::Result<()> {
279            self.base.validate()?;
280            self.resources.validate()?;
281            self.logging.validate()?;
282            validators::non_empty_string(&self.custom_setting, "custom_setting")?;
283            Ok(())
284        }
285    }
286
287    /// Example of creating a builder for the ExampleConfig
288    pub fn example_config_builder() -> ConfigBuilderImpl<ExampleConfig, ExampleConfig> {
289        ConfigBuilderImpl::new()
290    }
291
292    /// Example usage function showing how to use the standardized patterns
293    #[allow(dead_code)]
294    pub fn example_usage() -> crate::errors::Result<ExampleConfig> {
295        let config = ExampleConfig {
296            custom_setting: "example_value".to_string(),
297            ..Default::default()
298        };
299
300        let builder = example_config_builder()
301            .config(config)
302            .name("example_configuration")
303            .description("An example of using standardized builder patterns")
304            .tag("example")
305            .tag("documentation");
306
307        builder.build()
308    }
309}