Skip to main content

scirs2_core/integration/
traits.rs

1//! Common Interface Traits for Module Interoperability
2//!
3//! This module defines standard traits that SciRS2 modules can implement
4//! to enable seamless interoperability across the ecosystem.
5//!
6//! # Core Traits
7//!
8//! - **Configurable**: Modules that accept configuration
9//! - **DataProvider/DataConsumer**: Data flow interfaces
10//! - **ModuleCapability**: Capability discovery
11//! - **Serializable**: Cross-module serialization
12//! - **ResourceAware**: Resource management
13//! - **Diagnosable**: Diagnostics and debugging
14
15use std::any::Any;
16use std::collections::HashMap;
17use std::fmt;
18
19use super::config::{EcosystemConfig, ModuleConfig};
20use super::zero_copy::{SharedArrayView, SharedArrayViewMut};
21use crate::error::{CoreError, CoreResult, ErrorContext, ErrorLocation};
22
23/// Trait for identifiable components
24pub trait Identifiable {
25    /// Get the unique identifier for this component
26    fn id(&self) -> &str;
27
28    /// Get a human-readable name
29    fn name(&self) -> &str;
30
31    /// Get the component type
32    fn component_type(&self) -> &str;
33
34    /// Get additional metadata
35    fn metadata(&self) -> HashMap<String, String> {
36        HashMap::new()
37    }
38}
39
40/// Trait for configurable modules
41pub trait Configurable {
42    /// Apply ecosystem-wide configuration
43    fn configure(&mut self, config: &EcosystemConfig) -> CoreResult<()>;
44
45    /// Apply module-specific configuration
46    fn configure_module(&mut self, config: &ModuleConfig) -> CoreResult<()>;
47
48    /// Get current configuration as key-value pairs
49    fn get_config(&self) -> HashMap<String, String>;
50
51    /// Reset to default configuration
52    fn reset_config(&mut self);
53
54    /// Validate current configuration
55    fn validate_config(&self) -> CoreResult<()>;
56}
57
58/// Trait for components that provide data
59pub trait DataProvider<T> {
60    /// Get the number of items available
61    fn len(&self) -> usize;
62
63    /// Check if empty
64    fn is_empty(&self) -> bool {
65        self.len() == 0
66    }
67
68    /// Get a read-only view of the data
69    fn view(&self) -> CoreResult<SharedArrayView<'_, T>>;
70
71    /// Get data shape (for multi-dimensional providers)
72    fn shape(&self) -> &[usize];
73
74    /// Get data type name
75    fn dtype(&self) -> &str;
76
77    /// Check if data is contiguous in memory
78    fn is_contiguous(&self) -> bool;
79}
80
81/// Trait for components that consume data
82pub trait DataConsumer<T> {
83    /// Consume data from a provider
84    fn consume<P: DataProvider<T>>(&mut self, provider: &P) -> CoreResult<()>;
85
86    /// Consume data from a slice
87    fn consume_slice(&mut self, data: &[T]) -> CoreResult<()>;
88
89    /// Consume data from a view
90    fn consume_view(&mut self, view: SharedArrayView<'_, T>) -> CoreResult<()>;
91
92    /// Get expected input shape
93    fn expected_shape(&self) -> Option<&[usize]>;
94
95    /// Check if consumer can accept the given shape
96    fn can_accept_shape(&self, shape: &[usize]) -> bool;
97}
98
99/// Trait for components that can provide mutable data access
100pub trait MutableDataProvider<T>: DataProvider<T> {
101    /// Get a mutable view of the data
102    fn view_mut(&mut self) -> CoreResult<SharedArrayViewMut<'_, T>>;
103
104    /// Apply an operation to all elements
105    fn apply<F>(&mut self, f: F) -> CoreResult<()>
106    where
107        F: Fn(&mut T);
108
109    /// Clear all data
110    fn clear(&mut self);
111}
112
113/// Module capabilities enumeration
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115pub enum Capability {
116    /// Can process in parallel
117    Parallel,
118    /// Can use GPU acceleration
119    GpuAcceleration,
120    /// Supports SIMD operations
121    Simd,
122    /// Supports streaming/incremental processing
123    Streaming,
124    /// Supports distributed processing
125    Distributed,
126    /// Can serialize/deserialize state
127    Serializable,
128    /// Supports checkpointing
129    Checkpointing,
130    /// Thread-safe operations
131    ThreadSafe,
132    /// Async operations supported
133    Async,
134    /// Memory-mapped file support
135    MemoryMapped,
136    /// Zero-copy data sharing
137    ZeroCopy,
138    /// Supports batched operations
139    Batched,
140    /// Custom capability
141    Custom(&'static str),
142}
143
144impl fmt::Display for Capability {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        match self {
147            Capability::Parallel => write!(f, "parallel"),
148            Capability::GpuAcceleration => write!(f, "gpu"),
149            Capability::Simd => write!(f, "simd"),
150            Capability::Streaming => write!(f, "streaming"),
151            Capability::Distributed => write!(f, "distributed"),
152            Capability::Serializable => write!(f, "serializable"),
153            Capability::Checkpointing => write!(f, "checkpointing"),
154            Capability::ThreadSafe => write!(f, "thread-safe"),
155            Capability::Async => write!(f, "async"),
156            Capability::MemoryMapped => write!(f, "mmap"),
157            Capability::ZeroCopy => write!(f, "zero-copy"),
158            Capability::Batched => write!(f, "batched"),
159            Capability::Custom(name) => write!(f, "custom:{name}"),
160        }
161    }
162}
163
164/// Trait for capability discovery
165pub trait ModuleCapability {
166    /// Get list of supported capabilities
167    fn capabilities(&self) -> Vec<Capability>;
168
169    /// Check if a specific capability is supported
170    fn has_capability(&self, cap: Capability) -> bool {
171        self.capabilities().contains(&cap)
172    }
173
174    /// Get capability requirements for a specific operation
175    fn required_capabilities(&self, operation: &str) -> Vec<Capability>;
176
177    /// Check if all required capabilities for an operation are available
178    fn can_perform(&self, operation: &str) -> bool {
179        let required = self.required_capabilities(operation);
180        required.iter().all(|cap| self.has_capability(*cap))
181    }
182}
183
184/// Serialization format
185#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
186pub enum SerializationFormat {
187    /// JSON format
188    Json,
189    /// MessagePack format
190    MessagePack,
191    /// Binary format (custom)
192    Binary,
193    /// CBOR format
194    Cbor,
195    /// Protocol Buffers
196    Protobuf,
197}
198
199/// Trait for serializable components
200pub trait Serializable {
201    /// Supported serialization formats
202    fn supported_formats(&self) -> Vec<SerializationFormat>;
203
204    /// Serialize to bytes
205    fn serialize(&self, format: SerializationFormat) -> CoreResult<Vec<u8>>;
206
207    /// Deserialize from bytes
208    fn deserialize(&mut self, data: &[u8], format: SerializationFormat) -> CoreResult<()>;
209
210    /// Get serialization size estimate
211    fn estimated_size(&self, format: SerializationFormat) -> usize;
212}
213
214/// Trait for cross-module operators
215pub trait CrossModuleOperator<Input, Output> {
216    /// Apply the operation
217    fn apply(&self, input: &Input) -> CoreResult<Output>;
218
219    /// Apply in-place if possible
220    fn apply_inplace(&self, data: &mut Input) -> CoreResult<()>
221    where
222        Input: From<Output>;
223
224    /// Get the operator name
225    fn operator_name(&self) -> &str;
226
227    /// Get input type information
228    fn input_info(&self) -> &str;
229
230    /// Get output type information
231    fn output_info(&self) -> &str;
232
233    /// Check if operator is deterministic
234    fn is_deterministic(&self) -> bool;
235}
236
237/// API version information
238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
239pub struct ApiVersion {
240    /// Major version
241    pub major: u32,
242    /// Minor version
243    pub minor: u32,
244    /// Patch version
245    pub patch: u32,
246}
247
248impl ApiVersion {
249    /// Create a new version
250    #[must_use]
251    pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
252        Self {
253            major,
254            minor,
255            patch,
256        }
257    }
258
259    /// Check if this version is compatible with another
260    #[must_use]
261    pub const fn is_compatible(&self, other: &Self) -> bool {
262        self.major == other.major && self.minor >= other.minor
263    }
264
265    /// Check if this version is newer than another
266    #[must_use]
267    pub const fn is_newer_than(&self, other: &Self) -> bool {
268        if self.major != other.major {
269            return self.major > other.major;
270        }
271        if self.minor != other.minor {
272            return self.minor > other.minor;
273        }
274        self.patch > other.patch
275    }
276}
277
278impl fmt::Display for ApiVersion {
279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
281    }
282}
283
284/// Trait for versioned interfaces
285pub trait VersionedInterface {
286    /// Get the interface version
287    fn version(&self) -> ApiVersion;
288
289    /// Check compatibility with another version
290    fn is_compatible_with(&self, version: &ApiVersion) -> bool {
291        self.version().is_compatible(version)
292    }
293
294    /// Get minimum required version
295    fn minimum_version(&self) -> ApiVersion;
296
297    /// Get deprecated features
298    fn deprecated_features(&self) -> Vec<String>;
299}
300
301/// Module interface descriptor
302pub trait ModuleInterface:
303    Identifiable + Configurable + ModuleCapability + VersionedInterface
304{
305    /// Initialize the module
306    fn initialize(&mut self) -> CoreResult<()>;
307
308    /// Shutdown the module
309    fn shutdown(&mut self) -> CoreResult<()>;
310
311    /// Get module health status
312    fn health_check(&self) -> CoreResult<HealthStatus>;
313
314    /// Get module statistics
315    fn statistics(&self) -> HashMap<String, f64>;
316
317    /// Reset module state
318    fn reset(&mut self) -> CoreResult<()>;
319}
320
321/// Health status for modules
322#[derive(Debug, Clone, PartialEq, Eq)]
323pub enum HealthStatus {
324    /// Module is healthy and operational
325    Healthy,
326    /// Module is degraded but functional
327    Degraded(String),
328    /// Module is unhealthy
329    Unhealthy(String),
330    /// Health status unknown
331    Unknown,
332}
333
334impl fmt::Display for HealthStatus {
335    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336        match self {
337            HealthStatus::Healthy => write!(f, "healthy"),
338            HealthStatus::Degraded(msg) => write!(f, "degraded: {msg}"),
339            HealthStatus::Unhealthy(msg) => write!(f, "unhealthy: {msg}"),
340            HealthStatus::Unknown => write!(f, "unknown"),
341        }
342    }
343}
344
345/// Resource usage information
346#[derive(Debug, Clone, Default)]
347pub struct ResourceUsage {
348    /// Memory usage in bytes
349    pub memory_bytes: usize,
350    /// CPU usage percentage (0-100)
351    pub cpu_percent: f32,
352    /// GPU memory usage in bytes
353    pub gpu_memory_bytes: usize,
354    /// Number of threads in use
355    pub thread_count: usize,
356    /// Number of file handles open
357    pub file_handles: usize,
358    /// Custom resource metrics
359    pub custom: HashMap<String, f64>,
360}
361
362/// Trait for resource-aware components
363pub trait ResourceAware {
364    /// Get current resource usage
365    fn resource_usage(&self) -> ResourceUsage;
366
367    /// Get resource limits
368    fn resource_limits(&self) -> ResourceUsage;
369
370    /// Set resource limits
371    fn set_resource_limits(&mut self, limits: ResourceUsage) -> CoreResult<()>;
372
373    /// Check if resource usage is within limits
374    fn within_limits(&self) -> bool {
375        let usage = self.resource_usage();
376        let limits = self.resource_limits();
377
378        if limits.memory_bytes > 0 && usage.memory_bytes > limits.memory_bytes {
379            return false;
380        }
381        if limits.cpu_percent > 0.0 && usage.cpu_percent > limits.cpu_percent {
382            return false;
383        }
384        if limits.gpu_memory_bytes > 0 && usage.gpu_memory_bytes > limits.gpu_memory_bytes {
385            return false;
386        }
387        if limits.thread_count > 0 && usage.thread_count > limits.thread_count {
388            return false;
389        }
390        true
391    }
392
393    /// Release unused resources
394    fn release_resources(&mut self) -> CoreResult<usize>;
395
396    /// Estimate resources needed for an operation
397    fn estimate_resources(&self, operation: &str, input_size: usize) -> ResourceUsage;
398}
399
400/// Diagnostic information
401#[derive(Debug, Clone)]
402pub struct DiagnosticInfo {
403    /// Component name
404    pub component: String,
405    /// Diagnostic level
406    pub level: DiagnosticLevel,
407    /// Message
408    pub message: String,
409    /// Additional context
410    pub context: HashMap<String, String>,
411    /// Timestamp
412    pub timestamp: std::time::SystemTime,
413}
414
415/// Diagnostic level
416#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
417pub enum DiagnosticLevel {
418    /// Trace-level diagnostics
419    Trace,
420    /// Debug-level diagnostics
421    Debug,
422    /// Informational diagnostics
423    Info,
424    /// Warning diagnostics
425    Warning,
426    /// Error diagnostics
427    Error,
428}
429
430impl fmt::Display for DiagnosticLevel {
431    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432        match self {
433            DiagnosticLevel::Trace => write!(f, "TRACE"),
434            DiagnosticLevel::Debug => write!(f, "DEBUG"),
435            DiagnosticLevel::Info => write!(f, "INFO"),
436            DiagnosticLevel::Warning => write!(f, "WARN"),
437            DiagnosticLevel::Error => write!(f, "ERROR"),
438        }
439    }
440}
441
442/// Trait for diagnosable components
443pub trait Diagnosable {
444    /// Get diagnostics
445    fn diagnostics(&self) -> Vec<DiagnosticInfo>;
446
447    /// Get diagnostics at or above a level
448    fn diagnostics_at_level(&self, min_level: DiagnosticLevel) -> Vec<DiagnosticInfo> {
449        self.diagnostics()
450            .into_iter()
451            .filter(|d| d.level >= min_level)
452            .collect()
453    }
454
455    /// Clear diagnostics
456    fn clear_diagnostics(&mut self);
457
458    /// Enable diagnostic collection
459    fn enable_diagnostics(&mut self, enabled: bool);
460
461    /// Check if diagnostics are enabled
462    fn diagnostics_enabled(&self) -> bool;
463
464    /// Get diagnostic summary
465    fn diagnostic_summary(&self) -> String {
466        let diags = self.diagnostics();
467        let errors = diags
468            .iter()
469            .filter(|d| d.level == DiagnosticLevel::Error)
470            .count();
471        let warnings = diags
472            .iter()
473            .filter(|d| d.level == DiagnosticLevel::Warning)
474            .count();
475        format!(
476            "{} diagnostics ({} errors, {} warnings)",
477            diags.len(),
478            errors,
479            warnings
480        )
481    }
482}
483
484/// Trait for composable components
485pub trait Composable {
486    /// Compose with another component
487    fn compose<Other: Composable>(&self, other: &Other) -> CoreResult<Box<dyn Any>>;
488
489    /// Check if composition is possible
490    fn can_compose_with<Other: Composable>(&self, other: &Other) -> bool;
491
492    /// Get composition requirements
493    fn composition_requirements(&self) -> Vec<String>;
494
495    /// Get composition outputs
496    fn composition_outputs(&self) -> Vec<String>;
497}
498
499/// Pipeline stage trait
500pub trait PipelineStage<Input, Output> {
501    /// Process input and produce output
502    fn process(&self, input: Input) -> CoreResult<Output>;
503
504    /// Get stage name
505    fn stage_name(&self) -> &str;
506
507    /// Check if stage is ready
508    fn is_ready(&self) -> bool;
509
510    /// Get estimated processing time in milliseconds
511    fn estimated_time_ms(&self, input_size: usize) -> f64;
512}
513
514/// Trait for chainable operations
515pub trait Chainable<T> {
516    /// Chain with another operation
517    fn chain<F, U>(self, f: F) -> Chain<Self, F>
518    where
519        Self: Sized,
520        F: Fn(T) -> U;
521
522    /// Map over values
523    fn map<F, U>(self, f: F) -> Map<Self, F>
524    where
525        Self: Sized,
526        F: Fn(T) -> U;
527
528    /// Filter values
529    fn filter<F>(self, f: F) -> Filter<Self, F>
530    where
531        Self: Sized,
532        F: Fn(&T) -> bool;
533}
534
535/// Chain combinator
536#[derive(Debug)]
537pub struct Chain<A, F> {
538    inner: A,
539    f: F,
540}
541
542impl<A, F> Chain<A, F> {
543    /// Create a new chain
544    #[must_use]
545    pub const fn new(inner: A, f: F) -> Self {
546        Self { inner, f }
547    }
548
549    /// Get the inner value
550    #[must_use]
551    pub const fn inner(&self) -> &A {
552        &self.inner
553    }
554}
555
556/// Map combinator
557#[derive(Debug)]
558pub struct Map<A, F> {
559    inner: A,
560    f: F,
561}
562
563impl<A, F> Map<A, F> {
564    /// Create a new map
565    #[must_use]
566    pub const fn new(inner: A, f: F) -> Self {
567        Self { inner, f }
568    }
569}
570
571/// Filter combinator
572#[derive(Debug)]
573pub struct Filter<A, F> {
574    inner: A,
575    predicate: F,
576}
577
578impl<A, F> Filter<A, F> {
579    /// Create a new filter
580    #[must_use]
581    pub const fn new(inner: A, predicate: F) -> Self {
582        Self { inner, predicate }
583    }
584}
585
586/// Observer trait for reactive patterns
587pub trait Observer<T> {
588    /// Called when a new value is available
589    fn on_next(&mut self, value: T);
590
591    /// Called when an error occurs
592    fn on_error(&mut self, error: CoreError);
593
594    /// Called when the stream completes
595    fn on_complete(&mut self);
596}
597
598/// Observable trait for reactive patterns
599pub trait Observable<T> {
600    /// Subscribe an observer
601    fn subscribe(&mut self, observer: Box<dyn Observer<T> + Send>);
602
603    /// Unsubscribe an observer
604    fn unsubscribe(&mut self, observer_id: usize);
605
606    /// Get number of subscribers
607    fn subscriber_count(&self) -> usize;
608}
609
610#[cfg(test)]
611mod tests {
612    use super::*;
613
614    #[test]
615    fn test_api_version() {
616        let v1 = ApiVersion::new(1, 2, 3);
617        let v2 = ApiVersion::new(1, 3, 0);
618        let v3 = ApiVersion::new(2, 0, 0);
619
620        assert!(v2.is_compatible(&v1));
621        assert!(!v1.is_compatible(&v2));
622        assert!(!v3.is_compatible(&v1));
623
624        assert!(v2.is_newer_than(&v1));
625        assert!(v3.is_newer_than(&v2));
626    }
627
628    #[test]
629    fn test_version_display() {
630        let v = ApiVersion::new(1, 2, 3);
631        assert_eq!(v.to_string(), "1.2.3");
632    }
633
634    #[test]
635    fn test_capability_display() {
636        assert_eq!(Capability::Parallel.to_string(), "parallel");
637        assert_eq!(Capability::GpuAcceleration.to_string(), "gpu");
638        assert_eq!(Capability::Custom("test").to_string(), "custom:test");
639    }
640
641    #[test]
642    fn test_health_status() {
643        assert_eq!(HealthStatus::Healthy.to_string(), "healthy");
644        assert!(HealthStatus::Degraded("slow".into())
645            .to_string()
646            .contains("slow"));
647        assert!(HealthStatus::Unhealthy("failed".into())
648            .to_string()
649            .contains("failed"));
650    }
651
652    #[test]
653    fn test_resource_usage() {
654        let usage = ResourceUsage {
655            memory_bytes: 1024,
656            cpu_percent: 50.0,
657            thread_count: 4,
658            ..Default::default()
659        };
660
661        assert_eq!(usage.memory_bytes, 1024);
662        assert_eq!(usage.cpu_percent, 50.0);
663        assert_eq!(usage.thread_count, 4);
664    }
665
666    #[test]
667    fn test_diagnostic_level_ordering() {
668        assert!(DiagnosticLevel::Error > DiagnosticLevel::Warning);
669        assert!(DiagnosticLevel::Warning > DiagnosticLevel::Info);
670        assert!(DiagnosticLevel::Info > DiagnosticLevel::Debug);
671        assert!(DiagnosticLevel::Debug > DiagnosticLevel::Trace);
672    }
673
674    #[test]
675    fn test_diagnostic_info() {
676        let info = DiagnosticInfo {
677            component: "test".into(),
678            level: DiagnosticLevel::Info,
679            message: "test message".into(),
680            context: HashMap::new(),
681            timestamp: std::time::SystemTime::now(),
682        };
683
684        assert_eq!(info.component, "test");
685        assert_eq!(info.level, DiagnosticLevel::Info);
686    }
687
688    #[test]
689    fn test_chain_combinator() {
690        let chain = Chain::new(42, |x: i32| x * 2);
691        assert_eq!(*chain.inner(), 42);
692    }
693
694    #[test]
695    fn test_serialization_format() {
696        let format = SerializationFormat::Json;
697        assert_eq!(format, SerializationFormat::Json);
698    }
699}