1#![allow(non_snake_case)]
19
20use serde::{Serialize, Deserialize};
72use std::collections::HashMap;
73use uuid::Uuid;
74
75#[cfg(feature = "pyo3")]
76use pyo3::prelude::*;
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
81pub struct DMSCDeviceControlConfig {
82 pub enable_cpu_discovery: bool,
84 pub enable_gpu_discovery: bool,
86 pub enable_memory_discovery: bool,
88 pub enable_storage_discovery: bool,
90 pub enable_network_discovery: bool,
92 pub discovery_timeout_secs: u64,
94 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#[derive(Debug, Clone, Serialize, Deserialize)]
142#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
143pub struct DMSCDeviceConfig {
144 pub enable_cpu_discovery: bool,
146 pub enable_gpu_discovery: bool,
148 pub enable_memory_discovery: bool,
150 pub enable_storage_discovery: bool,
152 pub enable_network_discovery: bool,
154 pub discovery_timeout_secs: u64,
156 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#[derive(Debug, Clone, Serialize, Deserialize)]
190#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
191pub struct DMSCNetworkDeviceInfo {
192 pub id: String,
194 pub device_type: String,
196 pub source: String,
198 pub compute_units: Option<usize>,
200 pub memory_gb: Option<f64>,
202 pub storage_gb: Option<f64>,
204 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
235#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
236pub enum DMSCDeviceType {
237 CPU,
239 GPU,
241 Memory,
243 Storage,
245 Network,
247 Sensor,
249 Actuator,
251 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#[derive(Debug, Clone, Serialize, Deserialize)]
323#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
324pub struct DMSCDeviceCapabilities {
325 pub compute_units: Option<usize>,
327 pub memory_gb: Option<f64>,
329 pub storage_gb: Option<f64>,
331 pub bandwidth_gbps: Option<f64>,
333 pub custom_capabilities: HashMap<String, String>,
335}
336
337impl Default for DMSCDeviceCapabilities {
338 fn default() -> Self {
340 Self::new()
341 }
342}
343
344impl DMSCDeviceCapabilities {
345 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 pub fn with_compute_units(mut self, units: usize) -> Self {
370 self.compute_units = Some(units);
371 self
372 }
373
374 pub fn with_memory_gb(mut self, memory: f64) -> Self {
384 self.memory_gb = Some(memory);
385 self
386 }
387
388 pub fn with_storage_gb(mut self, storage: f64) -> Self {
398 self.storage_gb = Some(storage);
399 self
400 }
401
402 pub fn with_bandwidth_gbps(mut self, bandwidth: f64) -> Self {
412 self.bandwidth_gbps = Some(bandwidth);
413 self
414 }
415
416 pub fn with_custom_capability(mut self, key: String, value: String) -> Self {
427 self.custom_capabilities.insert(key, value);
428 self
429 }
430
431 pub fn meets_requirements(&self, requirements: &DMSCDeviceCapabilities) -> bool {
444 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; }
453 }
454
455 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; }
464 }
465
466 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; }
475 }
476
477 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; }
486 }
487
488 for (key, required_value) in &requirements.custom_capabilities {
490 match self.custom_capabilities.get(key) {
491 Some(available_value) => {
492 if available_value != required_value {
494 return false;
495 }
496 }
497 None => return false, }
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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
588#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
589pub enum DMSCDeviceStatus {
590 Unknown,
592 Available,
594 Busy,
596 Error,
598 Offline,
600 Maintenance,
602 Degraded,
604 Allocated,
606}
607
608
609
610#[derive(Debug, Clone, Serialize, Deserialize)]
614#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
615pub struct DMSCDeviceHealthMetrics {
616 pub cpu_usage_percent: f64,
618 pub memory_usage_percent: f64,
620 pub temperature_celsius: f64,
622 pub error_count: u32,
624 pub throughput: u64, pub network_latency_ms: f64,
628 pub disk_iops: u64,
630 pub battery_level_percent: f64,
632 pub response_time_ms: f64,
634 pub uptime_seconds: u64,
636}
637
638impl Default for DMSCDeviceHealthMetrics {
639 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#[derive(Debug, Clone, Serialize, Deserialize)]
661#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
662pub struct DMSCDevice {
663 id: String,
665 name: String,
667 device_type: DMSCDeviceType,
669 status: DMSCDeviceStatus,
671 capabilities: DMSCDeviceCapabilities,
673 health_metrics: DMSCDeviceHealthMetrics,
675 location: Option<String>,
677 group: Option<String>,
679 tags: Vec<String>,
681 metadata: HashMap<String, String>,
683 last_seen: chrono::DateTime<chrono::Utc>,
685 current_allocation_id: Option<String>,
687}
688
689impl DMSCDevice {
690 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 pub fn id(&self) -> &str {
723 &self.id
724 }
725
726 pub fn name(&self) -> &str {
732 &self.name
733 }
734
735 pub fn device_type(&self) -> DMSCDeviceType {
741 self.device_type
742 }
743
744 pub fn status(&self) -> DMSCDeviceStatus {
750 self.status
751 }
752
753 pub fn capabilities(&self) -> &DMSCDeviceCapabilities {
759 &self.capabilities
760 }
761
762 pub fn health_metrics(&self) -> &DMSCDeviceHealthMetrics {
768 &self.health_metrics
769 }
770
771 pub fn set_status(&mut self, status: DMSCDeviceStatus) {
777 self.status = status;
778 self.last_seen = chrono::Utc::now();
779 }
780
781 pub fn update_health_metrics(&mut self, metrics: DMSCDeviceHealthMetrics) {
787 self.health_metrics = metrics;
788 self.last_seen = chrono::Utc::now();
789 }
790
791 pub fn increment_error_count(&mut self) {
793 self.health_metrics.error_count += 1;
794 self.last_seen = chrono::Utc::now();
795 }
796
797 pub fn update_throughput(&mut self, throughput: u64) {
803 self.health_metrics.throughput = throughput;
804 self.last_seen = chrono::Utc::now();
805 }
806
807 pub fn with_capabilities(mut self, capabilities: DMSCDeviceCapabilities) -> Self {
817 self.capabilities = capabilities;
818 self
819 }
820
821 pub fn set_location(&mut self, location: String) {
827 self.location = Some(location);
828 }
829
830 pub fn add_metadata(&mut self, key: String, value: String) {
837 self.metadata.insert(key, value);
838 }
839
840 pub fn update_last_seen(&mut self) {
842 self.last_seen = chrono::Utc::now();
843 }
844
845 pub fn last_seen(&self) -> chrono::DateTime<chrono::Utc> {
851 self.last_seen
852 }
853
854 pub fn is_available(&self) -> bool {
862 self.status == DMSCDeviceStatus::Available && self.current_allocation_id.is_none()
863 }
864
865 pub fn is_allocated(&self) -> bool {
871 self.current_allocation_id.is_some()
872 }
873
874 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 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 pub fn group(&self) -> Option<&str> {
911 self.group.as_deref()
912 }
913
914 pub fn set_group(&mut self, group: Option<String>) {
920 self.group = group;
921 }
922
923 pub fn tags(&self) -> &Vec<String> {
929 &self.tags
930 }
931
932 pub fn add_tag(&mut self, tag: String) {
938 if !self.tags.contains(&tag) {
939 self.tags.push(tag);
940 }
941 }
942
943 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 pub fn has_tag(&self, tag: &str) -> bool {
968 self.tags.contains(&tag.to_string())
969 }
970
971 pub fn get_allocation_id(&self) -> Option<&str> {
977 self.current_allocation_id.as_deref()
978 }
979
980 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 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 pub fn dynamic_health_score(&self, health_metrics: &DMSCDeviceHealthMetrics) -> u8 {
1027 let mut score = self.health_score() as f64;
1028
1029 let cpu_penalty = (health_metrics.cpu_usage_percent / 100.0) * 20.0;
1031 score -= cpu_penalty;
1032
1033 let memory_penalty = (health_metrics.memory_usage_percent / 100.0) * 15.0;
1035 score -= memory_penalty;
1036
1037 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 let error_penalty = (health_metrics.error_count as f64) * 5.0;
1047 score -= error_penalty;
1048
1049 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 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 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 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 score.clamp(0.0, 100.0) as u8
1087 }
1088
1089 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 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}