Skip to main content

sklears_compose/
enhanced_compile_time_validation.rs

1//! Enhanced compile-time validation for pipeline configurations
2//!
3//! This module provides comprehensive compile-time validation capabilities for ML pipelines including:
4//! - Type-level validation using Rust's type system to catch errors at compile time
5//! - Constraint validation for parameter ranges and dependencies
6//! - Schema validation for configuration structure and format
7//! - Cross-reference validation for relationships between configuration sections
8//! - Custom validation rules and user-defined validation logic
9//! - Comprehensive validation reporting with detailed error messages and suggestions
10
11use crate::error::{Result, SklearsComposeError};
12use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, HashSet};
14use std::marker::PhantomData;
15use std::sync::{Arc, RwLock};
16use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
17
18/// Enhanced compile-time validation system for ML pipeline configurations
19#[derive(Debug)]
20pub struct CompileTimeValidator<State = Unvalidated> {
21    /// Validation state marker
22    state: PhantomData<State>,
23
24    /// Schema validators for different configuration types
25    schema_validators: Arc<RwLock<HashMap<String, Box<dyn SchemaValidator>>>>,
26
27    /// Constraint validators for parameter validation
28    constraint_validators: Arc<RwLock<Vec<Box<dyn ConstraintValidator>>>>,
29
30    /// Dependency validators for checking relationships
31    dependency_validators: Arc<RwLock<Vec<Box<dyn DependencyValidator>>>>,
32
33    /// Cross-reference validators for inter-section validation
34    cross_reference_validators: Arc<RwLock<Vec<Box<dyn CrossReferenceValidator>>>>,
35
36    /// Custom validation rules
37    custom_validators: Arc<RwLock<Vec<Box<dyn CustomValidator>>>>,
38
39    /// Validation configuration
40    config: ValidationConfig,
41
42    /// Validation cache for performance
43    validation_cache: Arc<RwLock<HashMap<String, ValidationResult>>>,
44}
45
46/// Validation state markers
47#[derive(Debug, Clone)]
48pub struct Unvalidated;
49
50#[derive(Debug, Clone)]
51pub struct Validated;
52
53#[derive(Debug, Clone)]
54pub struct PartiallyValidated;
55
56/// Configuration for validation behavior
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct ValidationConfig {
59    /// Enable strict type checking
60    pub strict_type_checking: bool,
61
62    /// Enable constraint validation
63    pub enable_constraint_validation: bool,
64
65    /// Enable dependency validation
66    pub enable_dependency_validation: bool,
67
68    /// Enable cross-reference validation
69    pub enable_cross_reference_validation: bool,
70
71    /// Enable custom validation rules
72    pub enable_custom_validation: bool,
73
74    /// Maximum validation depth for nested configurations
75    pub max_validation_depth: usize,
76
77    /// Validation timeout
78    pub validation_timeout: Duration,
79
80    /// Enable validation caching
81    pub enable_caching: bool,
82
83    /// Fail fast on first error or collect all errors
84    pub fail_fast: bool,
85
86    /// Enable detailed validation reports
87    pub detailed_reports: bool,
88}
89
90/// Comprehensive validation result
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct ValidationResult {
93    /// Overall validation status
94    pub status: ValidationStatus,
95
96    /// Validation errors found
97    pub errors: Vec<ValidationError>,
98
99    /// Validation warnings
100    pub warnings: Vec<ValidationWarning>,
101
102    /// Validation suggestions
103    pub suggestions: Vec<ValidationSuggestion>,
104
105    /// Validation metrics
106    pub metrics: ValidationMetrics,
107
108    /// Validation timestamp
109    pub timestamp: SystemTime,
110}
111
112/// Validation status
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub enum ValidationStatus {
115    /// Valid
116    Valid,
117    /// Invalid
118    Invalid,
119    /// Warning
120    Warning,
121    /// Partial
122    Partial,
123    /// Unknown
124    Unknown,
125}
126
127/// Validation error with detailed information
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct ValidationError {
130    /// Error identifier
131    pub error_id: String,
132
133    /// Error category
134    pub category: ValidationErrorCategory,
135
136    /// Error message
137    pub message: String,
138
139    /// Error location in configuration
140    pub location: ConfigurationLocation,
141
142    /// Error severity
143    pub severity: ValidationSeverity,
144
145    /// Expected value or format
146    pub expected: Option<String>,
147
148    /// Actual value found
149    pub actual: Option<String>,
150
151    /// Suggested fix
152    pub suggestion: Option<String>,
153
154    /// Related errors
155    pub related_errors: Vec<String>,
156}
157
158/// Categories of validation errors
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub enum ValidationErrorCategory {
161    /// TypeMismatch
162    TypeMismatch,
163    /// ConstraintViolation
164    ConstraintViolation,
165    /// MissingRequired
166    MissingRequired,
167    /// InvalidFormat
168    InvalidFormat,
169    /// DependencyMissing
170    DependencyMissing,
171    /// CrossReferenceError
172    CrossReferenceError,
173    /// CustomValidationFailure
174    CustomValidationFailure,
175    /// SchemaViolation
176    SchemaViolation,
177    /// RangeError
178    RangeError,
179    /// CompatibilityError
180    CompatibilityError,
181}
182
183/// Validation error severity levels
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub enum ValidationSeverity {
186    /// Critical
187    Critical,
188    /// High
189    High,
190    /// Medium
191    Medium,
192    /// Low
193    Low,
194    /// Info
195    Info,
196}
197
198/// Location within configuration
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct ConfigurationLocation {
201    /// Configuration section
202    pub section: String,
203
204    /// Field path (e.g., "`model.parameters.learning_rate`")
205    pub field_path: String,
206
207    /// Line number (if applicable)
208    pub line_number: Option<usize>,
209
210    /// Column number (if applicable)
211    pub column_number: Option<usize>,
212}
213
214/// Validation warning
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct ValidationWarning {
217    /// Warning identifier
218    pub warning_id: String,
219
220    /// Warning message
221    pub message: String,
222
223    /// Warning location
224    pub location: ConfigurationLocation,
225
226    /// Warning category
227    pub category: WarningCategory,
228
229    /// Recommendation
230    pub recommendation: Option<String>,
231}
232
233/// Warning categories
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub enum WarningCategory {
236    /// Performance
237    Performance,
238    /// Compatibility
239    Compatibility,
240    /// Deprecated
241    Deprecated,
242    /// Suboptimal
243    Suboptimal,
244    /// Experimental
245    Experimental,
246}
247
248/// Validation suggestion
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct ValidationSuggestion {
251    /// Suggestion identifier
252    pub suggestion_id: String,
253
254    /// Suggestion message
255    pub message: String,
256
257    /// Suggested action
258    pub action: SuggestionAction,
259
260    /// Confidence level
261    pub confidence: f64,
262
263    /// Priority level
264    pub priority: SuggestionPriority,
265}
266
267/// Types of suggestion actions
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub enum SuggestionAction {
270    /// AddField
271    AddField { field: String, value: String },
272    /// RemoveField
273    RemoveField { field: String },
274    /// ModifyField
275    ModifyField { field: String, new_value: String },
276    /// RestructureSection
277    RestructureSection {
278        section: String,
279        new_structure: String,
280    },
281    /// AddDependency
282    AddDependency { dependency: String },
283    /// UpgradeVersion
284    UpgradeVersion { component: String, version: String },
285}
286
287/// Suggestion priority levels
288#[derive(Debug, Clone, Serialize, Deserialize)]
289pub enum SuggestionPriority {
290    /// Critical
291    Critical,
292    /// High
293    High,
294    /// Medium
295    Medium,
296    /// Low
297    Low,
298}
299
300/// Validation performance metrics
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub struct ValidationMetrics {
303    /// Total validation time
304    pub validation_time: Duration,
305
306    /// Number of rules checked
307    pub rules_checked: usize,
308
309    /// Number of fields validated
310    pub fields_validated: usize,
311
312    /// Cache hit rate
313    pub cache_hit_rate: f64,
314
315    /// Memory usage during validation
316    pub memory_usage: u64,
317}
318
319/// Type-safe configuration builder with compile-time validation
320#[derive(Debug)]
321pub struct TypeSafeConfigBuilder<State = Unbuilt> {
322    /// Builder state marker
323    state: PhantomData<State>,
324
325    /// Configuration data
326    config_data: HashMap<String, ConfigValue>,
327
328    /// Type constraints
329    type_constraints: HashMap<String, TypeConstraint>,
330
331    /// Validation rules
332    validation_rules: Vec<Box<dyn ValidationRule>>,
333
334    /// Builder configuration
335    builder_config: BuilderConfig,
336}
337
338/// Builder state markers
339#[derive(Debug, Clone)]
340pub struct Unbuilt;
341
342#[derive(Debug, Clone)]
343pub struct Built;
344
345/// Configuration value with type information
346#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
347pub enum ConfigValue {
348    /// String
349    String(String),
350    /// Integer
351    Integer(i64),
352    /// Float
353    Float(f64),
354    /// Boolean
355    Boolean(bool),
356    /// Array
357    Array(Vec<ConfigValue>),
358    /// Object
359    Object(HashMap<String, ConfigValue>),
360    /// Null
361    Null,
362}
363
364/// Type constraint for configuration fields
365pub struct TypeConstraint {
366    /// Expected type
367    pub expected_type: ConfigType,
368
369    /// Whether field is required
370    pub required: bool,
371
372    /// Default value if not provided
373    pub default_value: Option<ConfigValue>,
374
375    /// Value constraints
376    pub constraints: Vec<ValueConstraint>,
377
378    /// Custom validation function
379    pub custom_validator: Option<Box<dyn Fn(&ConfigValue) -> Result<()> + Send + Sync>>,
380}
381
382impl std::fmt::Debug for TypeConstraint {
383    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384        f.debug_struct("TypeConstraint")
385            .field("expected_type", &self.expected_type)
386            .field("required", &self.required)
387            .field("default_value", &self.default_value)
388            .field("constraints", &self.constraints)
389            .field(
390                "custom_validator",
391                &format!(
392                    "<{} validator>",
393                    if self.custom_validator.is_some() {
394                        "some"
395                    } else {
396                        "none"
397                    }
398                ),
399            )
400            .finish()
401    }
402}
403
404impl Clone for TypeConstraint {
405    fn clone(&self) -> Self {
406        Self {
407            expected_type: self.expected_type.clone(),
408            required: self.required,
409            default_value: self.default_value.clone(),
410            constraints: self.constraints.clone(),
411            custom_validator: None, // Can't clone function pointers
412        }
413    }
414}
415
416/// Configuration value types
417#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
418pub enum ConfigType {
419    /// String
420    String,
421    /// Integer
422    Integer,
423    /// Float
424    Float,
425    /// Boolean
426    Boolean,
427    /// Array
428    Array(Box<ConfigType>),
429    /// Object
430    Object(HashMap<String, ConfigType>),
431    /// Union
432    Union(Vec<ConfigType>),
433    /// Optional
434    Optional(Box<ConfigType>),
435}
436
437/// Value constraints for configuration fields
438#[derive(Debug, Clone, Serialize, Deserialize)]
439pub enum ValueConstraint {
440    /// Range
441    Range { min: f64, max: f64 },
442    /// Length
443    Length { min: usize, max: Option<usize> },
444    /// Pattern
445    Pattern(String),
446    /// OneOf
447    OneOf(Vec<ConfigValue>),
448    /// Custom
449    Custom(String), // Custom constraint description
450}
451
452/// Builder configuration
453#[derive(Debug, Clone)]
454pub struct BuilderConfig {
455    /// Enable strict validation
456    pub strict_validation: bool,
457
458    /// Allow unknown fields
459    pub allow_unknown_fields: bool,
460
461    /// Maximum nesting depth
462    pub max_nesting_depth: usize,
463}
464
465/// Schema validator trait
466pub trait SchemaValidator: std::fmt::Debug + Send + Sync {
467    /// Validate configuration against schema
468    fn validate_schema(
469        &self,
470        config: &HashMap<String, ConfigValue>,
471    ) -> Result<Vec<ValidationError>>;
472
473    /// Get schema name
474    fn schema_name(&self) -> &str;
475
476    /// Get schema version
477    fn schema_version(&self) -> &str;
478}
479
480/// Constraint validator trait
481pub trait ConstraintValidator: std::fmt::Debug + Send + Sync {
482    /// Validate configuration constraints
483    fn validate_constraints(
484        &self,
485        config: &HashMap<String, ConfigValue>,
486    ) -> Result<Vec<ValidationError>>;
487
488    /// Get validator name
489    fn validator_name(&self) -> &str;
490}
491
492/// Dependency validator trait
493pub trait DependencyValidator: std::fmt::Debug + Send + Sync {
494    /// Validate configuration dependencies
495    fn validate_dependencies(
496        &self,
497        config: &HashMap<String, ConfigValue>,
498    ) -> Result<Vec<ValidationError>>;
499
500    /// Get dependency validator name
501    fn validator_name(&self) -> &str;
502}
503
504/// Cross-reference validator trait
505pub trait CrossReferenceValidator: std::fmt::Debug + Send + Sync {
506    /// Validate cross-references in configuration
507    fn validate_cross_references(
508        &self,
509        config: &HashMap<String, ConfigValue>,
510    ) -> Result<Vec<ValidationError>>;
511
512    /// Get validator name
513    fn validator_name(&self) -> &str;
514}
515
516/// Custom validator trait
517pub trait CustomValidator: std::fmt::Debug + Send + Sync {
518    /// Perform custom validation
519    fn validate(&self, config: &HashMap<String, ConfigValue>) -> Result<Vec<ValidationError>>;
520
521    /// Get validator name
522    fn validator_name(&self) -> &str;
523
524    /// Get validator description
525    fn description(&self) -> &str;
526}
527
528/// Validation rule trait
529pub trait ValidationRule: std::fmt::Debug + Send + Sync {
530    /// Apply validation rule
531    fn apply(&self, field: &str, value: &ConfigValue) -> Result<()>;
532
533    /// Get rule name
534    fn rule_name(&self) -> &str;
535}
536
537/// Pipeline configuration schema
538#[derive(Debug, Clone, Serialize, Deserialize)]
539pub struct PipelineConfigurationSchema {
540    /// Schema version
541    pub version: String,
542
543    /// Required fields
544    pub required_fields: HashSet<String>,
545
546    /// Field definitions
547    pub field_definitions: HashMap<String, FieldDefinition>,
548
549    /// Schema constraints
550    pub constraints: Vec<SchemaConstraint>,
551
552    /// Cross-reference rules
553    pub cross_reference_rules: Vec<CrossReferenceRule>,
554}
555
556/// Field definition in schema
557#[derive(Debug, Clone, Serialize, Deserialize)]
558pub struct FieldDefinition {
559    /// Field type
560    pub field_type: ConfigType,
561
562    /// Field description
563    pub description: String,
564
565    /// Default value
566    pub default: Option<ConfigValue>,
567
568    /// Field constraints
569    pub constraints: Vec<ValueConstraint>,
570
571    /// Whether field is deprecated
572    pub deprecated: bool,
573
574    /// Deprecation message
575    pub deprecation_message: Option<String>,
576}
577
578/// Schema-level constraint
579#[derive(Debug, Clone, Serialize, Deserialize)]
580pub struct SchemaConstraint {
581    /// Constraint name
582    pub name: String,
583
584    /// Constraint description
585    pub description: String,
586
587    /// Fields involved in constraint
588    pub fields: Vec<String>,
589
590    /// Constraint type
591    pub constraint_type: SchemaConstraintType,
592}
593
594/// Types of schema constraints
595#[derive(Debug, Clone, Serialize, Deserialize)]
596pub enum SchemaConstraintType {
597    /// MutualExclusion
598    MutualExclusion,
599    /// RequiredTogether
600    RequiredTogether,
601    /// ConditionalRequired
602    ConditionalRequired {
603        condition: String,
604        required: Vec<String>,
605    },
606    /// ValueDependency
607    ValueDependency {
608        field: String,
609        dependent_field: String,
610        values: Vec<ConfigValue>,
611    },
612}
613
614/// Cross-reference rule
615#[derive(Debug, Clone, Serialize, Deserialize)]
616pub struct CrossReferenceRule {
617    /// Rule name
618    pub name: String,
619
620    /// Source field
621    pub source_field: String,
622
623    /// Target field
624    pub target_field: String,
625
626    /// Reference type
627    pub reference_type: ReferenceType,
628
629    /// Validation rule
630    pub validation_rule: String,
631}
632
633/// Types of cross-references
634#[derive(Debug, Clone, Serialize, Deserialize)]
635pub enum ReferenceType {
636    /// ForeignKey
637    ForeignKey,
638    /// WeakReference
639    WeakReference,
640    /// StrongReference
641    StrongReference,
642    /// Computed
643    Computed,
644}
645
646/// Compile-time validated pipeline configuration
647#[derive(Debug)]
648pub struct ValidatedPipelineConfig<T> {
649    /// Configuration data
650    config: T,
651
652    /// Validation proof
653    validation_proof: ValidationProof,
654
655    /// Schema version used for validation
656    schema_version: String,
657}
658
659/// Proof that configuration has been validated
660#[derive(Debug, Clone)]
661pub struct ValidationProof {
662    /// Proof identifier
663    proof_id: String,
664
665    /// Validation timestamp
666    validation_time: SystemTime,
667
668    /// Validator version
669    validator_version: String,
670
671    /// Validation checksum
672    checksum: String,
673}
674
675/// Type-level proof that configuration is valid
676pub struct ValidConfigMarker<T>(PhantomData<T>);
677
678impl Default for ValidationConfig {
679    fn default() -> Self {
680        Self {
681            strict_type_checking: true,
682            enable_constraint_validation: true,
683            enable_dependency_validation: true,
684            enable_cross_reference_validation: true,
685            enable_custom_validation: true,
686            max_validation_depth: 10,
687            validation_timeout: Duration::from_secs(30),
688            enable_caching: true,
689            fail_fast: false,
690            detailed_reports: true,
691        }
692    }
693}
694
695impl<State> CompileTimeValidator<State> {
696    /// Create a new compile-time validator
697    #[must_use]
698    pub fn new() -> CompileTimeValidator<Unvalidated> {
699        Self::with_config(ValidationConfig::default())
700    }
701
702    /// Create a new compile-time validator with custom configuration
703    #[must_use]
704    pub fn with_config(config: ValidationConfig) -> CompileTimeValidator<Unvalidated> {
705        /// CompileTimeValidator
706        CompileTimeValidator {
707            state: PhantomData,
708            schema_validators: Arc::new(RwLock::new(HashMap::new())),
709            constraint_validators: Arc::new(RwLock::new(Vec::new())),
710            dependency_validators: Arc::new(RwLock::new(Vec::new())),
711            cross_reference_validators: Arc::new(RwLock::new(Vec::new())),
712            custom_validators: Arc::new(RwLock::new(Vec::new())),
713            config,
714            validation_cache: Arc::new(RwLock::new(HashMap::new())),
715        }
716    }
717}
718
719impl CompileTimeValidator<Unvalidated> {
720    /// Add a schema validator
721    #[must_use]
722    pub fn add_schema_validator(self, validator: Box<dyn SchemaValidator>) -> Self {
723        let schema_name = validator.schema_name().to_string();
724        self.schema_validators
725            .write()
726            .unwrap_or_else(|e| e.into_inner())
727            .insert(schema_name, validator);
728        self
729    }
730
731    /// Add a constraint validator
732    #[must_use]
733    pub fn add_constraint_validator(self, validator: Box<dyn ConstraintValidator>) -> Self {
734        self.constraint_validators
735            .write()
736            .unwrap_or_else(|e| e.into_inner())
737            .push(validator);
738        self
739    }
740
741    /// Add a dependency validator
742    #[must_use]
743    pub fn add_dependency_validator(self, validator: Box<dyn DependencyValidator>) -> Self {
744        self.dependency_validators
745            .write()
746            .unwrap_or_else(|e| e.into_inner())
747            .push(validator);
748        self
749    }
750
751    /// Add a cross-reference validator
752    #[must_use]
753    pub fn add_cross_reference_validator(
754        self,
755        validator: Box<dyn CrossReferenceValidator>,
756    ) -> Self {
757        self.cross_reference_validators
758            .write()
759            .unwrap_or_else(|e| e.into_inner())
760            .push(validator);
761        self
762    }
763
764    /// Add a custom validator
765    #[must_use]
766    pub fn add_custom_validator(self, validator: Box<dyn CustomValidator>) -> Self {
767        self.custom_validators
768            .write()
769            .unwrap_or_else(|e| e.into_inner())
770            .push(validator);
771        self
772    }
773
774    /// Validate configuration and transition to validated state
775    pub fn validate(
776        self,
777        config: &HashMap<String, ConfigValue>,
778    ) -> Result<(CompileTimeValidator<Validated>, ValidationResult)> {
779        let start_time = Instant::now();
780        let mut errors = Vec::new();
781        let warnings = Vec::new();
782        let mut suggestions = Vec::new();
783        let mut rules_checked = 0;
784
785        // Check validation cache
786        let config_hash = self.compute_config_hash(config);
787        if self.config.enable_caching {
788            if let Some(cached_result) = self
789                .validation_cache
790                .read()
791                .unwrap_or_else(|e| e.into_inner())
792                .get(&config_hash)
793            {
794                let validation_cache_clone = Arc::clone(&self.validation_cache);
795                return Ok((
796                    /// CompileTimeValidator
797                    CompileTimeValidator {
798                        state: PhantomData,
799                        schema_validators: self.schema_validators,
800                        constraint_validators: self.constraint_validators,
801                        dependency_validators: self.dependency_validators,
802                        cross_reference_validators: self.cross_reference_validators,
803                        custom_validators: self.custom_validators,
804                        config: self.config,
805                        validation_cache: validation_cache_clone,
806                    },
807                    cached_result.clone(),
808                ));
809            }
810        }
811
812        // Schema validation
813        if !self
814            .schema_validators
815            .read()
816            .unwrap_or_else(|e| e.into_inner())
817            .is_empty()
818        {
819            for validator in self
820                .schema_validators
821                .read()
822                .unwrap_or_else(|e| e.into_inner())
823                .values()
824            {
825                match validator.validate_schema(config) {
826                    Ok(mut schema_errors) => {
827                        errors.append(&mut schema_errors);
828                        rules_checked += 1;
829                    }
830                    Err(e) => {
831                        errors.push(ValidationError {
832                            error_id: format!("schema_error_{rules_checked}"),
833                            category: ValidationErrorCategory::SchemaViolation,
834                            message: e.to_string(),
835                            location: ConfigurationLocation {
836                                section: "schema".to_string(),
837                                field_path: "root".to_string(),
838                                line_number: None,
839                                column_number: None,
840                            },
841                            severity: ValidationSeverity::Critical,
842                            expected: None,
843                            actual: None,
844                            suggestion: Some(
845                                "Check schema definition and configuration format".to_string(),
846                            ),
847                            related_errors: Vec::new(),
848                        });
849                    }
850                }
851
852                if self.config.fail_fast && !errors.is_empty() {
853                    break;
854                }
855            }
856        }
857
858        // Constraint validation
859        if self.config.enable_constraint_validation && (errors.is_empty() || !self.config.fail_fast)
860        {
861            for validator in self
862                .constraint_validators
863                .read()
864                .unwrap_or_else(|e| e.into_inner())
865                .iter()
866            {
867                match validator.validate_constraints(config) {
868                    Ok(mut constraint_errors) => {
869                        errors.append(&mut constraint_errors);
870                        rules_checked += 1;
871                    }
872                    Err(e) => {
873                        errors.push(ValidationError {
874                            error_id: format!("constraint_error_{rules_checked}"),
875                            category: ValidationErrorCategory::ConstraintViolation,
876                            message: e.to_string(),
877                            location: ConfigurationLocation {
878                                section: "constraints".to_string(),
879                                field_path: "unknown".to_string(),
880                                line_number: None,
881                                column_number: None,
882                            },
883                            severity: ValidationSeverity::High,
884                            expected: None,
885                            actual: None,
886                            suggestion: Some(
887                                "Review parameter constraints and valid ranges".to_string(),
888                            ),
889                            related_errors: Vec::new(),
890                        });
891                    }
892                }
893
894                if self.config.fail_fast && !errors.is_empty() {
895                    break;
896                }
897            }
898        }
899
900        // Dependency validation
901        if self.config.enable_dependency_validation && (errors.is_empty() || !self.config.fail_fast)
902        {
903            for validator in self
904                .dependency_validators
905                .read()
906                .unwrap_or_else(|e| e.into_inner())
907                .iter()
908            {
909                match validator.validate_dependencies(config) {
910                    Ok(mut dependency_errors) => {
911                        errors.append(&mut dependency_errors);
912                        rules_checked += 1;
913                    }
914                    Err(e) => {
915                        errors.push(ValidationError {
916                            error_id: format!("dependency_error_{rules_checked}"),
917                            category: ValidationErrorCategory::DependencyMissing,
918                            message: e.to_string(),
919                            location: ConfigurationLocation {
920                                section: "dependencies".to_string(),
921                                field_path: "unknown".to_string(),
922                                line_number: None,
923                                column_number: None,
924                            },
925                            severity: ValidationSeverity::High,
926                            expected: None,
927                            actual: None,
928                            suggestion: Some(
929                                "Check that all required dependencies are configured".to_string(),
930                            ),
931                            related_errors: Vec::new(),
932                        });
933                    }
934                }
935
936                if self.config.fail_fast && !errors.is_empty() {
937                    break;
938                }
939            }
940        }
941
942        // Cross-reference validation
943        if self.config.enable_cross_reference_validation
944            && (errors.is_empty() || !self.config.fail_fast)
945        {
946            for validator in self
947                .cross_reference_validators
948                .read()
949                .unwrap_or_else(|e| e.into_inner())
950                .iter()
951            {
952                match validator.validate_cross_references(config) {
953                    Ok(mut cross_ref_errors) => {
954                        errors.append(&mut cross_ref_errors);
955                        rules_checked += 1;
956                    }
957                    Err(e) => {
958                        errors.push(ValidationError {
959                            error_id: format!("cross_ref_error_{rules_checked}"),
960                            category: ValidationErrorCategory::CrossReferenceError,
961                            message: e.to_string(),
962                            location: ConfigurationLocation {
963                                section: "cross_references".to_string(),
964                                field_path: "unknown".to_string(),
965                                line_number: None,
966                                column_number: None,
967                            },
968                            severity: ValidationSeverity::Medium,
969                            expected: None,
970                            actual: None,
971                            suggestion: Some(
972                                "Check cross-references between configuration sections".to_string(),
973                            ),
974                            related_errors: Vec::new(),
975                        });
976                    }
977                }
978
979                if self.config.fail_fast && !errors.is_empty() {
980                    break;
981                }
982            }
983        }
984
985        // Custom validation
986        if self.config.enable_custom_validation && (errors.is_empty() || !self.config.fail_fast) {
987            for validator in self
988                .custom_validators
989                .read()
990                .unwrap_or_else(|e| e.into_inner())
991                .iter()
992            {
993                match validator.validate(config) {
994                    Ok(mut custom_errors) => {
995                        errors.append(&mut custom_errors);
996                        rules_checked += 1;
997                    }
998                    Err(e) => {
999                        errors.push(ValidationError {
1000                            error_id: format!("custom_error_{rules_checked}"),
1001                            category: ValidationErrorCategory::CustomValidationFailure,
1002                            message: e.to_string(),
1003                            location: ConfigurationLocation {
1004                                section: "custom".to_string(),
1005                                field_path: "unknown".to_string(),
1006                                line_number: None,
1007                                column_number: None,
1008                            },
1009                            severity: ValidationSeverity::Medium,
1010                            expected: None,
1011                            actual: None,
1012                            suggestion: Some("Review custom validation rules".to_string()),
1013                            related_errors: Vec::new(),
1014                        });
1015                    }
1016                }
1017
1018                if self.config.fail_fast && !errors.is_empty() {
1019                    break;
1020                }
1021            }
1022        }
1023
1024        // Generate suggestions based on errors
1025        suggestions.extend(self.generate_suggestions(&errors, config));
1026
1027        // Determine validation status
1028        let status = if !errors.is_empty() {
1029            ValidationStatus::Invalid
1030        } else if !warnings.is_empty() {
1031            ValidationStatus::Warning
1032        } else {
1033            ValidationStatus::Valid
1034        };
1035
1036        // Create validation result
1037        let validation_time = start_time.elapsed();
1038        let result = ValidationResult {
1039            status,
1040            errors,
1041            warnings,
1042            suggestions,
1043            metrics: ValidationMetrics {
1044                validation_time,
1045                rules_checked,
1046                fields_validated: config.len(),
1047                cache_hit_rate: 0.0, // Would be calculated based on cache usage
1048                memory_usage: 0,     // Would be measured
1049            },
1050            timestamp: SystemTime::now(),
1051        };
1052
1053        // Cache result
1054        if self.config.enable_caching {
1055            self.validation_cache
1056                .write()
1057                .unwrap_or_else(|e| e.into_inner())
1058                .insert(config_hash, result.clone());
1059        }
1060
1061        // Transition to validated state
1062        let validated_validator = CompileTimeValidator {
1063            state: PhantomData,
1064            schema_validators: self.schema_validators,
1065            constraint_validators: self.constraint_validators,
1066            dependency_validators: self.dependency_validators,
1067            cross_reference_validators: self.cross_reference_validators,
1068            custom_validators: self.custom_validators,
1069            config: self.config,
1070            validation_cache: self.validation_cache,
1071        };
1072
1073        Ok((validated_validator, result))
1074    }
1075
1076    // Private helper methods
1077    fn compute_config_hash(&self, config: &HashMap<String, ConfigValue>) -> String {
1078        // Simple hash computation - would use a proper hash function in practice
1079        format!("hash_{}", config.len())
1080    }
1081
1082    fn generate_suggestions(
1083        &self,
1084        errors: &[ValidationError],
1085        config: &HashMap<String, ConfigValue>,
1086    ) -> Vec<ValidationSuggestion> {
1087        let mut suggestions = Vec::new();
1088
1089        for error in errors {
1090            match &error.category {
1091                ValidationErrorCategory::MissingRequired => {
1092                    suggestions.push(ValidationSuggestion {
1093                        suggestion_id: format!("add_required_{}", error.error_id),
1094                        message: format!("Add required field '{}'", error.location.field_path),
1095                        action: SuggestionAction::AddField {
1096                            field: error.location.field_path.clone(),
1097                            value: error
1098                                .expected
1099                                .clone()
1100                                .unwrap_or_else(|| "default_value".to_string()),
1101                        },
1102                        confidence: 0.9,
1103                        priority: SuggestionPriority::Critical,
1104                    });
1105                }
1106                ValidationErrorCategory::TypeMismatch => {
1107                    if let Some(expected) = &error.expected {
1108                        suggestions.push(ValidationSuggestion {
1109                            suggestion_id: format!("fix_type_{}", error.error_id),
1110                            message: format!(
1111                                "Convert field '{}' to type '{}'",
1112                                error.location.field_path, expected
1113                            ),
1114                            action: SuggestionAction::ModifyField {
1115                                field: error.location.field_path.clone(),
1116                                new_value: format!("convert_to_{expected}"),
1117                            },
1118                            confidence: 0.8,
1119                            priority: SuggestionPriority::High,
1120                        });
1121                    }
1122                }
1123                _ => {}
1124            }
1125        }
1126
1127        suggestions
1128    }
1129}
1130
1131impl CompileTimeValidator<Validated> {
1132    /// Create a validated configuration from raw config data
1133    pub fn create_validated_config<T>(&self, config: T) -> ValidatedPipelineConfig<T> {
1134        let validation_proof = ValidationProof {
1135            proof_id: format!(
1136                "proof_{}",
1137                SystemTime::now()
1138                    .duration_since(UNIX_EPOCH)
1139                    .unwrap_or_default()
1140                    .as_millis()
1141            ),
1142            validation_time: SystemTime::now(),
1143            validator_version: "1.0.0".to_string(),
1144            checksum: "validated".to_string(),
1145        };
1146
1147        /// ValidatedPipelineConfig
1148        ValidatedPipelineConfig {
1149            config,
1150            validation_proof,
1151            schema_version: "1.0.0".to_string(),
1152        }
1153    }
1154
1155    /// Get validation metrics
1156    #[must_use]
1157    pub fn get_validation_metrics(&self) -> ValidationMetrics {
1158        /// ValidationMetrics
1159        ValidationMetrics {
1160            validation_time: Duration::from_millis(0),
1161            rules_checked: 0,
1162            fields_validated: 0,
1163            cache_hit_rate: 0.0,
1164            memory_usage: 0,
1165        }
1166    }
1167}
1168
1169impl<T> ValidatedPipelineConfig<T> {
1170    /// Get the validated configuration
1171    pub fn config(&self) -> &T {
1172        &self.config
1173    }
1174
1175    /// Get the validation proof
1176    pub fn validation_proof(&self) -> &ValidationProof {
1177        &self.validation_proof
1178    }
1179
1180    /// Convert to another type while preserving validation
1181    pub fn map<U, F>(self, f: F) -> ValidatedPipelineConfig<U>
1182    where
1183        F: FnOnce(T) -> U,
1184    {
1185        /// ValidatedPipelineConfig
1186        ValidatedPipelineConfig {
1187            config: f(self.config),
1188            validation_proof: self.validation_proof,
1189            schema_version: self.schema_version,
1190        }
1191    }
1192}
1193
1194// Type-safe configuration builder implementation
1195
1196impl Default for TypeSafeConfigBuilder<Unbuilt> {
1197    fn default() -> Self {
1198        Self::new()
1199    }
1200}
1201
1202impl TypeSafeConfigBuilder<Unbuilt> {
1203    /// Create a new type-safe configuration builder
1204    #[must_use]
1205    pub fn new() -> Self {
1206        Self {
1207            state: PhantomData,
1208            config_data: HashMap::new(),
1209            type_constraints: HashMap::new(),
1210            validation_rules: Vec::new(),
1211            builder_config: BuilderConfig {
1212                strict_validation: true,
1213                allow_unknown_fields: false,
1214                max_nesting_depth: 5,
1215            },
1216        }
1217    }
1218
1219    /// Add a string field with validation
1220    pub fn string_field<T: Into<String>>(mut self, name: &str, value: T) -> Self {
1221        self.config_data
1222            .insert(name.to_string(), ConfigValue::String(value.into()));
1223        self.type_constraints.insert(
1224            name.to_string(),
1225            /// TypeConstraint
1226            TypeConstraint {
1227                expected_type: ConfigType::String,
1228                required: true,
1229                default_value: None,
1230                constraints: Vec::new(),
1231                custom_validator: None,
1232            },
1233        );
1234        self
1235    }
1236
1237    /// Add an integer field with validation
1238    #[must_use]
1239    pub fn integer_field(mut self, name: &str, value: i64) -> Self {
1240        self.config_data
1241            .insert(name.to_string(), ConfigValue::Integer(value));
1242        self.type_constraints.insert(
1243            name.to_string(),
1244            /// TypeConstraint
1245            TypeConstraint {
1246                expected_type: ConfigType::Integer,
1247                required: true,
1248                default_value: None,
1249                constraints: Vec::new(),
1250                custom_validator: None,
1251            },
1252        );
1253        self
1254    }
1255
1256    /// Add a float field with validation
1257    #[must_use]
1258    pub fn float_field(mut self, name: &str, value: f64) -> Self {
1259        self.config_data
1260            .insert(name.to_string(), ConfigValue::Float(value));
1261        self.type_constraints.insert(
1262            name.to_string(),
1263            /// TypeConstraint
1264            TypeConstraint {
1265                expected_type: ConfigType::Float,
1266                required: true,
1267                default_value: None,
1268                constraints: Vec::new(),
1269                custom_validator: None,
1270            },
1271        );
1272        self
1273    }
1274
1275    /// Add a boolean field with validation
1276    #[must_use]
1277    pub fn boolean_field(mut self, name: &str, value: bool) -> Self {
1278        self.config_data
1279            .insert(name.to_string(), ConfigValue::Boolean(value));
1280        self.type_constraints.insert(
1281            name.to_string(),
1282            /// TypeConstraint
1283            TypeConstraint {
1284                expected_type: ConfigType::Boolean,
1285                required: true,
1286                default_value: None,
1287                constraints: Vec::new(),
1288                custom_validator: None,
1289            },
1290        );
1291        self
1292    }
1293
1294    /// Add a constraint to a field
1295    #[must_use]
1296    pub fn with_constraint(mut self, field: &str, constraint: ValueConstraint) -> Self {
1297        if let Some(type_constraint) = self.type_constraints.get_mut(field) {
1298            type_constraint.constraints.push(constraint);
1299        }
1300        self
1301    }
1302
1303    /// Add a validation rule
1304    #[must_use]
1305    pub fn with_rule(mut self, rule: Box<dyn ValidationRule>) -> Self {
1306        self.validation_rules.push(rule);
1307        self
1308    }
1309
1310    /// Build the configuration with validation
1311    pub fn build(self) -> Result<TypeSafeConfigBuilder<Built>> {
1312        // Validate configuration
1313        for (field, constraint) in &self.type_constraints {
1314            if let Some(value) = self.config_data.get(field) {
1315                // Check type compatibility
1316                if !self.is_type_compatible(value, &constraint.expected_type) {
1317                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1318                        "Type mismatch for field '{}': expected {:?}, got {:?}",
1319                        field, constraint.expected_type, value
1320                    )));
1321                }
1322
1323                // Check constraints
1324                for value_constraint in &constraint.constraints {
1325                    self.validate_constraint(field, value, value_constraint)?;
1326                }
1327
1328                // Apply custom validator if present
1329                if let Some(ref validator) = constraint.custom_validator {
1330                    validator(value)
1331                        .map_err(|e| SklearsComposeError::InvalidConfiguration(e.to_string()))?;
1332                }
1333            } else if constraint.required {
1334                return Err(SklearsComposeError::InvalidConfiguration(format!(
1335                    "Required field '{field}' is missing"
1336                )));
1337            }
1338        }
1339
1340        // Apply validation rules
1341        for rule in &self.validation_rules {
1342            for (field, value) in &self.config_data {
1343                rule.apply(field, value)
1344                    .map_err(|e| SklearsComposeError::InvalidConfiguration(e.to_string()))?;
1345            }
1346        }
1347
1348        Ok(TypeSafeConfigBuilder {
1349            state: PhantomData,
1350            config_data: self.config_data,
1351            type_constraints: self.type_constraints,
1352            validation_rules: self.validation_rules,
1353            builder_config: self.builder_config,
1354        })
1355    }
1356
1357    // Helper methods
1358    fn is_type_compatible(&self, value: &ConfigValue, expected_type: &ConfigType) -> bool {
1359        match (value, expected_type) {
1360            (ConfigValue::String(_), ConfigType::String) => true,
1361            (ConfigValue::Integer(_), ConfigType::Integer) => true,
1362            (ConfigValue::Float(_), ConfigType::Float) => true,
1363            (ConfigValue::Boolean(_), ConfigType::Boolean) => true,
1364            (ConfigValue::Array(arr), ConfigType::Array(element_type)) => arr
1365                .iter()
1366                .all(|item| self.is_type_compatible(item, element_type)),
1367            (ConfigValue::Object(_), ConfigType::Object(_)) => true,
1368            (ConfigValue::Null, ConfigType::Optional(_)) => true,
1369            _ => false,
1370        }
1371    }
1372
1373    fn validate_constraint(
1374        &self,
1375        field: &str,
1376        value: &ConfigValue,
1377        constraint: &ValueConstraint,
1378    ) -> Result<()> {
1379        match constraint {
1380            ValueConstraint::Range { min, max } => {
1381                let numeric_value = match value {
1382                    ConfigValue::Integer(i) => *i as f64,
1383                    ConfigValue::Float(f) => *f,
1384                    _ => {
1385                        return Err(SklearsComposeError::InvalidConfiguration(format!(
1386                            "Range constraint can only be applied to numeric values in field '{field}'"
1387                        )));
1388                    }
1389                };
1390
1391                if numeric_value < *min || numeric_value > *max {
1392                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1393                        "Value {numeric_value} in field '{field}' is outside range [{min}, {max}]"
1394                    )));
1395                }
1396            }
1397            ValueConstraint::Length { min, max } => {
1398                let length = match value {
1399                    ConfigValue::String(s) => s.len(),
1400                    ConfigValue::Array(arr) => arr.len(),
1401                    _ => {
1402                        return Err(SklearsComposeError::InvalidConfiguration(
1403                            format!("Length constraint can only be applied to strings or arrays in field '{field}'")
1404                        ));
1405                    }
1406                };
1407
1408                if length < *min {
1409                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1410                        "Length {length} in field '{field}' is less than minimum {min}"
1411                    )));
1412                }
1413
1414                if let Some(max_len) = max {
1415                    if length > *max_len {
1416                        return Err(SklearsComposeError::InvalidConfiguration(format!(
1417                            "Length {length} in field '{field}' is greater than maximum {max_len}"
1418                        )));
1419                    }
1420                }
1421            }
1422            ValueConstraint::OneOf(allowed_values) => {
1423                if !allowed_values.contains(value) {
1424                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1425                        "Value in field '{field}' is not one of the allowed values"
1426                    )));
1427                }
1428            }
1429            ValueConstraint::Pattern(pattern) => {
1430                if let ConfigValue::String(s) = value {
1431                    // Simple pattern matching - would use regex in practice
1432                    if !s.contains(pattern) {
1433                        return Err(SklearsComposeError::InvalidConfiguration(format!(
1434                            "String in field '{field}' does not match pattern '{pattern}'"
1435                        )));
1436                    }
1437                } else {
1438                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1439                        "Pattern constraint can only be applied to strings in field '{field}'"
1440                    )));
1441                }
1442            }
1443            ValueConstraint::Custom(description) => {
1444                // Custom constraints would be implemented with proper validation logic
1445                // For now, just a placeholder
1446                println!("Custom constraint '{description}' applied to field '{field}'");
1447            }
1448        }
1449
1450        Ok(())
1451    }
1452}
1453
1454impl TypeSafeConfigBuilder<Built> {
1455    /// Get the validated configuration data
1456    #[must_use]
1457    pub fn config_data(&self) -> &HashMap<String, ConfigValue> {
1458        &self.config_data
1459    }
1460
1461    /// Extract configuration data
1462    #[must_use]
1463    pub fn into_config_data(self) -> HashMap<String, ConfigValue> {
1464        self.config_data
1465    }
1466}
1467
1468// Example schema and constraint validators
1469
1470/// Example schema validator for pipeline configurations
1471#[derive(Debug)]
1472pub struct PipelineSchemaValidator {
1473    schema: PipelineConfigurationSchema,
1474}
1475
1476impl Default for PipelineSchemaValidator {
1477    fn default() -> Self {
1478        Self::new()
1479    }
1480}
1481
1482impl PipelineSchemaValidator {
1483    #[must_use]
1484    pub fn new() -> Self {
1485        let mut required_fields = HashSet::new();
1486        required_fields.insert("model".to_string());
1487        required_fields.insert("pipeline".to_string());
1488
1489        let mut field_definitions = HashMap::new();
1490        field_definitions.insert(
1491            "model".to_string(),
1492            /// FieldDefinition
1493            FieldDefinition {
1494                field_type: ConfigType::Object(HashMap::new()),
1495                description: "Model configuration".to_string(),
1496                default: None,
1497                constraints: Vec::new(),
1498                deprecated: false,
1499                deprecation_message: None,
1500            },
1501        );
1502
1503        let schema = PipelineConfigurationSchema {
1504            version: "1.0.0".to_string(),
1505            required_fields,
1506            field_definitions,
1507            constraints: Vec::new(),
1508            cross_reference_rules: Vec::new(),
1509        };
1510
1511        Self { schema }
1512    }
1513}
1514
1515impl SchemaValidator for PipelineSchemaValidator {
1516    fn validate_schema(
1517        &self,
1518        config: &HashMap<String, ConfigValue>,
1519    ) -> Result<Vec<ValidationError>> {
1520        let mut errors = Vec::new();
1521
1522        // Check required fields
1523        for required_field in &self.schema.required_fields {
1524            if !config.contains_key(required_field) {
1525                errors.push(ValidationError {
1526                    error_id: format!("missing_required_{required_field}"),
1527                    category: ValidationErrorCategory::MissingRequired,
1528                    message: format!("Required field '{required_field}' is missing"),
1529                    location: ConfigurationLocation {
1530                        section: "root".to_string(),
1531                        field_path: required_field.clone(),
1532                        line_number: None,
1533                        column_number: None,
1534                    },
1535                    severity: ValidationSeverity::Critical,
1536                    expected: Some("required field".to_string()),
1537                    actual: Some("missing".to_string()),
1538                    suggestion: Some(format!("Add required field '{required_field}'")),
1539                    related_errors: Vec::new(),
1540                });
1541            }
1542        }
1543
1544        Ok(errors)
1545    }
1546
1547    fn schema_name(&self) -> &'static str {
1548        "PipelineSchema"
1549    }
1550
1551    fn schema_version(&self) -> &str {
1552        &self.schema.version
1553    }
1554}
1555
1556/// Example parameter constraint validator
1557#[derive(Debug)]
1558pub struct ParameterConstraintValidator;
1559
1560impl ConstraintValidator for ParameterConstraintValidator {
1561    fn validate_constraints(
1562        &self,
1563        config: &HashMap<String, ConfigValue>,
1564    ) -> Result<Vec<ValidationError>> {
1565        let mut errors = Vec::new();
1566
1567        // Example: validate learning rate is in valid range
1568        if let Some(ConfigValue::Object(model_config)) = config.get("model") {
1569            if let Some(ConfigValue::Float(learning_rate)) = model_config.get("learning_rate") {
1570                if *learning_rate <= 0.0 || *learning_rate > 1.0 {
1571                    errors.push(ValidationError {
1572                        error_id: "invalid_learning_rate".to_string(),
1573                        category: ValidationErrorCategory::RangeError,
1574                        message: "Learning rate must be between 0.0 and 1.0".to_string(),
1575                        location: ConfigurationLocation {
1576                            section: "model".to_string(),
1577                            field_path: "learning_rate".to_string(),
1578                            line_number: None,
1579                            column_number: None,
1580                        },
1581                        severity: ValidationSeverity::High,
1582                        expected: Some("0.0 < learning_rate <= 1.0".to_string()),
1583                        actual: Some(learning_rate.to_string()),
1584                        suggestion: Some(
1585                            "Set learning rate to a value between 0.001 and 0.1".to_string(),
1586                        ),
1587                        related_errors: Vec::new(),
1588                    });
1589                }
1590            }
1591        }
1592
1593        Ok(errors)
1594    }
1595
1596    fn validator_name(&self) -> &'static str {
1597        "ParameterConstraintValidator"
1598    }
1599}
1600
1601/// Example validation rule
1602#[derive(Debug)]
1603pub struct NonEmptyStringRule;
1604
1605impl ValidationRule for NonEmptyStringRule {
1606    fn apply(&self, field: &str, value: &ConfigValue) -> Result<()> {
1607        if let ConfigValue::String(s) = value {
1608            if s.is_empty() {
1609                return Err(format!("String field '{field}' cannot be empty").into());
1610            }
1611        }
1612        Ok(())
1613    }
1614
1615    fn rule_name(&self) -> &'static str {
1616        "NonEmptyStringRule"
1617    }
1618}
1619
1620// Convenience macros for compile-time validation
1621
1622/// Macro for creating enhanced validated configurations
1623#[macro_export]
1624macro_rules! enhanced_validated_config {
1625    ($($key:expr => $value:expr),*) => {{
1626        let mut config = std::collections::HashMap::new();
1627        $(
1628            config.insert($key.to_string(), $value);
1629        )*
1630        config
1631    }};
1632}
1633
1634/// Macro for type-safe configuration building
1635#[macro_export]
1636macro_rules! type_safe_config {
1637    (
1638        $($field:ident: $type:ident = $value:expr),*
1639    ) => {{
1640        let builder = TypeSafeConfigBuilder::new();
1641        $(
1642            let builder = match stringify!($type) {
1643                "String" => builder.string_field(stringify!($field), $value),
1644                "Integer" => builder.integer_field(stringify!($field), $value),
1645                "Float" => builder.float_field(stringify!($field), $value),
1646                "Boolean" => builder.boolean_field(stringify!($field), $value),
1647                _ => panic!("Unsupported type: {}", stringify!($type)),
1648            };
1649        )*
1650        builder.build()
1651    }};
1652}
1653
1654#[allow(non_snake_case)]
1655#[cfg(test)]
1656mod tests {
1657    use super::*;
1658
1659    #[test]
1660    fn test_validator_creation() {
1661        let validator = CompileTimeValidator::<Unvalidated>::new();
1662        assert!(validator.config.strict_type_checking);
1663    }
1664
1665    #[test]
1666    fn test_schema_validation() {
1667        let validator = CompileTimeValidator::<Unvalidated>::new()
1668            .add_schema_validator(Box::new(PipelineSchemaValidator::new()));
1669
1670        let mut config = HashMap::new();
1671        config.insert("model".to_string(), ConfigValue::Object(HashMap::new()));
1672        config.insert("pipeline".to_string(), ConfigValue::Object(HashMap::new()));
1673
1674        let result = validator.validate(&config);
1675        assert!(result.is_ok());
1676
1677        let (_, validation_result) = result.expect("operation should succeed");
1678        assert!(matches!(validation_result.status, ValidationStatus::Valid));
1679    }
1680
1681    #[test]
1682    fn test_constraint_validation() {
1683        let validator = CompileTimeValidator::<Unvalidated>::new()
1684            .add_constraint_validator(Box::new(ParameterConstraintValidator));
1685
1686        let mut model_config = HashMap::new();
1687        model_config.insert("learning_rate".to_string(), ConfigValue::Float(2.0)); // Invalid
1688
1689        let mut config = HashMap::new();
1690        config.insert("model".to_string(), ConfigValue::Object(model_config));
1691
1692        let result = validator.validate(&config);
1693        assert!(result.is_ok());
1694
1695        let (_, validation_result) = result.expect("operation should succeed");
1696        assert!(matches!(
1697            validation_result.status,
1698            ValidationStatus::Invalid
1699        ));
1700        assert!(!validation_result.errors.is_empty());
1701    }
1702
1703    #[test]
1704    fn test_type_safe_builder() {
1705        let builder = TypeSafeConfigBuilder::new()
1706            .string_field("name", "test_pipeline")
1707            .float_field("learning_rate", 0.01)
1708            .integer_field("epochs", 100)
1709            .boolean_field("verbose", true)
1710            .with_constraint(
1711                "learning_rate",
1712                ValueConstraint::Range { min: 0.0, max: 1.0 },
1713            )
1714            .with_rule(Box::new(NonEmptyStringRule));
1715
1716        let result = builder.build();
1717        assert!(result.is_ok());
1718
1719        let built_config = result.expect("operation should succeed");
1720        assert_eq!(built_config.config_data().len(), 4);
1721    }
1722
1723    #[test]
1724    fn test_validated_config_creation() {
1725        let validator = CompileTimeValidator::<Unvalidated>::new();
1726        let config = HashMap::new();
1727
1728        let (validated_validator, _) = validator
1729            .validate(&config)
1730            .expect("operation should succeed");
1731        let validated_config = validated_validator.create_validated_config(config);
1732
1733        assert!(validated_config
1734            .validation_proof()
1735            .proof_id
1736            .starts_with("proof_"));
1737    }
1738
1739    #[test]
1740    fn test_validation_errors() {
1741        let validator = CompileTimeValidator::<Unvalidated>::new()
1742            .add_schema_validator(Box::new(PipelineSchemaValidator::new()));
1743
1744        let config = HashMap::new(); // Missing required fields
1745
1746        let result = validator.validate(&config);
1747        assert!(result.is_ok());
1748
1749        let (_, validation_result) = result.expect("operation should succeed");
1750        assert!(matches!(
1751            validation_result.status,
1752            ValidationStatus::Invalid
1753        ));
1754        assert!(validation_result.errors.len() >= 2); // Missing "model" and "pipeline"
1755    }
1756
1757    #[test]
1758    fn test_config_value_types() {
1759        assert!(matches!(
1760            ConfigValue::String("test".to_string()),
1761            ConfigValue::String(_)
1762        ));
1763        assert!(matches!(ConfigValue::Integer(42), ConfigValue::Integer(_)));
1764        assert!(matches!(ConfigValue::Float(3.14), ConfigValue::Float(_)));
1765        assert!(matches!(
1766            ConfigValue::Boolean(true),
1767            ConfigValue::Boolean(_)
1768        ));
1769    }
1770
1771    #[test]
1772    fn test_validation_suggestions() {
1773        let validator = CompileTimeValidator::<Unvalidated>::new()
1774            .add_schema_validator(Box::new(PipelineSchemaValidator::new()));
1775
1776        let config = HashMap::new();
1777
1778        let (_, validation_result) = validator
1779            .validate(&config)
1780            .expect("operation should succeed");
1781        assert!(!validation_result.suggestions.is_empty());
1782
1783        let suggestion = &validation_result.suggestions[0];
1784        assert!(matches!(suggestion.priority, SuggestionPriority::Critical));
1785    }
1786
1787    #[test]
1788    fn test_constraint_range() {
1789        let builder = TypeSafeConfigBuilder::new()
1790            .float_field("value", 150.0)
1791            .with_constraint(
1792                "value",
1793                ValueConstraint::Range {
1794                    min: 0.0,
1795                    max: 100.0,
1796                },
1797            );
1798
1799        let result = builder.build();
1800        assert!(result.is_err());
1801    }
1802
1803    #[test]
1804    fn test_constraint_length() {
1805        let builder = TypeSafeConfigBuilder::new()
1806            .string_field("name", "a") // Too short
1807            .with_constraint(
1808                "name",
1809                ValueConstraint::Length {
1810                    min: 3,
1811                    max: Some(10),
1812                },
1813            );
1814
1815        let result = builder.build();
1816        assert!(result.is_err());
1817    }
1818}