Skip to main content

scirs2_core/validation/
cross_platform.rs

1//! Cross-platform validation utilities for consistent behavior across operating systems and architectures.
2//!
3//! This module provides validation utilities that handle platform-specific differences
4//! in numeric formats, file systems, memory models, and hardware capabilities to ensure
5//! consistent behavior across Windows, macOS, Linux, and different CPU architectures.
6
7use crate::error::{CoreError, CoreResult, ErrorContext};
8use crate::validation::production::{
9    ValidationContext, ValidationError, ValidationResult, ValidationSeverity,
10};
11use std::collections::HashMap;
12
13/// Platform information detected at runtime
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct PlatformInfo {
16    /// Operating system family
17    pub os_family: OsFamily,
18    /// CPU architecture
19    pub arch: CpuArchitecture,
20    /// Available SIMD instruction sets
21    pub simd_support: SimdSupport,
22    /// Endianness of the target platform
23    pub endianness: Endianness,
24    /// Native path separator
25    pub path_separator: char,
26    /// Maximum file path length
27    pub max_path_length: usize,
28    /// Default memory page size
29    pub page_size: usize,
30    /// Whether the platform supports memory-mapped files
31    pub memory_mapping_support: bool,
32    /// Default floating-point precision behavior
33    pub fp_behavior: FloatingPointBehavior,
34}
35
36/// Operating system families
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum OsFamily {
39    Windows,
40    Unix, // Linux, macOS, BSD, etc.
41    Wasm, // WebAssembly runtime
42    Unknown,
43}
44
45/// CPU architecture types
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum CpuArchitecture {
48    X86_64,
49    AArch64, // ARM64
50    X86,     // 32-bit x86
51    ARM,     // 32-bit ARM
52    RISCV64,
53    PowerPC64,
54    Wasm32, // WebAssembly 32-bit
55    Wasm64, // WebAssembly 64-bit
56    Other(u32),
57}
58
59/// SIMD instruction set support
60#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct SimdSupport {
62    /// SSE support levels (x86/x64)
63    pub sse: Option<SseLevel>,
64    /// AVX support levels (x86/x64)
65    pub avx: Option<AvxLevel>,
66    /// NEON support (ARM)
67    pub neon: bool,
68    /// SVE support (ARM)
69    pub sve: bool,
70    /// Vector extension support level
71    pub vector_width: usize,
72}
73
74/// SSE instruction set levels
75#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
76pub enum SseLevel {
77    Sse,
78    Sse2,
79    Sse3,
80    Ssse3,
81    Sse41,
82    Sse42,
83}
84
85/// AVX instruction set levels
86#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
87pub enum AvxLevel {
88    Avx,
89    Avx2,
90    Avx512f,
91    Avx512bw,
92    Avx512dq,
93}
94
95/// Platform endianness
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum Endianness {
98    Little,
99    Big,
100}
101
102/// Floating-point behavior characteristics
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct FloatingPointBehavior {
105    /// Whether denormal numbers are supported
106    pub denormals_supported: bool,
107    /// Default rounding mode
108    pub rounding_mode: RoundingMode,
109    /// Whether NaN propagation is IEEE 754 compliant
110    pub nan_propagation: bool,
111    /// Whether infinity is supported
112    pub infinity_supported: bool,
113}
114
115/// Floating-point rounding modes
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum RoundingMode {
118    ToNearest,
119    TowardZero,
120    TowardPositiveInfinity,
121    TowardNegativeInfinity,
122}
123
124/// Cross-platform validator with platform-aware validation rules
125pub struct CrossPlatformValidator {
126    /// Current platform information
127    platform_info: PlatformInfo,
128    /// Validation context
129    #[allow(dead_code)]
130    context: ValidationContext,
131    /// Cached validation results for performance
132    cache: HashMap<String, ValidationResult>,
133}
134
135impl CrossPlatformValidator {
136    /// Create a new cross-platform validator
137    pub fn new() -> CoreResult<Self> {
138        let platform_info = Self::detect_platform_info()?;
139        Ok(Self {
140            platform_info,
141            context: ValidationContext::default(),
142            cache: HashMap::new(),
143        })
144    }
145
146    /// Create a validator with custom context
147    pub fn with_context(context: ValidationContext) -> CoreResult<Self> {
148        let platform_info = Self::detect_platform_info()?;
149        Ok(Self {
150            platform_info,
151            context,
152            cache: HashMap::new(),
153        })
154    }
155
156    /// Detect platform information at runtime
157    fn detect_platform_info() -> CoreResult<PlatformInfo> {
158        let os_family = if cfg!(target_family = "wasm") {
159            OsFamily::Wasm
160        } else if cfg!(windows) {
161            OsFamily::Windows
162        } else if cfg!(unix) {
163            OsFamily::Unix
164        } else {
165            OsFamily::Unknown
166        };
167
168        let arch = if cfg!(target_arch = "wasm32") {
169            CpuArchitecture::Wasm32
170        } else if cfg!(target_arch = "wasm64") {
171            CpuArchitecture::Wasm64
172        } else if cfg!(target_arch = "x86_64") {
173            CpuArchitecture::X86_64
174        } else if cfg!(target_arch = "aarch64") {
175            CpuArchitecture::AArch64
176        } else if cfg!(target_arch = "x86") {
177            CpuArchitecture::X86
178        } else if cfg!(target_arch = "arm") {
179            CpuArchitecture::ARM
180        } else if cfg!(target_arch = "riscv64") {
181            CpuArchitecture::RISCV64
182        } else if cfg!(target_arch = "powerpc64") {
183            CpuArchitecture::PowerPC64
184        } else {
185            CpuArchitecture::Other(0)
186        };
187
188        let endianness = if cfg!(target_endian = "little") {
189            Endianness::Little
190        } else {
191            Endianness::Big
192        };
193
194        let path_separator = if cfg!(windows) {
195            '\\'
196        } else {
197            '/' // Unix-style paths for all non-Windows platforms (including WASM)
198        };
199
200        let max_path_length = if cfg!(target_family = "wasm") {
201            1024 // Conservative limit for WASM environments
202        } else if cfg!(windows) {
203            260 // MAX_PATH on Windows (unless long path support is enabled)
204        } else {
205            4096 // Common limit on Unix systems
206        };
207
208        // Detect SIMD support
209        let simd_support = Self::detect_simd_support(arch);
210
211        // Detect system page size
212        let page_size = Self::detect_page_size();
213
214        let memory_mapping_support = !cfg!(target_family = "wasm");
215
216        let fp_behavior = FloatingPointBehavior {
217            denormals_supported: true, // Most modern platforms support denormals
218            rounding_mode: RoundingMode::ToNearest,
219            nan_propagation: true,
220            infinity_supported: true,
221        };
222
223        Ok(PlatformInfo {
224            os_family,
225            arch,
226            simd_support,
227            endianness,
228            path_separator,
229            max_path_length,
230            page_size,
231            memory_mapping_support,
232            fp_behavior,
233        })
234    }
235
236    /// Detect SIMD instruction set support
237    fn detect_simd_support(arch: CpuArchitecture) -> SimdSupport {
238        match arch {
239            CpuArchitecture::X86_64 | CpuArchitecture::X86 => {
240                // For x86/x64, we'd normally use cpuid to detect features
241                // For now, provide conservative defaults
242                SimdSupport {
243                    sse: Some(SseLevel::Sse2), // SSE2 is guaranteed on x64
244                    avx: if cfg!(target_feature = "avx2") {
245                        Some(AvxLevel::Avx2)
246                    } else if cfg!(target_feature = "avx") {
247                        Some(AvxLevel::Avx)
248                    } else {
249                        None
250                    },
251                    neon: false,
252                    sve: false,
253                    vector_width: if cfg!(target_feature = "avx512f") {
254                        512
255                    } else if cfg!(target_feature = "avx2") {
256                        256
257                    } else {
258                        128
259                    },
260                }
261            }
262            CpuArchitecture::AArch64 | CpuArchitecture::ARM => {
263                SimdSupport {
264                    sse: None,
265                    avx: None,
266                    neon: true,        // NEON is standard on ARM64
267                    sve: false,        // SVE detection would require runtime checks
268                    vector_width: 128, // Default ARM NEON width
269                }
270            }
271            CpuArchitecture::Wasm32 | CpuArchitecture::Wasm64 => {
272                SimdSupport {
273                    sse: None,
274                    avx: None,
275                    neon: false,
276                    sve: false,
277                    vector_width: if cfg!(target_feature = "simd128") {
278                        128 // WASM SIMD128 support
279                    } else {
280                        64 // No SIMD support
281                    },
282                }
283            }
284            _ => {
285                SimdSupport {
286                    sse: None,
287                    avx: None,
288                    neon: false,
289                    sve: false,
290                    vector_width: 64, // Conservative default
291                }
292            }
293        }
294    }
295
296    /// Detect system page size
297    fn detect_page_size() -> usize {
298        #[cfg(unix)]
299        {
300            // Most Unix systems use 4KB pages, with some using 64KB (especially ARM64)
301            // For simplicity, we'll use 4KB as default since it's most common
302            4096
303        }
304        #[cfg(windows)]
305        {
306            // Windows typically uses 4KB pages, but can be 64KB on some systems
307            // For simplicity, use the common default
308            4096
309        }
310        #[cfg(not(any(unix, windows)))]
311        {
312            4096 // Default page size
313        }
314    }
315
316    /// Validate a file path for the current platform
317    pub fn validate_file_path(&mut self, path: &str) -> ValidationResult {
318        let mut result = ValidationResult {
319            is_valid: true,
320            errors: Vec::new(),
321            warnings: Vec::new(),
322            metrics: crate::validation::production::ValidationMetrics::default(),
323        };
324
325        // Check path length limits
326        if path.len() > self.platform_info.max_path_length {
327            result.is_valid = false;
328            result.errors.push(ValidationError {
329                code: "PATH_TOO_LONG".to_string(),
330                message: format!(
331                    "Path length {} exceeds platform maximum of {}",
332                    path.len(),
333                    self.platform_info.max_path_length
334                ),
335                field: Some(path.to_string()),
336                suggestion: Some("Use shorter path or enable long path support ".to_string()),
337                severity: ValidationSeverity::Error,
338            });
339        }
340
341        // Platform-specific path validation
342        match self.platform_info.os_family {
343            OsFamily::Windows => self.validate_windows_path(path, &mut result),
344            OsFamily::Unix => self.validate_unix_path(path, &mut result),
345            OsFamily::Wasm => self.validate_wasm_path(path, &mut result),
346            OsFamily::Unknown => {
347                result
348                    .warnings
349                    .push("Unknown platform - basic validation only ".to_string());
350            }
351        }
352
353        // Check for null bytes (invalid on all platforms)
354        if path.contains('\0') {
355            result.is_valid = false;
356            result.errors.push(ValidationError {
357                code: "NULL_BYTE_IN_PATH".to_string(),
358                message: "Path contains null byte ".to_string(),
359                field: Some(path.to_string()),
360                suggestion: Some("Remove null bytes from path ".to_string()),
361                severity: ValidationSeverity::Critical,
362            });
363        }
364
365        result
366    }
367
368    /// Validate Windows-specific path constraints
369    fn validate_windows_path(&self, path: &str, result: &mut ValidationResult) {
370        // A leading drive specifier (`C:`) is the one legal use of ':' in a
371        // Windows path, so strip it before scanning for invalid characters —
372        // otherwise every absolute Windows path is reported as invalid.
373        let scan_target = match path.as_bytes() {
374            [drive, b':', ..] if drive.is_ascii_alphabetic() => &path[2..],
375            _ => path,
376        };
377
378        // Check for invalid characters
379        let invalid_chars = r#"<>:"|?*"#.chars().collect::<Vec<_>>();
380        for &ch in &invalid_chars {
381            if scan_target.contains(ch) {
382                result.is_valid = false;
383                result.errors.push(ValidationError {
384                    code: "INVALID_WINDOWS_CHAR".to_string(),
385                    message: format!("Character '{ch}' is invalid in Windows paths"),
386                    field: Some(path.to_string()),
387                    suggestion: Some("Remove or replace invalid characters".to_string()),
388                    severity: ValidationSeverity::Error,
389                });
390                break;
391            }
392        }
393
394        // Check for reserved names
395        let reserved_names = [
396            "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
397            "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
398        ];
399
400        let path_upper = path.to_uppercase();
401        for &reserved in &reserved_names {
402            if path_upper == reserved || path_upper.starts_with(&format!("{reserved}.")) {
403                result.is_valid = false;
404                result.errors.push(ValidationError {
405                    code: "RESERVED_WINDOWS_NAME".to_string(),
406                    message: format!("'{reserved}' is a reserved name on Windows"),
407                    field: Some(path.to_string()),
408                    suggestion: Some("Use a different filename".to_string()),
409                    severity: ValidationSeverity::Error,
410                });
411                break;
412            }
413        }
414
415        // Check for trailing spaces or periods
416        if path.ends_with(' ') || path.ends_with('.') {
417            result.is_valid = false;
418            result.errors.push(ValidationError {
419                code: "INVALID_WINDOWS_ENDING".to_string(),
420                message: "Windows paths cannot end with spaces or periods".to_string(),
421                field: Some(path.to_string()),
422                suggestion: Some("Remove trailing spaces or periods".to_string()),
423                severity: ValidationSeverity::Error,
424            });
425        }
426    }
427
428    /// Validate Unix-specific path constraints
429    fn validate_unix_path(&self, path: &str, result: &mut ValidationResult) {
430        // Unix paths are generally more permissive, but check for some edge cases
431
432        // Check for double slashes (while technically valid, often unintended)
433        if path.contains("//") {
434            result
435                .warnings
436                .push("Path contains double slashes".to_string());
437        }
438
439        // Check if path starts with /dev/, /proc/, or /sys/ - potentially dangerous
440        let system_prefixes = ["/dev/", "/proc/", "/sys/"];
441        for &prefix in &system_prefixes {
442            if path.starts_with(prefix) {
443                result.warnings.push(format!(
444                    "Path accesses system directory '{prefix}' - ensure this is intended"
445                ));
446                break;
447            }
448        }
449
450        // Check for very long path components (while Unix supports long names,
451        // some filesystems have limits)
452        for component in path.split('/') {
453            if component.len() > 255 {
454                result
455                    .warnings
456                    .push("Path component exceeds 255 characters".to_string());
457                break;
458            }
459        }
460    }
461
462    /// Validate WebAssembly-specific path constraints
463    fn validate_wasm_path(&self, path: &str, result: &mut ValidationResult) {
464        // WebAssembly has very limited file system access
465
466        // Check if path is attempting to access outside the sandbox
467        if path.starts_with("../") || path.contains("/../") {
468            result.is_valid = false;
469            result.errors.push(ValidationError {
470                code: "WASM_SANDBOX_VIOLATION".to_string(),
471                message: "WebAssembly paths cannot escape sandbox with '..'".to_string(),
472                field: Some(path.to_string()),
473                suggestion: Some("Use paths relative to the WASM module".to_string()),
474                severity: ValidationSeverity::Critical,
475            });
476        }
477
478        // Check for absolute paths (typically not allowed in WASM)
479        if path.starts_with('/') {
480            result.warnings.push(
481                "Absolute paths may not be accessible in WebAssembly environment".to_string(),
482            );
483        }
484
485        // Check for special protocols that might not work in WASM
486        let special_prefixes = ["file://", "http://", "https://", "ftp://"];
487        for &prefix in &special_prefixes {
488            if path.starts_with(prefix) {
489                result.warnings.push(format!(
490                    "Protocol '{prefix}' may not be accessible in WebAssembly environment"
491                ));
492                break;
493            }
494        }
495
496        // WASM has stricter limits on path components
497        for component in path.split('/') {
498            if component.len() > 128 {
499                result.warnings.push(
500                    "Very long path components may not be supported in WebAssembly".to_string(),
501                );
502                break;
503            }
504        }
505
506        // Check for WASM-specific virtual file system conventions
507        if path.starts_with("/tmp/") || path.starts_with("/temp/") {
508            result.warnings.push(
509                "Temporary directories may have limited persistence in WebAssembly".to_string(),
510            );
511        }
512
513        // General warning about WASM file system limitations
514        result
515            .warnings
516            .push("WebAssembly environment has limited file system access".to_string());
517    }
518
519    /// Validate numeric value considering platform-specific floating-point behavior
520    pub fn validate_numeric_cross_platform<T>(
521        &mut self,
522        value: T,
523        fieldname: &str,
524    ) -> ValidationResult
525    where
526        T: PartialOrd + Copy + std::fmt::Debug + std::fmt::Display + 'static,
527    {
528        let mut result = ValidationResult {
529            is_valid: true,
530            errors: Vec::new(),
531            warnings: Vec::new(),
532            metrics: crate::validation::production::ValidationMetrics::default(),
533        };
534
535        // Check for platform-specific numeric issues
536        if std::any::TypeId::of::<T>() == std::any::TypeId::of::<f32>()
537            || std::any::TypeId::of::<T>() == std::any::TypeId::of::<f64>()
538        {
539            self.validate_floating_point_value(&value, fieldname, &mut result);
540        }
541
542        // Check for endianness-sensitive operations
543        if self.platform_info.endianness == Endianness::Big {
544            result.warnings.push(
545                "Running on big-endian platform - verify binary data compatibility".to_string(),
546            );
547        }
548
549        result
550    }
551
552    /// Validate floating-point value considering platform behavior
553    fn validate_floating_point_value<T>(
554        &self,
555        value: &T,
556        fieldname: &str,
557        result: &mut ValidationResult,
558    ) where
559        T: std::fmt::Debug + std::fmt::Display,
560    {
561        // This is a simplified check - in practice we'd need unsafe transmutation
562        // to properly inspect the floating-point representation
563        let value_str = format!("{value:?}");
564
565        if value_str.contains("inf") && !self.platform_info.fp_behavior.infinity_supported {
566            result.is_valid = false;
567            result.errors.push(ValidationError {
568                code: "INFINITY_NOT_SUPPORTED".to_string(),
569                message: format!("Infinity values not supported on this platform for {fieldname}"),
570                field: Some(fieldname.to_string()),
571                suggestion: Some("Use finite values only".to_string()),
572                severity: ValidationSeverity::Error,
573            });
574        }
575
576        if value_str.contains("nan") && !self.platform_info.fp_behavior.nan_propagation {
577            result.warnings.push(format!(
578                "NaN value in {fieldname} - platform may not handle NaN propagation correctly"
579            ));
580        }
581    }
582
583    /// Validate SIMD operation compatibility
584    pub fn validate_simd_operation(
585        &mut self,
586        operation: &str,
587        _data_size: usize,
588        vector_size: usize,
589    ) -> ValidationResult {
590        let mut result = ValidationResult {
591            is_valid: true,
592            errors: Vec::new(),
593            warnings: Vec::new(),
594            metrics: crate::validation::production::ValidationMetrics::default(),
595        };
596
597        // Check if requested vector size is supported
598        if vector_size > self.platform_info.simd_support.vector_width {
599            result.is_valid = false;
600            result.errors.push(ValidationError {
601                code: "SIMD_VECTOR_TOO_LARGE".to_string(),
602                message: format!(
603                    "Requested vector size {} exceeds platform maximum of {}",
604                    vector_size, self.platform_info.simd_support.vector_width
605                ),
606                field: Some(vector_size.to_string()),
607                suggestion: Some(format!(
608                    "Use vector size <= {}",
609                    self.platform_info.simd_support.vector_width
610                )),
611                severity: ValidationSeverity::Error,
612            });
613        }
614
615        // Check operation-specific requirements
616        if operation.contains("avx") && self.platform_info.simd_support.avx.is_none() {
617            result.is_valid = false;
618            result.errors.push(ValidationError {
619                code: "AVX_NOT_SUPPORTED".to_string(),
620                message: "AVX instructions not supported on this platform".to_string(),
621                field: Some(operation.to_string()),
622                suggestion: Some("Use SSE fallback or check platform capabilities".to_string()),
623                severity: ValidationSeverity::Error,
624            });
625        }
626
627        if operation.contains("neon") && !self.platform_info.simd_support.neon {
628            result.is_valid = false;
629            result.errors.push(ValidationError {
630                code: "NEON_NOT_SUPPORTED".to_string(),
631                message: "NEON instructions not supported on this platform".to_string(),
632                field: Some(operation.to_string()),
633                suggestion: Some("Use scalar fallback".to_string()),
634                severity: ValidationSeverity::Error,
635            });
636        }
637
638        result
639    }
640
641    /// Validate memory allocation size considering platform limits
642    pub fn validate_memory_allocation(&mut self, size: usize, purpose: &str) -> ValidationResult {
643        let mut result = ValidationResult {
644            is_valid: true,
645            errors: Vec::new(),
646            warnings: Vec::new(),
647            metrics: crate::validation::production::ValidationMetrics::default(),
648        };
649
650        // Check if allocation is aligned to page size for optimal performance
651        if size > self.platform_info.page_size && size % self.platform_info.page_size != 0 {
652            result.warnings.push(format!(
653                "Allocation size {} is not page-aligned (page size: {})",
654                size, self.platform_info.page_size
655            ));
656        }
657
658        // Platform-specific memory limits
659        let max_alloc_size = match self.platform_info.arch {
660            CpuArchitecture::X86 => 2usize.pow(31), // 2GB limit for 32-bit
661            CpuArchitecture::ARM => 2usize.pow(31),
662            CpuArchitecture::Wasm32 => 2usize.pow(31), // WASM32 has 32-bit address space
663            CpuArchitecture::Wasm64 => {
664                // WASM64 is limited by browser memory constraints
665                4usize.pow(30) // 1GB conservative limit for WASM64
666            }
667            _ => usize::MAX, // 64-bit platforms
668        };
669
670        if size > max_alloc_size {
671            result.is_valid = false;
672            result.errors.push(ValidationError {
673                code: "ALLOCATION_TOO_LARGE".to_string(),
674                message: format!(
675                    "Allocation size {size} exceeds platform maximum of {max_alloc_size} for {purpose}"
676                ),
677                field: Some(size.to_string()),
678                suggestion: Some("Reduce allocation size or use memory mapping".to_string()),
679                severity: ValidationSeverity::Error,
680            });
681        }
682
683        // Check if memory mapping is needed but not supported
684        if size > 100_000_000 && !self.platform_info.memory_mapping_support {
685            result.warnings.push(format!(
686                "Large allocation ({size} bytes) for {purpose} but memory mapping not supported"
687            ));
688        }
689
690        result
691    }
692
693    /// Get current platform information
694    pub fn platform_info(&self) -> &PlatformInfo {
695        &self.platform_info
696    }
697
698    /// Clear validation cache
699    pub fn clear_cache(&mut self) {
700        self.cache.clear();
701    }
702
703    /// Check if a specific platform feature is available
704    pub fn is_feature_available(&self, feature: PlatformFeature) -> bool {
705        match feature {
706            PlatformFeature::MemoryMapping => self.platform_info.memory_mapping_support,
707            PlatformFeature::Avx => self.platform_info.simd_support.avx.is_some(),
708            PlatformFeature::Neon => self.platform_info.simd_support.neon,
709            PlatformFeature::LongPaths => {
710                // This would require more sophisticated detection in practice
711                matches!(self.platform_info.os_family, OsFamily::Unix)
712            }
713            PlatformFeature::DenormalNumbers => self.platform_info.fp_behavior.denormals_supported,
714            PlatformFeature::WasmSimd128 => {
715                matches!(
716                    self.platform_info.arch,
717                    CpuArchitecture::Wasm32 | CpuArchitecture::Wasm64
718                ) && self.platform_info.simd_support.vector_width >= 128
719            }
720            PlatformFeature::ThreadSupport => {
721                // WASM traditionally doesn't support threads, but some environments do
722                !matches!(self.platform_info.os_family, OsFamily::Wasm)
723            }
724            PlatformFeature::FileSystemAccess => {
725                // WASM has very limited file system access
726                !matches!(self.platform_info.os_family, OsFamily::Wasm)
727            }
728        }
729    }
730}
731
732/// Platform features that can be queried
733#[derive(Debug, Clone, Copy, PartialEq, Eq)]
734pub enum PlatformFeature {
735    MemoryMapping,
736    Avx,
737    Neon,
738    LongPaths,
739    DenormalNumbers,
740    WasmSimd128,
741    ThreadSupport,
742    FileSystemAccess,
743}
744
745impl Default for CrossPlatformValidator {
746    fn default() -> Self {
747        Self::new().expect("Failed to create cross-platform validator")
748    }
749}
750
751/// Convenience functions for common cross-platform validations
752/// Validate that a path is appropriate for the current platform
753#[allow(dead_code)]
754pub fn validate_path(path: &str) -> CoreResult<()> {
755    let mut validator = CrossPlatformValidator::new()?;
756    let result = validator.validate_file_path(path);
757
758    if result.is_valid {
759        Ok(())
760    } else {
761        Err(CoreError::ValidationError(ErrorContext::new(format!(
762            "Path validation failed: {:?}",
763            result.errors
764        ))))
765    }
766}
767
768/// Validate SIMD capability for an operation
769#[allow(dead_code)]
770pub fn validate_simd_capability(operation: &str, size: usize) -> CoreResult<()> {
771    let mut validator = CrossPlatformValidator::new()?;
772    let result = validator.validate_simd_operation(operation, size, 128);
773
774    if result.is_valid {
775        Ok(())
776    } else {
777        Err(CoreError::ValidationError(ErrorContext::new(format!(
778            "SIMD validation failed: {:?}",
779            result.errors
780        ))))
781    }
782}
783
784/// Get platform information
785#[allow(dead_code)]
786pub fn get_platform_info() -> CoreResult<PlatformInfo> {
787    CrossPlatformValidator::detect_platform_info()
788}
789
790#[cfg(test)]
791mod tests {
792    use super::*;
793
794    #[test]
795    fn test_platform_detection() {
796        let info = CrossPlatformValidator::detect_platform_info().expect("Operation failed");
797
798        // Basic sanity checks
799        assert_ne!(info.os_family, OsFamily::Unknown);
800        assert!(info.page_size > 0);
801        assert!(info.max_path_length > 0);
802        assert!(info.simd_support.vector_width > 0);
803    }
804
805    #[test]
806    fn test_path_validation() {
807        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
808
809        // Valid path
810        let result = validator.validate_file_path("/home/user/data.txt");
811        assert!(result.is_valid);
812
813        // Path with null byte
814        let result = validator.validate_file_path("/home/user\0/data.txt");
815        assert!(!result.is_valid);
816    }
817
818    #[cfg(windows)]
819    #[test]
820    fn test_windows_path_validation() {
821        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
822
823        // Valid Windows path
824        let result = validator.validate_file_path("C:\\Users\\user\\data.txt");
825        assert!(result.is_valid);
826
827        // Invalid character
828        let result = validator.validate_file_path("C:\\Users\\user<data.txt");
829        assert!(!result.is_valid);
830
831        // Reserved name
832        let result = validator.validate_file_path("CON");
833        assert!(!result.is_valid);
834    }
835
836    #[cfg(unix)]
837    #[test]
838    fn test_unix_path_validation() {
839        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
840
841        // Valid Unix path
842        let result = validator.validate_file_path("/home/user/data.txt");
843        assert!(result.is_valid);
844
845        // System directory warning
846        let result = validator.validate_file_path("/dev/null");
847        assert!(result.is_valid);
848        assert!(!result.warnings.is_empty());
849    }
850
851    #[test]
852    fn test_simd_validation() {
853        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
854
855        // Valid vector size
856        let result = validator.validate_simd_operation("add", 128, 128);
857        assert!(result.is_valid);
858
859        // Too large vector size
860        let result = validator.validate_simd_operation("add", 10000, 10000);
861        assert!(!result.is_valid);
862    }
863
864    #[test]
865    fn test_memory_allocation_validation() {
866        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
867
868        // Normal allocation
869        let result = validator.validate_memory_allocation(1024, "test");
870        assert!(result.is_valid);
871
872        // Very large allocation
873        let result = validator.validate_memory_allocation(usize::MAX - 1, "test");
874        // Result depends on platform - 32-bit will fail, 64-bit might succeed
875    }
876
877    #[test]
878    fn test_feature_availability() {
879        let validator = CrossPlatformValidator::new().expect("Operation failed");
880
881        // These should return boolean values without panicking
882        let memory_mapping = validator.is_feature_available(PlatformFeature::MemoryMapping);
883        let avx = validator.is_feature_available(PlatformFeature::Avx);
884        let neon = validator.is_feature_available(PlatformFeature::Neon);
885    }
886
887    #[test]
888    fn test_convenience_functions() {
889        // These should not panic
890        let _ = validate_path("/tmp/test.txt");
891        let _ = validate_simd_capability("add", 128);
892        let _ = get_platform_info();
893    }
894
895    #[test]
896    fn test_wasm_specific_features() {
897        let validator = CrossPlatformValidator::new().expect("Operation failed");
898
899        // Test WASM-specific feature detection
900        let wasm_simd = validator.is_feature_available(PlatformFeature::WasmSimd128);
901        let thread_support = validator.is_feature_available(PlatformFeature::ThreadSupport);
902        let fs_access = validator.is_feature_available(PlatformFeature::FileSystemAccess);
903
904        // These should return boolean values without panicking
905        // Test passes if we reach here without panicking
906    }
907
908    #[test]
909    fn test_wasm_path_validation() {
910        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
911
912        // Simulate WASM environment for testing
913        // Note: This test will behave differently on actual WASM vs native platforms
914
915        // Test relative path (should be okay in WASM)
916        let result = validator.validate_file_path("data/input.txt");
917        // Should be valid but may have warnings in WASM
918
919        // Test sandbox escape attempt
920        let result = validator.validate_file_path("../../../etc/passwd");
921        // This would be rejected in actual WASM validation
922
923        // Just ensure these don't panic
924        // Test passes if we reach here without panicking
925    }
926
927    #[test]
928    fn test_platform_memory_limits() {
929        let validator = CrossPlatformValidator::new().expect("Operation failed");
930
931        // Test that memory allocation validation considers platform architecture
932        let small_alloc = validator.platform_info().page_size * 2;
933        let large_alloc = 2usize.pow(30); // 1GB
934
935        // These should not panic
936        let mut validator_mut = CrossPlatformValidator::new().expect("Operation failed");
937        let small_result = validator_mut.validate_memory_allocation(small_alloc, "test");
938        let large_result = validator_mut.validate_memory_allocation(large_alloc, "test");
939
940        // Test passes if we reach here without panicking
941    }
942
943    #[test]
944    fn test_simd_capabilities_cross_platform() {
945        let mut validator = CrossPlatformValidator::new().expect("Operation failed");
946
947        // Test SIMD validation across different architectures
948        let result = validator.validate_simd_operation("generic_add", 64, 64);
949        assert!(result.is_valid); // Should be supported on all platforms
950
951        let result = validator.validate_simd_operation("avx2_multiply", 256, 256);
952        // Result depends on platform - should not panic
953
954        let result = validator.validate_simd_operation("neon_add", 128, 128);
955        // Result depends on platform - should not panic
956
957        // Test passes if we reach here without panicking
958    }
959}