Skip to main content

torsh_data/
utils.rs

1//! Common utilities to reduce code duplication across modules
2
3use torsh_core::error::{Result, TorshError};
4
5/// Utility macros for common patterns
6///
7/// This module provides macros and functions to eliminate repetitive code
8/// patterns found throughout the torsh-data crate.
9/// Validate probability value is in [0, 1] range
10pub fn validate_probability(prob: f32, name: &str) -> Result<()> {
11    if !(0.0..=1.0).contains(&prob) {
12        return Err(TorshError::InvalidArgument(format!(
13            "{name} must be between 0 and 1, got {prob}"
14        )));
15    }
16    Ok(())
17}
18
19/// Validate that a range is valid (min <= max)
20pub fn validate_range<T: PartialOrd + std::fmt::Debug>(range: (T, T), name: &str) -> Result<()> {
21    if range.0 > range.1 {
22        return Err(TorshError::InvalidArgument(format!(
23            "Invalid {name} range: {range:?}"
24        )));
25    }
26    Ok(())
27}
28
29/// Validate that a value is positive
30pub fn validate_positive<T: PartialOrd + Default + std::fmt::Debug>(
31    value: T,
32    name: &str,
33) -> Result<()> {
34    if value <= T::default() {
35        return Err(TorshError::InvalidArgument(format!(
36            "{name} must be positive, got {value:?}"
37        )));
38    }
39    Ok(())
40}
41
42/// Validate that vectors have the same length
43pub fn validate_same_length<T, U>(vec1: &[T], vec2: &[U], name1: &str, name2: &str) -> Result<()> {
44    if vec1.len() != vec2.len() {
45        return Err(TorshError::InvalidArgument(format!(
46            "{} and {} must have the same length, got {} and {}",
47            name1,
48            name2,
49            vec1.len(),
50            vec2.len()
51        )));
52    }
53    Ok(())
54}
55
56/// Validate that a vector is not empty
57pub fn validate_not_empty<T>(vec: &[T], name: &str) -> Result<()> {
58    if vec.is_empty() {
59        return Err(TorshError::InvalidArgument(format!(
60            "{name} cannot be empty"
61        )));
62    }
63    Ok(())
64}
65
66/// Error utilities for common error patterns
67pub mod errors {
68    use torsh_core::error::TorshError;
69
70    /// Create an invalid index error
71    pub fn invalid_index(index: usize, size: usize) -> TorshError {
72        TorshError::IndexError { index, size }
73    }
74
75    /// Create an invalid argument error
76    pub fn invalid_argument(msg: impl Into<String>) -> TorshError {
77        TorshError::InvalidArgument(msg.into())
78    }
79
80    /// Create a configuration error
81    pub fn config_error(msg: impl Into<String>) -> TorshError {
82        TorshError::InvalidArgument(msg.into())
83    }
84
85    /// Create an empty batch error
86    pub fn empty_batch() -> TorshError {
87        TorshError::InvalidArgument("Cannot process empty batch".to_string())
88    }
89
90    /// Create a shape mismatch error
91    pub fn shape_mismatch(expected: &[usize], got: &[usize]) -> TorshError {
92        TorshError::ShapeMismatch {
93            expected: expected.to_vec(),
94            got: got.to_vec(),
95        }
96    }
97
98    /// Create a file not found error
99    pub fn file_not_found(path: &std::path::Path) -> TorshError {
100        TorshError::InvalidArgument(format!("File not found: {}", path.display()))
101    }
102
103    /// Create an invalid format error
104    pub fn invalid_format(expected: &str, got: &str) -> TorshError {
105        TorshError::InvalidArgument(format!("Expected {expected} format, got {got}"))
106    }
107}
108
109/// Macro to create a simple constructor with validation
110#[macro_export]
111macro_rules! validated_constructor {
112    // Constructor with single probability validation
113    ($name:ident, $field:ident: f32, probability) => {
114        impl $name {
115            /// Create a new instance
116            pub fn new($field: f32) -> Result<Self> {
117                $crate::utils::validate_probability($field, stringify!($field))?;
118                Ok(Self { $field })
119            }
120        }
121    };
122
123    // Constructor with range validation
124    ($name:ident, $field:ident: ($t1:ty, $t2:ty), range) => {
125        impl $name {
126            /// Create a new instance
127            pub fn new($field: ($t1, $t2)) -> Result<Self> {
128                $crate::utils::validate_range($field, stringify!($field))?;
129                Ok(Self { $field })
130            }
131        }
132    };
133
134    // Constructor with positive validation
135    ($name:ident, $field:ident: $t:ty, positive) => {
136        impl $name {
137            /// Create a new instance
138            pub fn new($field: $t) -> Result<Self> {
139                $crate::utils::validate_positive($field, stringify!($field))?;
140                Ok(Self { $field })
141            }
142        }
143    };
144
145    // Constructor with size tuple (for image operations)
146    ($name:ident, size: ($t1:ty, $t2:ty)) => {
147        impl $name {
148            /// Create a new instance
149            pub fn new(size: ($t1, $t2)) -> Self {
150                Self { size }
151            }
152        }
153    };
154
155    // Constructor with custom validation
156    ($name:ident, $($field:ident: $t:ty),+, validate = $validator:expr) => {
157        impl $name {
158            /// Create a new instance
159            pub fn new($($field: $t),+) -> Result<Self> {
160                $validator(&$($field),+)?;
161                Ok(Self { $($field),+ })
162            }
163        }
164    };
165}
166
167/// Macro to create builder patterns with fluent interface
168#[macro_export]
169macro_rules! builder_pattern {
170    ($name:ident, $($field:ident: $t:ty),+) => {
171        // Note: This macro would generate methods like with_field_name
172        // For now, users should implement builders manually for better control
173        // Example:
174        // impl MyStruct {
175        //     pub fn with_field(mut self, field: Type) -> Self {
176        //         self.field = field;
177        //         self
178        //     }
179        // }
180    };
181}
182
183/// Common transform implementation macro
184#[macro_export]
185macro_rules! simple_random_transform {
186    ($name:ident, $input:ty, $output:ty, $prob_field:ident, $transform_fn:expr) => {
187        impl $crate::transforms::Transform<$input> for $name {
188            type Output = $output;
189
190            fn transform(&self, input: $input) -> Result<Self::Output> {
191                // ✅ SciRS2 Policy Compliant - Using scirs2_core::random instead of direct rand
192                use scirs2_core::random::{Random, Rng};
193                let mut rng = Random::seed(42);
194
195                if rng.random::<f32>() < self.$prob_field {
196                    $transform_fn(input, &mut rng)
197                } else {
198                    Ok(input)
199                }
200            }
201
202            fn is_deterministic(&self) -> bool {
203                false
204            }
205        }
206    };
207}
208
209/// Common dataset path validation
210pub fn validate_dataset_path(path: &std::path::Path, name: &str) -> Result<()> {
211    if !path.exists() {
212        return Err(TorshError::InvalidArgument(format!(
213            "{} path does not exist: {}",
214            name,
215            path.display()
216        )));
217    }
218    Ok(())
219}
220
221/// Common file extension validation
222pub fn validate_file_extension(path: &std::path::Path, extensions: &[&str]) -> Result<()> {
223    if let Some(ext) = path.extension() {
224        let ext_str = ext.to_string_lossy().to_lowercase();
225        if extensions.iter().any(|&e| e == ext_str) {
226            return Ok(());
227        }
228    }
229
230    Err(TorshError::InvalidArgument(format!(
231        "File must have one of these extensions: {:?}, got: {}",
232        extensions,
233        path.display()
234    )))
235}
236
237/// Common tensor shape validation
238pub fn validate_tensor_shape(shape: &[usize], expected_dims: usize, name: &str) -> Result<()> {
239    if shape.len() != expected_dims {
240        return Err(TorshError::InvalidArgument(format!(
241            "{} tensor must have {} dimensions, got {}",
242            name,
243            expected_dims,
244            shape.len()
245        )));
246    }
247    Ok(())
248}
249
250/// Helper for creating size tuples with validation
251pub fn create_size_tuple(width: usize, height: usize) -> Result<(usize, usize)> {
252    validate_positive(width, "width")?;
253    validate_positive(height, "height")?;
254    Ok((width, height))
255}
256
257/// Utility traits for common functionality
258pub trait Resettable {
259    /// Reset to initial state
260    fn reset(&mut self);
261}
262
263pub trait Configurable<T> {
264    /// Configure with settings
265    fn configure(&mut self, config: T) -> Result<()>;
266}
267
268pub trait Cacheable {
269    /// Clear any cached data
270    fn clear_cache(&mut self);
271
272    /// Get cache hit rate if applicable
273    fn cache_hit_rate(&self) -> Option<f32> {
274        None
275    }
276}
277
278/// Helper for progress tracking
279pub struct ProgressTracker {
280    current: usize,
281    total: usize,
282    last_reported: f32,
283    report_interval: f32,
284}
285
286impl ProgressTracker {
287    /// Create a new progress tracker
288    pub fn new(total: usize) -> Self {
289        Self {
290            current: 0,
291            total,
292            last_reported: 0.0,
293            report_interval: 0.1, // Report every 10%
294        }
295    }
296
297    /// Update progress and return true if should report
298    pub fn update(&mut self) -> bool {
299        self.current += 1;
300        let progress = self.current as f32 / self.total as f32;
301
302        if progress - self.last_reported >= self.report_interval {
303            self.last_reported = progress;
304            true
305        } else {
306            false
307        }
308    }
309
310    /// Get current progress as percentage
311    pub fn percentage(&self) -> f32 {
312        (self.current as f32 / self.total as f32) * 100.0
313    }
314
315    /// Check if completed
316    pub fn is_complete(&self) -> bool {
317        self.current >= self.total
318    }
319}
320
321/// Performance measurement utilities
322pub mod performance {
323    use std::collections::VecDeque;
324    use std::time::{Duration, Instant};
325
326    /// Simple performance timer
327    pub struct Timer {
328        start: Instant,
329        measurements: VecDeque<Duration>,
330        max_samples: usize,
331    }
332
333    impl Timer {
334        /// Create a new timer
335        pub fn new() -> Self {
336            Self {
337                start: Instant::now(),
338                measurements: VecDeque::new(),
339                max_samples: 100,
340            }
341        }
342
343        /// Start timing
344        pub fn start(&mut self) {
345            self.start = Instant::now();
346        }
347
348        /// Stop timing and record measurement
349        pub fn stop(&mut self) -> Duration {
350            let duration = self.start.elapsed();
351
352            if self.measurements.len() >= self.max_samples {
353                self.measurements.pop_front();
354            }
355            self.measurements.push_back(duration);
356
357            duration
358        }
359
360        /// Get average measurement
361        pub fn average(&self) -> Option<Duration> {
362            if self.measurements.is_empty() {
363                None
364            } else {
365                let total: Duration = self.measurements.iter().sum();
366                Some(total / self.measurements.len() as u32)
367            }
368        }
369
370        /// Get throughput in items per second
371        pub fn throughput(&self, items: usize) -> Option<f64> {
372            self.average().map(|avg| items as f64 / avg.as_secs_f64())
373        }
374    }
375
376    impl Default for Timer {
377        fn default() -> Self {
378            Self::new()
379        }
380    }
381}
382
383/// Memory management utilities
384pub mod memory {
385    use std::collections::HashMap;
386    use std::sync::{Arc, Mutex};
387
388    /// Simple memory pool for reusing allocations
389    pub struct MemoryPool<T> {
390        available: Vec<Vec<T>>,
391        capacity: usize,
392        default_size: usize,
393    }
394
395    impl<T: Clone + Default> MemoryPool<T> {
396        /// Create a new memory pool
397        pub fn new(capacity: usize, default_size: usize) -> Self {
398            Self {
399                available: Vec::with_capacity(capacity),
400                capacity,
401                default_size,
402            }
403        }
404
405        /// Get a buffer from the pool
406        pub fn get(&mut self) -> Vec<T> {
407            self.available
408                .pop()
409                .unwrap_or_else(|| Vec::with_capacity(self.default_size))
410        }
411
412        /// Return a buffer to the pool
413        pub fn put(&mut self, mut buffer: Vec<T>) {
414            if self.available.len() < self.capacity {
415                buffer.clear();
416                self.available.push(buffer);
417            }
418        }
419
420        /// Get current pool size
421        pub fn size(&self) -> usize {
422            self.available.len()
423        }
424    }
425
426    /// Thread-safe memory pool
427    pub type SharedMemoryPool<T> = Arc<Mutex<MemoryPool<T>>>;
428
429    /// Memory usage tracker
430    pub struct MemoryTracker {
431        allocations: HashMap<String, usize>,
432        peak_memory: usize,
433        current_memory: usize,
434    }
435
436    impl MemoryTracker {
437        /// Create a new memory tracker
438        pub fn new() -> Self {
439            Self {
440                allocations: HashMap::new(),
441                peak_memory: 0,
442                current_memory: 0,
443            }
444        }
445
446        /// Record an allocation
447        pub fn allocate(&mut self, name: &str, size: usize) {
448            self.current_memory += size;
449            self.peak_memory = self.peak_memory.max(self.current_memory);
450            *self.allocations.entry(name.to_string()).or_insert(0) += size;
451        }
452
453        /// Record a deallocation
454        pub fn deallocate(&mut self, name: &str, size: usize) {
455            self.current_memory = self.current_memory.saturating_sub(size);
456            if let Some(total) = self.allocations.get_mut(name) {
457                *total = total.saturating_sub(size);
458            }
459        }
460
461        /// Get current memory usage
462        pub fn current_usage(&self) -> usize {
463            self.current_memory
464        }
465
466        /// Get peak memory usage
467        pub fn peak_usage(&self) -> usize {
468            self.peak_memory
469        }
470
471        /// Get memory usage breakdown
472        pub fn breakdown(&self) -> &HashMap<String, usize> {
473            &self.allocations
474        }
475    }
476
477    impl Default for MemoryTracker {
478        fn default() -> Self {
479            Self::new()
480        }
481    }
482}
483
484/// Batch processing utilities
485pub mod batch {
486    // ✅ SciRS2 POLICY: Use scirs2_core::parallel_ops instead of rayon::prelude
487    use scirs2_core::parallel_ops::*;
488    use std::sync::mpsc;
489    use std::thread;
490
491    /// Process data in parallel batches
492    pub fn parallel_batch_process<T, R, F>(data: Vec<T>, batch_size: usize, processor: F) -> Vec<R>
493    where
494        T: Send + Sync,
495        R: Send,
496        F: Fn(&[T]) -> R + Send + Sync,
497    {
498        data.par_chunks(batch_size).map(processor).collect()
499    }
500
501    /// Async batch processor with channels
502    pub struct AsyncBatchProcessor<T, R> {
503        sender: mpsc::Sender<Vec<T>>,
504        receiver: mpsc::Receiver<R>,
505        _handle: thread::JoinHandle<()>,
506    }
507
508    impl<T, R> AsyncBatchProcessor<T, R>
509    where
510        T: Send + 'static,
511        R: Send + 'static,
512    {
513        /// Create a new async batch processor
514        pub fn new<F>(batch_size: usize, processor: F) -> Self
515        where
516            F: Fn(Vec<T>) -> R + Send + 'static,
517        {
518            let (input_sender, input_receiver) = mpsc::channel();
519            let (output_sender, output_receiver) = mpsc::channel();
520
521            let handle = thread::spawn(move || {
522                let mut buffer = Vec::with_capacity(batch_size);
523
524                while let Ok(mut data) = input_receiver.recv() {
525                    buffer.append(&mut data);
526
527                    while buffer.len() >= batch_size {
528                        let batch = buffer.drain(..batch_size).collect();
529                        let result = processor(batch);
530                        if output_sender.send(result).is_err() {
531                            break;
532                        }
533                    }
534                }
535
536                // Process remaining data
537                if !buffer.is_empty() {
538                    let result = processor(buffer);
539                    let _ = output_sender.send(result);
540                }
541            });
542
543            Self {
544                sender: input_sender,
545                receiver: output_receiver,
546                _handle: handle,
547            }
548        }
549
550        /// Send data for processing
551        pub fn send(&self, data: Vec<T>) -> Result<(), mpsc::SendError<Vec<T>>> {
552            self.sender.send(data)
553        }
554
555        /// Receive processed results
556        pub fn recv(&self) -> Result<R, mpsc::RecvError> {
557            self.receiver.recv()
558        }
559
560        /// Try to receive without blocking
561        pub fn try_recv(&self) -> Result<R, mpsc::TryRecvError> {
562            self.receiver.try_recv()
563        }
564    }
565}
566
567/// Concurrent utilities for thread-safe operations
568pub mod concurrent {
569    use parking_lot::{Mutex, RwLock};
570    use std::collections::HashMap;
571    use std::sync::Arc;
572
573    /// Thread-safe cache with concurrent access
574    pub struct ConcurrentCache<K, V>
575    where
576        K: Eq + std::hash::Hash,
577    {
578        data: Arc<RwLock<HashMap<K, V>>>,
579        max_size: usize,
580    }
581
582    impl<K, V> ConcurrentCache<K, V>
583    where
584        K: Eq + std::hash::Hash + Clone,
585        V: Clone,
586    {
587        /// Create a new concurrent cache
588        pub fn new(max_size: usize) -> Self {
589            Self {
590                data: Arc::new(RwLock::new(HashMap::new())),
591                max_size,
592            }
593        }
594
595        /// Get a value from the cache
596        pub fn get(&self, key: &K) -> Option<V> {
597            self.data.read().get(key).cloned()
598        }
599
600        /// Insert a value into the cache
601        pub fn insert(&self, key: K, value: V) {
602            let mut data = self.data.write();
603
604            // Simple eviction if at capacity
605            if data.len() >= self.max_size && !data.contains_key(&key) {
606                if let Some(first_key) = data.keys().next().cloned() {
607                    data.remove(&first_key);
608                }
609            }
610
611            data.insert(key, value);
612        }
613
614        /// Remove a value from the cache
615        pub fn remove(&self, key: &K) -> Option<V> {
616            self.data.write().remove(key)
617        }
618
619        /// Clear the cache
620        pub fn clear(&self) {
621            self.data.write().clear();
622        }
623
624        /// Get cache size
625        pub fn len(&self) -> usize {
626            self.data.read().len()
627        }
628
629        /// Check if cache is empty
630        pub fn is_empty(&self) -> bool {
631            self.data.read().is_empty()
632        }
633    }
634
635    /// Thread-safe statistics collector
636    pub struct StatisticsCollector {
637        data: Arc<Mutex<Vec<f64>>>,
638        max_samples: usize,
639    }
640
641    impl StatisticsCollector {
642        /// Create a new statistics collector
643        pub fn new(max_samples: usize) -> Self {
644            Self {
645                data: Arc::new(Mutex::new(Vec::new())),
646                max_samples,
647            }
648        }
649
650        /// Add a sample
651        pub fn add_sample(&self, value: f64) {
652            let mut data = self.data.lock();
653            if data.len() >= self.max_samples {
654                data.remove(0);
655            }
656            data.push(value);
657        }
658
659        /// Get mean
660        pub fn mean(&self) -> Option<f64> {
661            let data = self.data.lock();
662            if data.is_empty() {
663                None
664            } else {
665                Some(data.iter().sum::<f64>() / data.len() as f64)
666            }
667        }
668
669        /// Get standard deviation
670        pub fn std_dev(&self) -> Option<f64> {
671            let data = self.data.lock();
672            if data.len() < 2 {
673                None
674            } else {
675                let mean = data.iter().sum::<f64>() / data.len() as f64;
676                let variance =
677                    data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (data.len() - 1) as f64;
678                Some(variance.sqrt())
679            }
680        }
681
682        /// Get min and max
683        pub fn min_max(&self) -> Option<(f64, f64)> {
684            let data = self.data.lock();
685            if data.is_empty() {
686                None
687            } else {
688                let min = data.iter().fold(f64::INFINITY, |a, &b| a.min(b));
689                let max = data.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
690                Some((min, max))
691            }
692        }
693
694        /// Get sample count
695        pub fn count(&self) -> usize {
696            self.data.lock().len()
697        }
698    }
699}
700
701/// Configuration management utilities
702pub mod config {
703    use std::collections::HashMap;
704    use std::env;
705    use std::path::Path;
706
707    #[cfg(feature = "serialize")]
708    use std::fs;
709    use torsh_core::error::{Result, TorshError};
710
711    #[cfg(feature = "serialize")]
712    use serde::{Deserialize, Serialize};
713
714    /// Configuration manager for handling settings from multiple sources
715    pub struct ConfigManager {
716        values: HashMap<String, ConfigValue>,
717        env_prefix: String,
718    }
719
720    /// Represents different types of configuration values
721    #[derive(Debug, Clone, PartialEq)]
722    #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
723    pub enum ConfigValue {
724        String(String),
725        Integer(i64),
726        Float(f64),
727        Boolean(bool),
728        Array(Vec<ConfigValue>),
729        Object(HashMap<String, ConfigValue>),
730    }
731
732    impl ConfigValue {
733        /// Convert to string if possible
734        pub fn as_string(&self) -> Option<&str> {
735            match self {
736                ConfigValue::String(s) => Some(s),
737                _ => None,
738            }
739        }
740
741        /// Convert to integer if possible
742        pub fn as_i64(&self) -> Option<i64> {
743            match self {
744                ConfigValue::Integer(i) => Some(*i),
745                _ => None,
746            }
747        }
748
749        /// Convert to float if possible
750        pub fn as_f64(&self) -> Option<f64> {
751            match self {
752                ConfigValue::Float(f) => Some(*f),
753                ConfigValue::Integer(i) => Some(*i as f64),
754                _ => None,
755            }
756        }
757
758        /// Convert to boolean if possible
759        pub fn as_bool(&self) -> Option<bool> {
760            match self {
761                ConfigValue::Boolean(b) => Some(*b),
762                _ => None,
763            }
764        }
765
766        /// Convert to array if possible
767        pub fn as_array(&self) -> Option<&Vec<ConfigValue>> {
768            match self {
769                ConfigValue::Array(arr) => Some(arr),
770                _ => None,
771            }
772        }
773
774        /// Convert to object if possible
775        pub fn as_object(&self) -> Option<&HashMap<String, ConfigValue>> {
776            match self {
777                ConfigValue::Object(obj) => Some(obj),
778                _ => None,
779            }
780        }
781    }
782
783    impl ConfigManager {
784        /// Create a new configuration manager
785        pub fn new() -> Self {
786            Self {
787                values: HashMap::new(),
788                env_prefix: "TORSH_".to_string(),
789            }
790        }
791
792        /// Create a new configuration manager with custom environment prefix
793        pub fn with_env_prefix(prefix: &str) -> Self {
794            Self {
795                values: HashMap::new(),
796                env_prefix: prefix.to_string(),
797            }
798        }
799
800        /// Load configuration from JSON file
801        #[cfg(feature = "serialize")]
802        pub fn load_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
803            let content = fs::read_to_string(path).map_err(|e| {
804                TorshError::InvalidArgument(format!("Failed to read config file: {}", e))
805            })?;
806
807            let json_value: serde_json::Value = serde_json::from_str(&content)
808                .map_err(|e| TorshError::InvalidArgument(format!("Failed to parse JSON: {}", e)))?;
809
810            self.load_from_json_value("", &json_value);
811            Ok(())
812        }
813
814        /// Load configuration from JSON file (feature-gated fallback)
815        #[cfg(not(feature = "serialize"))]
816        pub fn load_from_file<P: AsRef<Path>>(&mut self, _path: P) -> Result<()> {
817            Err(TorshError::InvalidArgument(
818                "JSON loading requires 'serialize' feature. Enable with --features serialize"
819                    .to_string(),
820            ))
821        }
822
823        /// Load configuration from environment variables
824        pub fn load_from_env(&mut self) {
825            for (key, value) in env::vars() {
826                if key.starts_with(&self.env_prefix) {
827                    let config_key = key
828                        .strip_prefix(&self.env_prefix)
829                        .expect("prefix exists as checked in starts_with")
830                        .to_lowercase();
831                    self.set_from_string(&config_key, &value);
832                }
833            }
834        }
835
836        /// Set a configuration value
837        pub fn set(&mut self, key: &str, value: ConfigValue) {
838            self.values.insert(key.to_string(), value);
839        }
840
841        /// Get a configuration value
842        pub fn get(&self, key: &str) -> Option<&ConfigValue> {
843            self.values.get(key)
844        }
845
846        /// Get a string value with default
847        pub fn get_string(&self, key: &str, default: &str) -> String {
848            self.get(key)
849                .and_then(|v| v.as_string())
850                .unwrap_or(default)
851                .to_string()
852        }
853
854        /// Get an integer value with default
855        pub fn get_i64(&self, key: &str, default: i64) -> i64 {
856            self.get(key).and_then(|v| v.as_i64()).unwrap_or(default)
857        }
858
859        /// Get a float value with default
860        pub fn get_f64(&self, key: &str, default: f64) -> f64 {
861            self.get(key).and_then(|v| v.as_f64()).unwrap_or(default)
862        }
863
864        /// Get a boolean value with default
865        pub fn get_bool(&self, key: &str, default: bool) -> bool {
866            self.get(key).and_then(|v| v.as_bool()).unwrap_or(default)
867        }
868
869        /// Check if a key exists
870        pub fn contains_key(&self, key: &str) -> bool {
871            self.values.contains_key(key)
872        }
873
874        /// Get all configuration keys
875        pub fn keys(&self) -> Vec<&String> {
876            self.values.keys().collect()
877        }
878
879        /// Clear all configuration
880        pub fn clear(&mut self) {
881            self.values.clear();
882        }
883
884        /// Merge configuration from another manager
885        pub fn merge(&mut self, other: &ConfigManager) {
886            for (key, value) in &other.values {
887                self.values.insert(key.clone(), value.clone());
888            }
889        }
890
891        /// Set value from string representation
892        fn set_from_string(&mut self, key: &str, value: &str) {
893            // Try to parse as different types
894            if let Ok(b) = value.parse::<bool>() {
895                self.set(key, ConfigValue::Boolean(b));
896            } else if let Ok(i) = value.parse::<i64>() {
897                self.set(key, ConfigValue::Integer(i));
898            } else if let Ok(f) = value.parse::<f64>() {
899                self.set(key, ConfigValue::Float(f));
900            } else {
901                self.set(key, ConfigValue::String(value.to_string()));
902            }
903        }
904
905        /// Load from JSON value recursively
906        #[cfg(feature = "serialize")]
907        fn load_from_json_value(&mut self, prefix: &str, value: &serde_json::Value) {
908            match value {
909                serde_json::Value::String(s) => {
910                    self.set(prefix, ConfigValue::String(s.clone()));
911                }
912                serde_json::Value::Number(n) => {
913                    if let Some(i) = n.as_i64() {
914                        self.set(prefix, ConfigValue::Integer(i));
915                    } else if let Some(f) = n.as_f64() {
916                        self.set(prefix, ConfigValue::Float(f));
917                    }
918                }
919                serde_json::Value::Bool(b) => {
920                    self.set(prefix, ConfigValue::Boolean(*b));
921                }
922                serde_json::Value::Array(arr) => {
923                    let config_arr: Vec<ConfigValue> = arr
924                        .iter()
925                        .map(|v| self.json_value_to_config_value(v))
926                        .collect();
927                    self.set(prefix, ConfigValue::Array(config_arr));
928                }
929                serde_json::Value::Object(obj) => {
930                    for (key, val) in obj {
931                        let new_key = if prefix.is_empty() {
932                            key.clone()
933                        } else {
934                            format!("{}.{}", prefix, key)
935                        };
936                        self.load_from_json_value(&new_key, val);
937                    }
938                }
939                serde_json::Value::Null => {}
940            }
941        }
942
943        /// Convert JSON value to ConfigValue
944        #[cfg(feature = "serialize")]
945        fn json_value_to_config_value(&self, value: &serde_json::Value) -> ConfigValue {
946            match value {
947                serde_json::Value::String(s) => ConfigValue::String(s.clone()),
948                serde_json::Value::Number(n) => {
949                    if let Some(i) = n.as_i64() {
950                        ConfigValue::Integer(i)
951                    } else if let Some(f) = n.as_f64() {
952                        ConfigValue::Float(f)
953                    } else {
954                        ConfigValue::String(n.to_string())
955                    }
956                }
957                serde_json::Value::Bool(b) => ConfigValue::Boolean(*b),
958                serde_json::Value::Array(arr) => {
959                    let config_arr: Vec<ConfigValue> = arr
960                        .iter()
961                        .map(|v| self.json_value_to_config_value(v))
962                        .collect();
963                    ConfigValue::Array(config_arr)
964                }
965                serde_json::Value::Object(obj) => {
966                    let mut config_obj = HashMap::new();
967                    for (key, val) in obj {
968                        config_obj.insert(key.clone(), self.json_value_to_config_value(val));
969                    }
970                    ConfigValue::Object(config_obj)
971                }
972                serde_json::Value::Null => ConfigValue::String("null".to_string()),
973            }
974        }
975    }
976
977    impl Default for ConfigManager {
978        fn default() -> Self {
979            Self::new()
980        }
981    }
982
983    /// Configuration builder for fluent API
984    pub struct ConfigBuilder {
985        manager: ConfigManager,
986    }
987
988    impl ConfigBuilder {
989        /// Create a new config builder
990        pub fn new() -> Self {
991            Self {
992                manager: ConfigManager::new(),
993            }
994        }
995
996        /// Set environment prefix
997        pub fn env_prefix(mut self, prefix: &str) -> Self {
998            self.manager.env_prefix = prefix.to_string();
999            self
1000        }
1001
1002        /// Load from file
1003        #[cfg(feature = "serialize")]
1004        pub fn file<P: AsRef<Path>>(mut self, path: P) -> Result<Self> {
1005            self.manager.load_from_file(path)?;
1006            Ok(self)
1007        }
1008
1009        /// Load from file (feature-gated fallback)
1010        #[cfg(not(feature = "serialize"))]
1011        pub fn file<P: AsRef<Path>>(self, _path: P) -> Result<Self> {
1012            Err(TorshError::InvalidArgument(
1013                "JSON file loading requires 'serialize' feature. Enable with --features serialize"
1014                    .to_string(),
1015            ))
1016        }
1017
1018        /// Load from environment
1019        pub fn env(mut self) -> Self {
1020            self.manager.load_from_env();
1021            self
1022        }
1023
1024        /// Set a value
1025        pub fn set(mut self, key: &str, value: ConfigValue) -> Self {
1026            self.manager.set(key, value);
1027            self
1028        }
1029
1030        /// Set a string value
1031        pub fn set_string(mut self, key: &str, value: &str) -> Self {
1032            self.manager
1033                .set(key, ConfigValue::String(value.to_string()));
1034            self
1035        }
1036
1037        /// Set an integer value
1038        pub fn set_i64(mut self, key: &str, value: i64) -> Self {
1039            self.manager.set(key, ConfigValue::Integer(value));
1040            self
1041        }
1042
1043        /// Set a float value
1044        pub fn set_f64(mut self, key: &str, value: f64) -> Self {
1045            self.manager.set(key, ConfigValue::Float(value));
1046            self
1047        }
1048
1049        /// Set a boolean value
1050        pub fn set_bool(mut self, key: &str, value: bool) -> Self {
1051            self.manager.set(key, ConfigValue::Boolean(value));
1052            self
1053        }
1054
1055        /// Build the configuration manager
1056        pub fn build(self) -> ConfigManager {
1057            self.manager
1058        }
1059    }
1060
1061    impl Default for ConfigBuilder {
1062        fn default() -> Self {
1063            Self::new()
1064        }
1065    }
1066}
1067
1068// Re-export commonly used macros
1069pub use builder_pattern;
1070pub use simple_random_transform;
1071pub use validated_constructor;
1072
1073#[cfg(test)]
1074mod tests {
1075    use super::*;
1076    use std::thread;
1077    use std::time::Duration;
1078
1079    #[test]
1080    fn test_validate_probability() {
1081        assert!(validate_probability(0.5, "test").is_ok());
1082        assert!(validate_probability(0.0, "test").is_ok());
1083        assert!(validate_probability(1.0, "test").is_ok());
1084        assert!(validate_probability(-0.1, "test").is_err());
1085        assert!(validate_probability(1.1, "test").is_err());
1086    }
1087
1088    #[test]
1089    fn test_validate_range() {
1090        assert!(validate_range((0.0, 1.0), "test").is_ok());
1091        assert!(validate_range((1.0, 1.0), "test").is_ok());
1092        assert!(validate_range((1.0, 0.0), "test").is_err());
1093    }
1094
1095    #[test]
1096    fn test_validate_positive() {
1097        assert!(validate_positive(1, "test").is_ok());
1098        assert!(validate_positive(0, "test").is_err());
1099        assert!(validate_positive(-1, "test").is_err());
1100    }
1101
1102    #[test]
1103    fn test_progress_tracker() {
1104        let mut tracker = ProgressTracker::new(10);
1105        assert!(!tracker.is_complete());
1106
1107        // Should report at 10%, 20%, etc.
1108        assert!(tracker.update()); // 10% - should report
1109        assert!(tracker.update()); // 20% - should also report (10% interval)
1110
1111        for _ in 0..8 {
1112            tracker.update();
1113        }
1114        assert!(tracker.is_complete());
1115    }
1116
1117    #[test]
1118    fn test_performance_timer() {
1119        let mut timer = performance::Timer::new();
1120        timer.start();
1121        thread::sleep(Duration::from_millis(10));
1122        let duration = timer.stop();
1123
1124        assert!(duration >= Duration::from_millis(10));
1125        assert!(timer.average().is_some());
1126        assert!(timer.throughput(100).is_some());
1127    }
1128
1129    #[test]
1130    fn test_memory_pool() {
1131        let mut pool = memory::MemoryPool::<u8>::new(5, 1024);
1132        assert_eq!(pool.size(), 0);
1133
1134        let buffer1 = pool.get();
1135        assert_eq!(buffer1.capacity(), 1024);
1136
1137        pool.put(buffer1);
1138        assert_eq!(pool.size(), 1);
1139
1140        let buffer2 = pool.get();
1141        assert_eq!(pool.size(), 0);
1142        assert_eq!(buffer2.len(), 0); // Should be cleared
1143    }
1144
1145    #[test]
1146    fn test_memory_tracker() {
1147        let mut tracker = memory::MemoryTracker::new();
1148        assert_eq!(tracker.current_usage(), 0);
1149
1150        tracker.allocate("test", 1024);
1151        assert_eq!(tracker.current_usage(), 1024);
1152        assert_eq!(tracker.peak_usage(), 1024);
1153
1154        tracker.deallocate("test", 512);
1155        assert_eq!(tracker.current_usage(), 512);
1156        assert_eq!(tracker.peak_usage(), 1024); // Peak should remain
1157    }
1158
1159    #[test]
1160    fn test_parallel_batch_process() {
1161        let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1162        let results = batch::parallel_batch_process(data, 3, |chunk| chunk.iter().sum::<i32>());
1163
1164        assert_eq!(results.len(), 4); // 4 batches: [1,2,3], [4,5,6], [7,8,9], [10]
1165        assert_eq!(results[0], 6); // 1+2+3
1166        assert_eq!(results[1], 15); // 4+5+6
1167        assert_eq!(results[2], 24); // 7+8+9
1168        assert_eq!(results[3], 10); // 10
1169    }
1170
1171    #[test]
1172    fn test_concurrent_cache() {
1173        let cache = concurrent::ConcurrentCache::new(2);
1174
1175        cache.insert("key1", "value1");
1176        cache.insert("key2", "value2");
1177        assert_eq!(cache.len(), 2);
1178
1179        assert_eq!(cache.get(&"key1"), Some("value1"));
1180        assert_eq!(cache.get(&"key2"), Some("value2"));
1181        assert_eq!(cache.get(&"key3"), None);
1182
1183        // Test eviction
1184        cache.insert("key3", "value3");
1185        assert_eq!(cache.len(), 2); // Should evict oldest
1186    }
1187
1188    #[test]
1189    fn test_statistics_collector() {
1190        let collector = concurrent::StatisticsCollector::new(100);
1191        assert_eq!(collector.count(), 0);
1192
1193        collector.add_sample(1.0);
1194        collector.add_sample(2.0);
1195        collector.add_sample(3.0);
1196
1197        assert_eq!(collector.count(), 3);
1198        assert_eq!(collector.mean(), Some(2.0));
1199        assert_eq!(collector.min_max(), Some((1.0, 3.0)));
1200        assert!(collector.std_dev().is_some());
1201    }
1202
1203    #[test]
1204    fn test_config_manager() {
1205        let mut config = config::ConfigManager::new();
1206
1207        // Test setting and getting different types
1208        config.set(
1209            "string_key",
1210            config::ConfigValue::String("test_value".to_string()),
1211        );
1212        config.set("int_key", config::ConfigValue::Integer(42));
1213        config.set("float_key", config::ConfigValue::Float(3.14));
1214        config.set("bool_key", config::ConfigValue::Boolean(true));
1215
1216        assert_eq!(config.get_string("string_key", "default"), "test_value");
1217        assert_eq!(config.get_i64("int_key", 0), 42);
1218        assert_eq!(config.get_f64("float_key", 0.0), 3.14);
1219        assert!(config.get_bool("bool_key", false));
1220
1221        // Test defaults
1222        assert_eq!(config.get_string("missing_key", "default"), "default");
1223        assert_eq!(config.get_i64("missing_key", 123), 123);
1224
1225        // Test contains_key
1226        assert!(config.contains_key("string_key"));
1227        assert!(!config.contains_key("missing_key"));
1228
1229        // Test keys
1230        let keys = config.keys();
1231        assert!(keys.len() >= 4);
1232
1233        // Test clear
1234        config.clear();
1235        assert_eq!(config.keys().len(), 0);
1236    }
1237
1238    #[test]
1239    fn test_config_value_conversions() {
1240        let string_val = config::ConfigValue::String("test".to_string());
1241        let int_val = config::ConfigValue::Integer(42);
1242        let float_val = config::ConfigValue::Float(3.14);
1243        let bool_val = config::ConfigValue::Boolean(true);
1244
1245        assert_eq!(string_val.as_string(), Some("test"));
1246        assert_eq!(int_val.as_i64(), Some(42));
1247        assert_eq!(float_val.as_f64(), Some(3.14));
1248        assert_eq!(bool_val.as_bool(), Some(true));
1249
1250        // Test type mismatches
1251        assert_eq!(string_val.as_i64(), None);
1252        assert_eq!(int_val.as_string(), None);
1253
1254        // Test integer to float conversion
1255        assert_eq!(int_val.as_f64(), Some(42.0));
1256    }
1257
1258    #[test]
1259    fn test_config_builder() {
1260        let config = config::ConfigBuilder::new()
1261            .env_prefix("TEST_")
1262            .set_string("app_name", "torsh-data")
1263            .set_i64("version", 1)
1264            .set_f64("threshold", 0.5)
1265            .set_bool("debug", true)
1266            .build();
1267
1268        assert_eq!(config.get_string("app_name", ""), "torsh-data");
1269        assert_eq!(config.get_i64("version", 0), 1);
1270        assert_eq!(config.get_f64("threshold", 0.0), 0.5);
1271        assert!(config.get_bool("debug", false));
1272    }
1273
1274    #[test]
1275    fn test_config_merge() {
1276        let mut config1 = config::ConfigManager::new();
1277        config1.set("key1", config::ConfigValue::String("value1".to_string()));
1278        config1.set("key2", config::ConfigValue::Integer(42));
1279
1280        let mut config2 = config::ConfigManager::new();
1281        config2.set("key2", config::ConfigValue::Integer(100)); // Override
1282        config2.set("key3", config::ConfigValue::Boolean(true)); // New key
1283
1284        config1.merge(&config2);
1285
1286        assert_eq!(config1.get_string("key1", ""), "value1");
1287        assert_eq!(config1.get_i64("key2", 0), 100); // Should be overridden
1288        assert!(config1.get_bool("key3", false));
1289    }
1290}