dmsc/device/
core.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18#![allow(non_snake_case)]
19
20//! # Device Core Structures
21//! 
22//! This file defines the core data structures for device management in DMSC, including device types,
23//! capabilities, status, health metrics, and the device representation itself. These structures form
24//! the foundation for device discovery, scheduling, and management.
25//! 
26//! ## Key Components
27//! 
28//! - **DMSCDeviceType**: Enum defining supported device types
29//! - **DMSCDeviceCapabilities**: Device capabilities structure
30//! - **DMSCDeviceStatus**: Enum defining device statuses
31//! - **DMSCDeviceHealthMetrics**: Device health metrics structure
32//! - **DMSCDevice**: Main device representation with status, capabilities, and health metrics
33//! 
34//! ## Design Principles
35//! 
36//! 1. **Comprehensive Coverage**: Covers all aspects of device management
37//! 2. **Flexibility**: Supports custom device types and capabilities
38//! 3. **Health Monitoring**: Built-in health metrics for device monitoring
39//! 4. **Resource Management**: Capabilities structure for resource allocation
40//! 5. **Status Tracking**: Clear status definitions for device lifecycle management
41//! 6. **Serialization Support**: All structures support serialization/deserialization
42//! 7. **Builder Pattern**: Capabilities support a fluent builder API
43//! 8. **Health Scoring**: Built-in health scoring for device selection
44//! 
45//! ## Usage
46//! 
47//! ```rust
48//! use dmsc::device::{DMSCDevice, DMSCDeviceType, DMSCDeviceCapabilities};
49//! 
50//! // Create a new device
51//! let mut device = DMSCDevice::new("server-1".to_string(), DMSCDeviceType::CPU);
52//! 
53//! // Configure device capabilities
54//! let capabilities = DMSCDeviceCapabilities::new()
55//!     .with_compute_units(16)
56//!     .with_memory_gb(32.0)
57//!     .with_storage_gb(1024.0)
58//!     .with_bandwidth_gbps(10.0);
59//! 
60//! // Set device capabilities and status
61//! device = device.with_capabilities(capabilities);
62//! device.set_status(dmsc::device::DMSCDeviceStatus::Available);
63//! 
64//! // Check if device meets requirements
65//! let requirements = DMSCDeviceCapabilities::new().with_compute_units(8);
66//! if device.capabilities().meets_requirements(&requirements) {
67//!     println!("Device meets requirements");
68//! }
69//! ```
70
71use serde::{Serialize, Deserialize};
72use std::collections::HashMap;
73use uuid::Uuid;
74
75#[cfg(feature = "pyo3")]
76use pyo3::prelude::*;
77
78/// Configuration for device control module
79#[derive(Debug, Clone, Serialize, Deserialize)]
80#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
81pub struct DMSCDeviceControlConfig {
82    /// Enable CPU discovery
83    pub enable_cpu_discovery: bool,
84    /// Enable GPU discovery  
85    pub enable_gpu_discovery: bool,
86    /// Enable memory discovery
87    pub enable_memory_discovery: bool,
88    /// Enable storage discovery
89    pub enable_storage_discovery: bool,
90    /// Enable network discovery
91    pub enable_network_discovery: bool,
92    /// Network discovery timeout in seconds
93    pub discovery_timeout_secs: u64,
94    /// Maximum number of devices to discover per type
95    pub max_devices_per_type: usize,
96}
97
98impl Default for DMSCDeviceControlConfig {
99    fn default() -> Self {
100        Self {
101            enable_cpu_discovery: true,
102            enable_gpu_discovery: true,
103            enable_memory_discovery: true,
104            enable_storage_discovery: true,
105            enable_network_discovery: true,
106            discovery_timeout_secs: 30,
107            max_devices_per_type: 100,
108        }
109    }
110}
111
112#[cfg(feature = "pyo3")]
113#[pymethods]
114impl DMSCDeviceControlConfig {
115    #[new]
116    fn py_new() -> Self {
117        Self::default()
118    }
119    
120    #[staticmethod]
121    fn default_config() -> Self {
122        Self::default()
123    }
124}
125
126#[cfg(feature = "pyo3")]
127#[pymethods]
128impl DMSCDeviceHealthMetrics {
129    #[new]
130    fn py_new() -> Self {
131        Self::default()
132    }
133    
134    #[staticmethod]
135    fn default_metrics() -> Self {
136        Self::default()
137    }
138}
139
140/// Configuration for device module
141#[derive(Debug, Clone, Serialize, Deserialize)]
142#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
143pub struct DMSCDeviceConfig {
144    /// Enable CPU discovery
145    pub enable_cpu_discovery: bool,
146    /// Enable GPU discovery  
147    pub enable_gpu_discovery: bool,
148    /// Enable memory discovery
149    pub enable_memory_discovery: bool,
150    /// Enable storage discovery
151    pub enable_storage_discovery: bool,
152    /// Enable network discovery
153    pub enable_network_discovery: bool,
154    /// Network discovery timeout in seconds
155    pub discovery_timeout_secs: u64,
156    /// Maximum number of devices to discover per type
157    pub max_devices_per_type: usize,
158}
159
160impl Default for DMSCDeviceConfig {
161    fn default() -> Self {
162        Self {
163            enable_cpu_discovery: true,
164            enable_gpu_discovery: true,
165            enable_memory_discovery: true,
166            enable_storage_discovery: true,
167            enable_network_discovery: true,
168            discovery_timeout_secs: 30,
169            max_devices_per_type: 100,
170        }
171    }
172}
173
174#[cfg(feature = "pyo3")]
175#[pymethods]
176impl DMSCDeviceConfig {
177    #[new]
178    fn py_new() -> Self {
179        Self::default()
180    }
181    
182    #[staticmethod]
183    fn default_config() -> Self {
184        Self::default()
185    }
186}
187
188/// Network device information for remote device discovery
189#[derive(Debug, Clone, Serialize, Deserialize)]
190#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
191pub struct DMSCNetworkDeviceInfo {
192    /// Unique device identifier
193    pub id: String,
194    /// Device type (CPU, GPU, Memory, Storage, Network)
195    pub device_type: String,
196    /// Source system identifier
197    pub source: String,
198    /// Number of compute units (for CPU/GPU)
199    pub compute_units: Option<usize>,
200    /// Memory capacity in GB
201    pub memory_gb: Option<f64>,
202    /// Storage capacity in GB
203    pub storage_gb: Option<f64>,
204    /// Bandwidth in Gbps
205    pub bandwidth_gbps: Option<f64>,
206}
207
208#[cfg(feature = "pyo3")]
209#[pymethods]
210impl DMSCNetworkDeviceInfo {
211    #[new]
212    fn py_new(id: String, device_type: String, source: String) -> Self {
213        Self {
214            id,
215            device_type,
216            source,
217            compute_units: None,
218            memory_gb: None,
219            storage_gb: None,
220            bandwidth_gbps: None,
221        }
222    }
223    
224    #[staticmethod]
225    fn default_info(id: String, device_type: String, source: String) -> Self {
226        Self::py_new(id, device_type, source)
227    }
228}
229
230/// Device type enumeration
231/// 
232/// This enum defines the different types of devices supported by DMSC. Each device type
233/// has specific capabilities and use cases in the system.
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
235#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
236pub enum DMSCDeviceType {
237    /// Central Processing Unit - General purpose computing
238    CPU,
239    /// Graphics Processing Unit - Parallel computing and graphics
240    GPU,
241    /// Memory - RAM and other memory devices
242    Memory,
243    /// Storage - Hard drives, SSDs, and other storage devices
244    Storage,
245    /// Network - Network interfaces and devices
246    Network,
247    /// Sensor - Devices that collect data from the environment
248    Sensor,
249    /// Actuator - Devices that perform physical actions
250    Actuator,
251    /// Custom - User-defined device types
252    Custom,
253}
254
255impl std::fmt::Display for DMSCDeviceType {
256    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257        match self {
258            DMSCDeviceType::CPU => write!(f, "CPU"),
259            DMSCDeviceType::GPU => write!(f, "GPU"),
260            DMSCDeviceType::Memory => write!(f, "Memory"),
261            DMSCDeviceType::Storage => write!(f, "Storage"),
262            DMSCDeviceType::Network => write!(f, "Network"),
263            DMSCDeviceType::Sensor => write!(f, "Sensor"),
264            DMSCDeviceType::Actuator => write!(f, "Actuator"),
265            DMSCDeviceType::Custom => write!(f, "Custom"),
266        }
267    }
268}
269
270#[cfg(feature = "pyo3")]
271#[pymethods]
272impl DMSCDeviceType {
273    #[staticmethod]
274    fn new_cpu() -> Self {
275        DMSCDeviceType::CPU
276    }
277    
278    #[staticmethod]
279    fn new_gpu() -> Self {
280        DMSCDeviceType::GPU
281    }
282    
283    #[staticmethod]
284    fn new_memory() -> Self {
285        DMSCDeviceType::Memory
286    }
287    
288    #[staticmethod]
289    fn new_storage() -> Self {
290        DMSCDeviceType::Storage
291    }
292    
293    #[staticmethod]
294    fn new_network() -> Self {
295        DMSCDeviceType::Network
296    }
297    
298    #[staticmethod]
299    fn new_sensor() -> Self {
300        DMSCDeviceType::Sensor
301    }
302    
303    #[staticmethod]
304    fn new_actuator() -> Self {
305        DMSCDeviceType::Actuator
306    }
307    
308    #[staticmethod]
309    fn new_custom() -> Self {
310        DMSCDeviceType::Custom
311    }
312    
313    fn __str__(&self) -> String {
314        self.to_string()
315    }
316}
317
318/// Device capabilities structure
319/// 
320/// This struct defines the capabilities of a device, including compute power, memory, storage,
321/// bandwidth, and custom capabilities. It supports a fluent builder API for easy configuration.
322#[derive(Debug, Clone, Serialize, Deserialize)]
323#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
324pub struct DMSCDeviceCapabilities {
325    /// Number of compute units (e.g., CPU cores, GPU CUDA cores)
326    pub compute_units: Option<usize>,
327    /// Memory capacity in gigabytes
328    pub memory_gb: Option<f64>,
329    /// Storage capacity in gigabytes
330    pub storage_gb: Option<f64>,
331    /// Bandwidth in gigabits per second
332    pub bandwidth_gbps: Option<f64>,
333    /// Custom capabilities as key-value pairs
334    pub custom_capabilities: HashMap<String, String>,
335}
336
337impl Default for DMSCDeviceCapabilities {
338    /// Returns the default device capabilities (empty capabilities)
339    fn default() -> Self {
340        Self::new()
341    }
342}
343
344impl DMSCDeviceCapabilities {
345    /// Creates a new empty device capabilities structure
346    /// 
347    /// # Returns
348    /// 
349    /// A new `DMSCDeviceCapabilities` instance with no capabilities set
350    pub fn new() -> Self {
351        Self {
352            compute_units: None,
353            memory_gb: None,
354            storage_gb: None,
355            bandwidth_gbps: None,
356            custom_capabilities: HashMap::new(),
357        }
358    }
359    
360    /// Sets the number of compute units
361    /// 
362    /// # Parameters
363    /// 
364    /// - `units`: Number of compute units
365    /// 
366    /// # Returns
367    /// 
368    /// The updated `DMSCDeviceCapabilities` instance
369    pub fn with_compute_units(mut self, units: usize) -> Self {
370        self.compute_units = Some(units);
371        self
372    }
373    
374    /// Sets the memory capacity in gigabytes
375    /// 
376    /// # Parameters
377    /// 
378    /// - `memory`: Memory capacity in GB
379    /// 
380    /// # Returns
381    /// 
382    /// The updated `DMSCDeviceCapabilities` instance
383    pub fn with_memory_gb(mut self, memory: f64) -> Self {
384        self.memory_gb = Some(memory);
385        self
386    }
387    
388    /// Sets the storage capacity in gigabytes
389    /// 
390    /// # Parameters
391    /// 
392    /// - `storage`: Storage capacity in GB
393    /// 
394    /// # Returns
395    /// 
396    /// The updated `DMSCDeviceCapabilities` instance
397    pub fn with_storage_gb(mut self, storage: f64) -> Self {
398        self.storage_gb = Some(storage);
399        self
400    }
401    
402    /// Sets the bandwidth in gigabits per second
403    /// 
404    /// # Parameters
405    /// 
406    /// - `bandwidth`: Bandwidth in Gbps
407    /// 
408    /// # Returns
409    /// 
410    /// The updated `DMSCDeviceCapabilities` instance
411    pub fn with_bandwidth_gbps(mut self, bandwidth: f64) -> Self {
412        self.bandwidth_gbps = Some(bandwidth);
413        self
414    }
415    
416    /// Adds a custom capability
417    /// 
418    /// # Parameters
419    /// 
420    /// - `key`: Custom capability key
421    /// - `value`: Custom capability value
422    /// 
423    /// # Returns
424    /// 
425    /// The updated `DMSCDeviceCapabilities` instance
426    pub fn with_custom_capability(mut self, key: String, value: String) -> Self {
427        self.custom_capabilities.insert(key, value);
428        self
429    }
430    
431    /// Checks if this device meets the required capabilities
432    /// 
433    /// This method compares the device's capabilities with the required capabilities and
434    /// returns true if all required capabilities are met or exceeded.
435    /// 
436    /// # Parameters
437    /// 
438    /// - `requirements`: The required capabilities to check against
439    /// 
440    /// # Returns
441    /// 
442    /// `true` if the device meets all requirements, `false` otherwise
443    pub fn meets_requirements(&self, requirements: &DMSCDeviceCapabilities) -> bool {
444        // Check compute units requirement
445        if let Some(required_units) = requirements.compute_units {
446            if let Some(available_units) = self.compute_units {
447                if available_units < required_units {
448                    return false;
449                }
450            } else {
451                return false; // No compute units available
452            }
453        }
454        
455        // Check memory requirement
456        if let Some(required_memory) = requirements.memory_gb {
457            if let Some(available_memory) = self.memory_gb {
458                if available_memory < required_memory {
459                    return false;
460                }
461            } else {
462                return false; // No memory available
463            }
464        }
465        
466        // Check storage requirement
467        if let Some(required_storage) = requirements.storage_gb {
468            if let Some(available_storage) = self.storage_gb {
469                if available_storage < required_storage {
470                    return false;
471                }
472            } else {
473                return false; // No storage available
474            }
475        }
476        
477        // Check bandwidth requirement
478        if let Some(required_bandwidth) = requirements.bandwidth_gbps {
479            if let Some(available_bandwidth) = self.bandwidth_gbps {
480                if available_bandwidth < required_bandwidth {
481                    return false;
482                }
483            } else {
484                return false; // No bandwidth available
485            }
486        }
487        
488        // Check custom capabilities
489        for (key, required_value) in &requirements.custom_capabilities {
490            match self.custom_capabilities.get(key) {
491                Some(available_value) => {
492                    // Simple string comparison for now
493                    if available_value != required_value {
494                        return false;
495                    }
496                }
497                None => return false, // Required capability not available
498            }
499        }
500        
501        true
502    }
503}
504
505#[cfg(feature = "pyo3")]
506#[pymethods]
507impl DMSCDeviceCapabilities {
508    #[new]
509    fn py_new() -> Self {
510        Self::new()
511    }
512    
513    #[staticmethod]
514    fn default_capabilities() -> Self {
515        Self::default()
516    }
517    
518    #[pyo3(name = "with_compute_units")]
519    fn with_compute_units_impl(&self, units: usize) -> Self {
520        let mut new = self.clone();
521        new.compute_units = Some(units);
522        new
523    }
524    
525    #[pyo3(name = "with_memory_gb")]
526    fn with_memory_gb_impl(&self, memory: f64) -> Self {
527        let mut new = self.clone();
528        new.memory_gb = Some(memory);
529        new
530    }
531    
532    #[pyo3(name = "with_storage_gb")]
533    fn with_storage_gb_impl(&self, storage: f64) -> Self {
534        let mut new = self.clone();
535        new.storage_gb = Some(storage);
536        new
537    }
538    
539    #[pyo3(name = "with_bandwidth_gbps")]
540    fn with_bandwidth_gbps_impl(&self, bandwidth: f64) -> Self {
541        let mut new = self.clone();
542        new.bandwidth_gbps = Some(bandwidth);
543        new
544    }
545    
546    #[pyo3(name = "with_custom_capability")]
547    fn with_custom_capability_impl(&self, key: String, value: String) -> Self {
548        let mut new = self.clone();
549        new.custom_capabilities.insert(key, value);
550        new
551    }
552    
553    #[pyo3(name = "get_compute_units")]
554    fn get_compute_units_impl(&self) -> Option<usize> { 
555        self.compute_units 
556    }
557    
558    #[pyo3(name = "get_memory_gb")]
559    fn get_memory_gb_impl(&self) -> Option<f64> { 
560        self.memory_gb 
561    }
562    
563    #[pyo3(name = "get_storage_gb")]
564    fn get_storage_gb_impl(&self) -> Option<f64> { 
565        self.storage_gb 
566    }
567    
568    #[pyo3(name = "get_bandwidth_gbps")]
569    fn get_bandwidth_gbps_impl(&self) -> Option<f64> { 
570        self.bandwidth_gbps 
571    }
572    
573    #[pyo3(name = "get_custom_capabilities")]
574    fn get_custom_capabilities_impl(&self) -> HashMap<String, String> { 
575        self.custom_capabilities.clone() 
576    }
577    
578    #[pyo3(name = "meets_requirements")]
579    fn meets_requirements_impl(&self, requirements: &DMSCDeviceCapabilities) -> bool {
580        self.meets_requirements(requirements)
581    }
582}
583
584/// Device status enumeration
585/// 
586/// This enum defines the different statuses a device can have during its lifecycle.
587#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
588#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
589pub enum DMSCDeviceStatus {
590    /// Device status is unknown
591    Unknown,
592    /// Device is available for use
593    Available,
594    /// Device is currently in use
595    Busy,
596    /// Device has encountered an error
597    Error,
598    /// Device is offline or unreachable
599    Offline,
600    /// Device is under maintenance
601    Maintenance,
602    /// Device is degraded but still operational
603    Degraded,
604    /// Device is allocated to a specific task
605    Allocated,
606}
607
608
609
610/// Device health metrics structure
611/// 
612/// This struct contains health metrics for monitoring device performance and reliability.
613#[derive(Debug, Clone, Serialize, Deserialize)]
614#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
615pub struct DMSCDeviceHealthMetrics {
616    /// CPU usage percentage (0-100)
617    pub cpu_usage_percent: f64,
618    /// Memory usage percentage (0-100)
619    pub memory_usage_percent: f64,
620    /// Device temperature in Celsius
621    pub temperature_celsius: f64,
622    /// Number of errors encountered
623    pub error_count: u32,
624    /// Throughput in operations per second
625    pub throughput: u64, // operations per second
626    /// Network latency in milliseconds (for network devices)
627    pub network_latency_ms: f64,
628    /// Disk I/O operations per second (for storage devices)
629    pub disk_iops: u64,
630    /// Battery level percentage (for battery-powered devices, 0-100)
631    pub battery_level_percent: f64,
632    /// Response time in milliseconds
633    pub response_time_ms: f64,
634    /// Uptime in seconds
635    pub uptime_seconds: u64,
636}
637
638impl Default for DMSCDeviceHealthMetrics {
639    /// Returns default health metrics (all zero values)
640    fn default() -> Self {
641        Self {
642            cpu_usage_percent: 0.0,
643            memory_usage_percent: 0.0,
644            temperature_celsius: 0.0,
645            error_count: 0,
646            throughput: 0,
647            network_latency_ms: 0.0,
648            disk_iops: 0,
649            battery_level_percent: 0.0,
650            response_time_ms: 0.0,
651            uptime_seconds: 0,
652        }
653    }
654}
655
656/// Smart device representation
657/// 
658/// This struct represents a smart device in the DMSC system, including its status, capabilities,
659/// health metrics, and lifecycle information.
660#[derive(Debug, Clone, Serialize, Deserialize)]
661#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
662pub struct DMSCDevice {
663    /// Unique device ID
664    id: String,
665    /// Device name
666    name: String,
667    /// Device type
668    device_type: DMSCDeviceType,
669    /// Current device status
670    status: DMSCDeviceStatus,
671    /// Device capabilities for resource allocation
672    capabilities: DMSCDeviceCapabilities,
673    /// Current health metrics
674    health_metrics: DMSCDeviceHealthMetrics,
675    /// Physical location of the device (optional)
676    location: Option<String>,
677    /// Device group (for grouping devices)
678    group: Option<String>,
679    /// Device tags (for filtering and selection)
680    tags: Vec<String>,
681    /// Additional metadata as key-value pairs
682    metadata: HashMap<String, String>,
683    /// Last time the device was seen/updated
684    last_seen: chrono::DateTime<chrono::Utc>,
685    /// ID of the current allocation using this device (if any)
686    current_allocation_id: Option<String>,
687}
688
689impl DMSCDevice {
690    /// Creates a new device with the given name and type
691    /// 
692    /// # Parameters
693    /// 
694    /// - `name`: The name of the device
695    /// - `device_type`: The type of the device
696    /// 
697    /// # Returns
698    /// 
699    /// A new `DMSCDevice` instance with default capabilities and health metrics
700    pub fn new(name: String, device_type: DMSCDeviceType) -> Self {
701        Self {
702            id: Uuid::new_v4().to_string(),
703            name,
704            device_type,
705            status: DMSCDeviceStatus::Unknown,
706            capabilities: DMSCDeviceCapabilities::new(),
707            health_metrics: DMSCDeviceHealthMetrics::default(),
708            location: None,
709            group: None,
710            tags: Vec::new(),
711            metadata: HashMap::new(),
712            last_seen: chrono::Utc::now(),
713            current_allocation_id: None,
714        }
715    }
716    
717    /// Gets the device ID
718    /// 
719    /// # Returns
720    /// 
721    /// The device ID as a string slice
722    pub fn id(&self) -> &str {
723        &self.id
724    }
725    
726    /// Gets the device name
727    /// 
728    /// # Returns
729    /// 
730    /// The device name as a string slice
731    pub fn name(&self) -> &str {
732        &self.name
733    }
734    
735    /// Gets the device type
736    /// 
737    /// # Returns
738    /// 
739    /// The device type as a `DMSCDeviceType` enum
740    pub fn device_type(&self) -> DMSCDeviceType {
741        self.device_type
742    }
743    
744    /// Gets the current device status
745    /// 
746    /// # Returns
747    /// 
748    /// The device status as a `DMSCDeviceStatus` enum
749    pub fn status(&self) -> DMSCDeviceStatus {
750        self.status
751    }
752    
753    /// Gets a reference to the device capabilities
754    /// 
755    /// # Returns
756    /// 
757    /// A reference to the `DMSCDeviceCapabilities` structure
758    pub fn capabilities(&self) -> &DMSCDeviceCapabilities {
759        &self.capabilities
760    }
761    
762    /// Gets a reference to the device health metrics
763    /// 
764    /// # Returns
765    /// 
766    /// A reference to the `DMSCDeviceHealthMetrics` structure
767    pub fn health_metrics(&self) -> &DMSCDeviceHealthMetrics {
768        &self.health_metrics
769    }
770    
771    /// Sets the device status and updates the last seen timestamp
772    /// 
773    /// # Parameters
774    /// 
775    /// - `status`: The new status to set
776    pub fn set_status(&mut self, status: DMSCDeviceStatus) {
777        self.status = status;
778        self.last_seen = chrono::Utc::now();
779    }
780    
781    /// Updates the device health metrics and last seen timestamp
782    /// 
783    /// # Parameters
784    /// 
785    /// - `metrics`: The new health metrics to set
786    pub fn update_health_metrics(&mut self, metrics: DMSCDeviceHealthMetrics) {
787        self.health_metrics = metrics;
788        self.last_seen = chrono::Utc::now();
789    }
790    
791    /// Increments the device error count and updates the last seen timestamp
792    pub fn increment_error_count(&mut self) {
793        self.health_metrics.error_count += 1;
794        self.last_seen = chrono::Utc::now();
795    }
796    
797    /// Updates the device throughput and last seen timestamp
798    /// 
799    /// # Parameters
800    /// 
801    /// - `throughput`: The new throughput value in operations per second
802    pub fn update_throughput(&mut self, throughput: u64) {
803        self.health_metrics.throughput = throughput;
804        self.last_seen = chrono::Utc::now();
805    }
806    
807    /// Sets the device capabilities using the builder pattern
808    /// 
809    /// # Parameters
810    /// 
811    /// - `capabilities`: The new capabilities to set
812    /// 
813    /// # Returns
814    /// 
815    /// The updated `DMSCDevice` instance
816    pub fn with_capabilities(mut self, capabilities: DMSCDeviceCapabilities) -> Self {
817        self.capabilities = capabilities;
818        self
819    }
820    
821    /// Sets the device location
822    /// 
823    /// # Parameters
824    /// 
825    /// - `location`: The physical location of the device
826    pub fn set_location(&mut self, location: String) {
827        self.location = Some(location);
828    }
829    
830    /// Adds a metadata key-value pair to the device
831    /// 
832    /// # Parameters
833    /// 
834    /// - `key`: Metadata key
835    /// - `value`: Metadata value
836    pub fn add_metadata(&mut self, key: String, value: String) {
837        self.metadata.insert(key, value);
838    }
839    
840    /// Updates the last seen timestamp to the current time
841    pub fn update_last_seen(&mut self) {
842        self.last_seen = chrono::Utc::now();
843    }
844    
845    /// Gets the last seen timestamp
846    /// 
847    /// # Returns
848    /// 
849    /// The last seen timestamp as a `chrono::DateTime<chrono::Utc>`
850    pub fn last_seen(&self) -> chrono::DateTime<chrono::Utc> {
851        self.last_seen
852    }
853    
854    /// Checks if the device is available for allocation
855    /// 
856    /// A device is available if its status is Available and it has no current allocation.
857    /// 
858    /// # Returns
859    /// 
860    /// `true` if the device is available, `false` otherwise
861    pub fn is_available(&self) -> bool {
862        self.status == DMSCDeviceStatus::Available && self.current_allocation_id.is_none()
863    }
864    
865    /// Checks if the device is currently allocated
866    /// 
867    /// # Returns
868    /// 
869    /// `true` if the device is allocated, `false` otherwise
870    pub fn is_allocated(&self) -> bool {
871        self.current_allocation_id.is_some()
872    }
873    
874    /// Allocates the device to a specific allocation ID
875    /// 
876    /// This method marks the device as busy and associates it with the given allocation ID.
877    /// 
878    /// # Parameters
879    /// 
880    /// - `allocation_id`: The ID of the allocation using this device
881    /// 
882    /// # Returns
883    /// 
884    /// `true` if the device was successfully allocated, `false` if it was already in use
885    pub fn allocate(&mut self, allocation_id: &str) -> bool {
886        if self.is_available() {
887            self.current_allocation_id = Some(allocation_id.to_string());
888            self.status = DMSCDeviceStatus::Busy;
889            true
890        } else {
891            false
892        }
893    }
894    
895    /// Releases the device from its current allocation
896    /// 
897    /// This method clears the allocation ID and sets the device status to Available if it was Busy.
898    pub fn release(&mut self) {
899        self.current_allocation_id = None;
900        if self.status == DMSCDeviceStatus::Busy {
901            self.status = DMSCDeviceStatus::Available;
902        }
903    }
904    
905    /// Gets the device group
906    /// 
907    /// # Returns
908    /// 
909    /// The device group as an `Option<&str>`
910    pub fn group(&self) -> Option<&str> {
911        self.group.as_deref()
912    }
913    
914    /// Sets the device group
915    /// 
916    /// # Parameters
917    /// 
918    /// - `group`: The new group for the device
919    pub fn set_group(&mut self, group: Option<String>) {
920        self.group = group;
921    }
922    
923    /// Gets the device tags
924    /// 
925    /// # Returns
926    /// 
927    /// A reference to the device tags vector
928    pub fn tags(&self) -> &Vec<String> {
929        &self.tags
930    }
931    
932    /// Adds a tag to the device
933    /// 
934    /// # Parameters
935    /// 
936    /// - `tag`: The tag to add to the device
937    pub fn add_tag(&mut self, tag: String) {
938        if !self.tags.contains(&tag) {
939            self.tags.push(tag);
940        }
941    }
942    
943    /// Removes a tag from the device
944    /// 
945    /// # Parameters
946    /// 
947    /// - `tag`: The tag to remove from the device
948    /// 
949    /// # Returns
950    /// 
951    /// `true` if the tag was removed, `false` if the tag was not found
952    pub fn remove_tag(&mut self, tag: &str) -> bool {
953        let initial_len = self.tags.len();
954        self.tags.retain(|t| t != tag);
955        self.tags.len() < initial_len
956    }
957    
958    /// Checks if the device has a specific tag
959    /// 
960    /// # Parameters
961    /// 
962    /// - `tag`: The tag to check for
963    /// 
964    /// # Returns
965    /// 
966    /// `true` if the device has the tag, `false` otherwise
967    pub fn has_tag(&self, tag: &str) -> bool {
968        self.tags.contains(&tag.to_string())
969    }
970    
971    /// Gets the current allocation ID if the device is allocated
972    /// 
973    /// # Returns
974    /// 
975    /// An `Option<&str>` containing the allocation ID if the device is allocated, `None` otherwise
976    pub fn get_allocation_id(&self) -> Option<&str> {
977        self.current_allocation_id.as_deref()
978    }
979    
980    /// Calculates a simple health score based on device status (0-100)
981    /// 
982    /// This method returns a basic health score based solely on the device status.
983    /// 
984    /// # Returns
985    /// 
986    /// A health score between 0 (worst) and 100 (best)
987    pub fn health_score(&self) -> u8 {
988        match self.status {
989            DMSCDeviceStatus::Available => 100,
990            DMSCDeviceStatus::Busy => 80,
991            DMSCDeviceStatus::Allocated => 80,
992            DMSCDeviceStatus::Maintenance => 60,
993            DMSCDeviceStatus::Degraded => 40,
994            DMSCDeviceStatus::Offline => 20,
995            DMSCDeviceStatus::Error => 10,
996            DMSCDeviceStatus::Unknown => 0,
997        }
998    }
999    
1000    /// Checks if the device is still responsive (last seen within the timeout)
1001    /// 
1002    /// # Parameters
1003    /// 
1004    /// - `timeout_secs`: Maximum number of seconds since last seen for the device to be considered responsive
1005    /// 
1006    /// # Returns
1007    /// 
1008    /// `true` if the device is responsive, `false` otherwise
1009    pub fn is_responsive(&self, timeout_secs: i64) -> bool {
1010        let elapsed = chrono::Utc::now() - self.last_seen;
1011        elapsed.num_seconds() < timeout_secs
1012    }
1013    
1014    /// Calculates a dynamic health score based on multiple factors (0-100)
1015    /// 
1016    /// This method calculates a comprehensive health score based on device status, CPU usage,
1017    /// memory usage, temperature, and error count.
1018    /// 
1019    /// # Parameters
1020    /// 
1021    /// - `health_metrics`: Current health metrics for the device
1022    /// 
1023    /// # Returns
1024    /// 
1025    /// A dynamic health score between 0 (worst) and 100 (best)
1026    pub fn dynamic_health_score(&self, health_metrics: &DMSCDeviceHealthMetrics) -> u8 {
1027        let mut score = self.health_score() as f64;
1028        
1029        // Adjust score based on CPU usage
1030        let cpu_penalty = (health_metrics.cpu_usage_percent / 100.0) * 20.0;
1031        score -= cpu_penalty;
1032        
1033        // Adjust score based on memory usage
1034        let memory_penalty = (health_metrics.memory_usage_percent / 100.0) * 15.0;
1035        score -= memory_penalty;
1036        
1037        // Adjust score based on temperature
1038        let temp_penalty = if health_metrics.temperature_celsius > 80.0 {
1039            (health_metrics.temperature_celsius - 80.0) * 2.0
1040        } else {
1041            0.0
1042        };
1043        score -= temp_penalty;
1044        
1045        // Adjust score based on error count
1046        let error_penalty = (health_metrics.error_count as f64) * 5.0;
1047        score -= error_penalty;
1048        
1049        // Adjust score based on network latency (for network devices)
1050        if matches!(self.device_type, DMSCDeviceType::Network) {
1051            let latency_penalty = if health_metrics.network_latency_ms > 100.0 {
1052                (health_metrics.network_latency_ms - 100.0) * 0.5
1053            } else {
1054                0.0
1055            };
1056            score -= latency_penalty;
1057        }
1058        
1059        // Adjust score based on disk IOPS (for storage devices)
1060        if matches!(self.device_type, DMSCDeviceType::Storage) {
1061            let iops_penalty = if health_metrics.disk_iops < 100 {
1062                (100.0 - health_metrics.disk_iops as f64) * 0.3
1063            } else {
1064                0.0
1065            };
1066            score -= iops_penalty;
1067        }
1068        
1069        // Adjust score based on battery level (for mobile/portable devices)
1070        let battery_penalty = if health_metrics.battery_level_percent < 20.0 {
1071            (20.0 - health_metrics.battery_level_percent) * 2.0
1072        } else {
1073            0.0
1074        };
1075        score -= battery_penalty;
1076        
1077        // Adjust score based on response time
1078        let response_time_penalty = if health_metrics.response_time_ms > 50.0 {
1079            (health_metrics.response_time_ms - 50.0) * 1.0
1080        } else {
1081            0.0
1082        };
1083        score -= response_time_penalty;
1084        
1085        // Ensure score is within 0-100 range
1086        score.clamp(0.0, 100.0) as u8
1087    }
1088    
1089    /// Checks if the device is healthy based on multiple criteria
1090    /// 
1091    /// A device is considered healthy if it is responsive, has a good health score,
1092    /// and is not in an error or offline state.
1093    /// 
1094    /// # Parameters
1095    /// 
1096    /// - `health_metrics`: Current health metrics for the device
1097    /// - `timeout_secs`: Maximum number of seconds since last seen for the device to be considered responsive
1098    /// 
1099    /// # Returns
1100    /// 
1101    /// `true` if the device is healthy, `false` otherwise
1102    pub fn is_healthy(&self, health_metrics: &DMSCDeviceHealthMetrics, timeout_secs: i64) -> bool {
1103        self.is_responsive(timeout_secs) && 
1104        self.dynamic_health_score(health_metrics) > 50 && 
1105        self.status != DMSCDeviceStatus::Error && 
1106        self.status != DMSCDeviceStatus::Offline
1107    }
1108
1109    /// Gets a reference to the device metadata
1110    /// 
1111    /// # Returns
1112    /// 
1113    /// A reference to the metadata HashMap
1114    pub fn metadata(&self) -> &HashMap<String, String> {
1115        &self.metadata
1116    }
1117}
1118
1119#[cfg(feature = "pyo3")]
1120#[pymethods]
1121impl DMSCDevice {
1122    #[new]
1123    fn py_new(name: String, device_type: DMSCDeviceType) -> Self {
1124        Self::new(name, device_type)
1125    }
1126    
1127    #[staticmethod]
1128    fn default_device(name: String, device_type: DMSCDeviceType) -> Self {
1129        Self::new(name, device_type)
1130    }
1131    
1132    #[pyo3(name = "id")]
1133    fn id_impl(&self) -> String {
1134        self.id().to_string()
1135    }
1136    
1137    #[pyo3(name = "name")]
1138    fn name_impl(&self) -> String {
1139        self.name().to_string()
1140    }
1141    
1142    #[pyo3(name = "device_type")]
1143    fn device_type_impl(&self) -> DMSCDeviceType {
1144        self.device_type()
1145    }
1146    
1147    #[pyo3(name = "status")]
1148    fn status_impl(&self) -> DMSCDeviceStatus {
1149        self.status()
1150    }
1151    
1152    #[pyo3(name = "capabilities")]
1153    fn capabilities_impl(&self) -> DMSCDeviceCapabilities {
1154        self.capabilities().clone()
1155    }
1156    
1157    #[pyo3(name = "health_metrics")]
1158    fn health_metrics_impl(&self) -> DMSCDeviceHealthMetrics {
1159        self.health_metrics().clone()
1160    }
1161    
1162    #[pyo3(name = "set_status")]
1163    fn set_status_impl(&mut self, status: DMSCDeviceStatus) {
1164        self.set_status(status)
1165    }
1166    
1167    #[pyo3(name = "update_health_metrics")]
1168    fn update_health_metrics_impl(&mut self, metrics: DMSCDeviceHealthMetrics) {
1169        self.update_health_metrics(metrics)
1170    }
1171    
1172    #[pyo3(name = "increment_error_count")]
1173    fn increment_error_count_impl(&mut self) {
1174        self.increment_error_count()
1175    }
1176    
1177    #[pyo3(name = "update_throughput")]
1178    fn update_throughput_impl(&mut self, throughput: u64) {
1179        self.update_throughput(throughput)
1180    }
1181    
1182    #[pyo3(name = "with_capabilities")]
1183    fn with_capabilities_impl(&self, capabilities: DMSCDeviceCapabilities) -> Self {
1184        self.clone().with_capabilities(capabilities)
1185    }
1186    
1187    #[pyo3(name = "set_location")]
1188    fn set_location_impl(&mut self, location: String) {
1189        self.set_location(location)
1190    }
1191    
1192    #[pyo3(name = "add_metadata")]
1193    fn add_metadata_impl(&mut self, key: String, value: String) {
1194        self.add_metadata(key, value)
1195    }
1196    
1197    #[pyo3(name = "update_last_seen")]
1198    fn update_last_seen_impl(&mut self) {
1199        self.update_last_seen()
1200    }
1201    
1202    #[pyo3(name = "is_available")]
1203    fn is_available_impl(&self) -> bool {
1204        self.is_available()
1205    }
1206    
1207    #[pyo3(name = "is_allocated")]
1208    fn is_allocated_impl(&self) -> bool {
1209        self.is_allocated()
1210    }
1211    
1212    #[pyo3(name = "allocate")]
1213    fn allocate_impl(&mut self, allocation_id: String) -> bool {
1214        self.allocate(&allocation_id)
1215    }
1216    
1217    #[pyo3(name = "release")]
1218    fn release_impl(&mut self) {
1219        self.release()
1220    }
1221    
1222    #[pyo3(name = "group")]
1223    fn group_impl(&self) -> Option<String> {
1224        self.group().map(|s| s.to_string())
1225    }
1226    
1227    #[pyo3(name = "set_group")]
1228    fn set_group_impl(&mut self, group: Option<String>) {
1229        self.set_group(group)
1230    }
1231    
1232    #[pyo3(name = "tags")]
1233    fn tags_impl(&self) -> Vec<String> {
1234        self.tags().clone()
1235    }
1236    
1237    #[pyo3(name = "add_tag")]
1238    fn add_tag_impl(&mut self, tag: String) {
1239        self.add_tag(tag)
1240    }
1241    
1242    #[pyo3(name = "remove_tag")]
1243    fn remove_tag_impl(&mut self, tag: String) -> bool {
1244        self.remove_tag(&tag)
1245    }
1246    
1247    #[pyo3(name = "has_tag")]
1248    fn has_tag_impl(&self, tag: String) -> bool {
1249        self.has_tag(&tag)
1250    }
1251    
1252    #[pyo3(name = "get_allocation_id")]
1253    fn get_allocation_id_impl(&self) -> Option<String> {
1254        self.get_allocation_id().map(|s| s.to_string())
1255    }
1256    
1257    #[pyo3(name = "health_score")]
1258    fn health_score_impl(&self) -> u8 {
1259        self.health_score()
1260    }
1261    
1262    #[pyo3(name = "is_responsive")]
1263    fn is_responsive_impl(&self, timeout_secs: i64) -> bool {
1264        self.is_responsive(timeout_secs)
1265    }
1266    
1267    #[pyo3(name = "dynamic_health_score")]
1268    fn dynamic_health_score_impl(&self, health_metrics: DMSCDeviceHealthMetrics) -> u8 {
1269        self.dynamic_health_score(&health_metrics)
1270    }
1271    
1272    #[pyo3(name = "is_healthy")]
1273    fn is_healthy_impl(&self, health_metrics: DMSCDeviceHealthMetrics, timeout_secs: i64) -> bool {
1274        self.is_healthy(&health_metrics, timeout_secs)
1275    }
1276    
1277    #[pyo3(name = "metadata")]
1278    fn metadata_impl(&self) -> HashMap<String, String> {
1279        self.metadata().clone()
1280    }
1281}