1use super::{QoSClass, QoSPolicy};
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum DataType {
16 ContactReport,
21 EmergencyAlert,
23 AbortCommand,
25 RoeUpdate,
27
28 TargetImage,
33 AudioIntercept,
35 MissionRetasking,
37 FormationChange,
39
40 HealthStatus,
45 CapabilityChange,
47 FormationUpdate,
49 TaskAssignment,
51
52 PositionUpdate,
57 Heartbeat,
59 SensorTelemetry,
61 EnvironmentData,
63
64 ModelUpdate,
69 DebugLog,
71 HistoricalTrack,
73 TrainingData,
75
76 Custom {
81 name: String,
83 qos_class: QoSClass,
85 },
86}
87
88impl DataType {
89 pub fn default_class(&self) -> QoSClass {
91 match self {
92 Self::ContactReport | Self::EmergencyAlert | Self::AbortCommand | Self::RoeUpdate => {
94 QoSClass::Critical
95 }
96
97 Self::TargetImage
99 | Self::AudioIntercept
100 | Self::MissionRetasking
101 | Self::FormationChange => QoSClass::High,
102
103 Self::HealthStatus
105 | Self::CapabilityChange
106 | Self::FormationUpdate
107 | Self::TaskAssignment => QoSClass::Normal,
108
109 Self::PositionUpdate
111 | Self::Heartbeat
112 | Self::SensorTelemetry
113 | Self::EnvironmentData => QoSClass::Low,
114
115 Self::ModelUpdate | Self::DebugLog | Self::HistoricalTrack | Self::TrainingData => {
117 QoSClass::Bulk
118 }
119
120 Self::Custom { qos_class, .. } => *qos_class,
122 }
123 }
124
125 pub fn default_policy(&self) -> QoSPolicy {
127 match self {
128 Self::ContactReport => QoSPolicy {
130 base_class: QoSClass::Critical,
131 max_latency_ms: Some(500),
132 max_size_bytes: Some(32 * 1024), ttl_seconds: None, retention_priority: 5,
135 preemptable: false,
136 },
137 Self::EmergencyAlert => QoSPolicy {
138 base_class: QoSClass::Critical,
139 max_latency_ms: Some(500),
140 max_size_bytes: Some(8 * 1024), ttl_seconds: None,
142 retention_priority: 5,
143 preemptable: false,
144 },
145 Self::AbortCommand => QoSPolicy {
146 base_class: QoSClass::Critical,
147 max_latency_ms: Some(500),
148 max_size_bytes: Some(1024), ttl_seconds: None,
150 retention_priority: 5,
151 preemptable: false,
152 },
153 Self::RoeUpdate => QoSPolicy {
154 base_class: QoSClass::Critical,
155 max_latency_ms: Some(500),
156 max_size_bytes: Some(64 * 1024), ttl_seconds: None,
158 retention_priority: 5,
159 preemptable: false,
160 },
161
162 Self::TargetImage => QoSPolicy {
164 base_class: QoSClass::High,
165 max_latency_ms: Some(5_000),
166 max_size_bytes: Some(10 * 1024 * 1024), ttl_seconds: Some(3600), retention_priority: 4,
169 preemptable: true,
170 },
171 Self::AudioIntercept => QoSPolicy {
172 base_class: QoSClass::High,
173 max_latency_ms: Some(5_000),
174 max_size_bytes: Some(5 * 1024 * 1024), ttl_seconds: Some(3600),
176 retention_priority: 4,
177 preemptable: true,
178 },
179 Self::MissionRetasking => QoSPolicy {
180 base_class: QoSClass::High,
181 max_latency_ms: Some(2_000), max_size_bytes: Some(64 * 1024),
183 ttl_seconds: Some(7200), retention_priority: 4,
185 preemptable: false, },
187 Self::FormationChange => QoSPolicy {
188 base_class: QoSClass::High,
189 max_latency_ms: Some(5_000),
190 max_size_bytes: Some(16 * 1024),
191 ttl_seconds: Some(3600),
192 retention_priority: 4,
193 preemptable: true,
194 },
195
196 Self::HealthStatus => QoSPolicy {
198 base_class: QoSClass::Normal,
199 max_latency_ms: Some(60_000), max_size_bytes: Some(8 * 1024),
201 ttl_seconds: Some(86400), retention_priority: 3,
203 preemptable: true,
204 },
205 Self::CapabilityChange => QoSPolicy {
206 base_class: QoSClass::Normal,
207 max_latency_ms: Some(60_000),
208 max_size_bytes: Some(16 * 1024),
209 ttl_seconds: Some(86400),
210 retention_priority: 3,
211 preemptable: true,
212 },
213 Self::FormationUpdate => QoSPolicy {
214 base_class: QoSClass::Normal,
215 max_latency_ms: Some(60_000),
216 max_size_bytes: Some(32 * 1024),
217 ttl_seconds: Some(43200), retention_priority: 3,
219 preemptable: true,
220 },
221 Self::TaskAssignment => QoSPolicy {
222 base_class: QoSClass::Normal,
223 max_latency_ms: Some(30_000), max_size_bytes: Some(16 * 1024),
225 ttl_seconds: Some(86400),
226 retention_priority: 3,
227 preemptable: true,
228 },
229
230 Self::PositionUpdate => QoSPolicy {
232 base_class: QoSClass::Low,
233 max_latency_ms: Some(300_000), max_size_bytes: Some(1024), ttl_seconds: Some(86400), retention_priority: 2,
237 preemptable: true,
238 },
239 Self::Heartbeat => QoSPolicy {
240 base_class: QoSClass::Low,
241 max_latency_ms: Some(300_000),
242 max_size_bytes: Some(256), ttl_seconds: Some(3600), retention_priority: 1, preemptable: true,
246 },
247 Self::SensorTelemetry => QoSPolicy {
248 base_class: QoSClass::Low,
249 max_latency_ms: Some(300_000),
250 max_size_bytes: Some(64 * 1024),
251 ttl_seconds: Some(43200), retention_priority: 2,
253 preemptable: true,
254 },
255 Self::EnvironmentData => QoSPolicy {
256 base_class: QoSClass::Low,
257 max_latency_ms: Some(600_000), max_size_bytes: Some(128 * 1024),
259 ttl_seconds: Some(86400),
260 retention_priority: 2,
261 preemptable: true,
262 },
263
264 Self::ModelUpdate => QoSPolicy {
266 base_class: QoSClass::Bulk,
267 max_latency_ms: None, max_size_bytes: Some(500 * 1024 * 1024), ttl_seconds: Some(604800), retention_priority: 2, preemptable: true,
272 },
273 Self::DebugLog => QoSPolicy {
274 base_class: QoSClass::Bulk,
275 max_latency_ms: None,
276 max_size_bytes: Some(10 * 1024 * 1024), ttl_seconds: Some(259200), retention_priority: 1, preemptable: true,
280 },
281 Self::HistoricalTrack => QoSPolicy {
282 base_class: QoSClass::Bulk,
283 max_latency_ms: None,
284 max_size_bytes: Some(100 * 1024 * 1024), ttl_seconds: Some(604800), retention_priority: 2,
287 preemptable: true,
288 },
289 Self::TrainingData => QoSPolicy {
290 base_class: QoSClass::Bulk,
291 max_latency_ms: None,
292 max_size_bytes: Some(1024 * 1024 * 1024), ttl_seconds: Some(2592000), retention_priority: 2,
295 preemptable: true,
296 },
297
298 Self::Custom { qos_class, .. } => match qos_class {
300 QoSClass::Critical => QoSPolicy::critical(),
301 QoSClass::High => QoSPolicy::high(),
302 QoSClass::Normal => QoSPolicy::default(),
303 QoSClass::Low => QoSPolicy::low(),
304 QoSClass::Bulk => QoSPolicy::bulk(),
305 },
306 }
307 }
308
309 pub fn is_critical(&self) -> bool {
311 self.default_class() == QoSClass::Critical
312 }
313
314 pub fn is_preemptable(&self) -> bool {
316 self.default_policy().preemptable
317 }
318
319 pub fn all_predefined() -> &'static [DataType] {
321 &[
322 DataType::ContactReport,
324 DataType::EmergencyAlert,
325 DataType::AbortCommand,
326 DataType::RoeUpdate,
327 DataType::TargetImage,
329 DataType::AudioIntercept,
330 DataType::MissionRetasking,
331 DataType::FormationChange,
332 DataType::HealthStatus,
334 DataType::CapabilityChange,
335 DataType::FormationUpdate,
336 DataType::TaskAssignment,
337 DataType::PositionUpdate,
339 DataType::Heartbeat,
340 DataType::SensorTelemetry,
341 DataType::EnvironmentData,
342 DataType::ModelUpdate,
344 DataType::DebugLog,
345 DataType::HistoricalTrack,
346 DataType::TrainingData,
347 ]
348 }
349}
350
351impl fmt::Display for DataType {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 match self {
354 Self::ContactReport => write!(f, "ContactReport"),
355 Self::EmergencyAlert => write!(f, "EmergencyAlert"),
356 Self::AbortCommand => write!(f, "AbortCommand"),
357 Self::RoeUpdate => write!(f, "RoeUpdate"),
358 Self::TargetImage => write!(f, "TargetImage"),
359 Self::AudioIntercept => write!(f, "AudioIntercept"),
360 Self::MissionRetasking => write!(f, "MissionRetasking"),
361 Self::FormationChange => write!(f, "FormationChange"),
362 Self::HealthStatus => write!(f, "HealthStatus"),
363 Self::CapabilityChange => write!(f, "CapabilityChange"),
364 Self::FormationUpdate => write!(f, "FormationUpdate"),
365 Self::TaskAssignment => write!(f, "TaskAssignment"),
366 Self::PositionUpdate => write!(f, "PositionUpdate"),
367 Self::Heartbeat => write!(f, "Heartbeat"),
368 Self::SensorTelemetry => write!(f, "SensorTelemetry"),
369 Self::EnvironmentData => write!(f, "EnvironmentData"),
370 Self::ModelUpdate => write!(f, "ModelUpdate"),
371 Self::DebugLog => write!(f, "DebugLog"),
372 Self::HistoricalTrack => write!(f, "HistoricalTrack"),
373 Self::TrainingData => write!(f, "TrainingData"),
374 Self::Custom { name, .. } => write!(f, "Custom({})", name),
375 }
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382
383 #[test]
384 fn test_data_type_default_class() {
385 assert_eq!(DataType::ContactReport.default_class(), QoSClass::Critical);
387 assert_eq!(DataType::EmergencyAlert.default_class(), QoSClass::Critical);
388 assert_eq!(DataType::AbortCommand.default_class(), QoSClass::Critical);
389
390 assert_eq!(DataType::TargetImage.default_class(), QoSClass::High);
392 assert_eq!(DataType::MissionRetasking.default_class(), QoSClass::High);
393
394 assert_eq!(DataType::HealthStatus.default_class(), QoSClass::Normal);
396 assert_eq!(DataType::CapabilityChange.default_class(), QoSClass::Normal);
397
398 assert_eq!(DataType::PositionUpdate.default_class(), QoSClass::Low);
400 assert_eq!(DataType::Heartbeat.default_class(), QoSClass::Low);
401
402 assert_eq!(DataType::ModelUpdate.default_class(), QoSClass::Bulk);
404 assert_eq!(DataType::DebugLog.default_class(), QoSClass::Bulk);
405 }
406
407 #[test]
408 fn test_data_type_default_policy() {
409 let policy = DataType::ContactReport.default_policy();
410 assert_eq!(policy.base_class, QoSClass::Critical);
411 assert_eq!(policy.max_latency_ms, Some(500));
412 assert!(!policy.preemptable);
413
414 let policy = DataType::PositionUpdate.default_policy();
415 assert_eq!(policy.base_class, QoSClass::Low);
416 assert_eq!(policy.max_latency_ms, Some(300_000));
417 assert!(policy.preemptable);
418 }
419
420 #[test]
421 fn test_data_type_is_critical() {
422 assert!(DataType::ContactReport.is_critical());
423 assert!(DataType::EmergencyAlert.is_critical());
424 assert!(!DataType::HealthStatus.is_critical());
425 assert!(!DataType::DebugLog.is_critical());
426 }
427
428 #[test]
429 fn test_data_type_is_preemptable() {
430 assert!(!DataType::ContactReport.is_preemptable());
431 assert!(!DataType::AbortCommand.is_preemptable());
432 assert!(!DataType::MissionRetasking.is_preemptable()); assert!(DataType::TargetImage.is_preemptable());
434 assert!(DataType::HealthStatus.is_preemptable());
435 }
436
437 #[test]
438 fn test_custom_data_type() {
439 let custom = DataType::Custom {
440 name: "MyType".to_string(),
441 qos_class: QoSClass::High,
442 };
443 assert_eq!(custom.default_class(), QoSClass::High);
444 assert_eq!(custom.to_string(), "Custom(MyType)");
445 }
446
447 #[test]
448 fn test_all_predefined_data_types() {
449 let all = DataType::all_predefined();
450 assert_eq!(all.len(), 20);
451
452 for dt in all {
454 let policy = dt.default_policy();
455 assert!(policy.retention_priority >= 1 && policy.retention_priority <= 5);
456 }
457 }
458
459 #[test]
460 fn test_data_type_serialization() {
461 let dt = DataType::ContactReport;
462 let json = serde_json::to_string(&dt).unwrap();
463 assert_eq!(json, "\"ContactReport\"");
464
465 let deserialized: DataType = serde_json::from_str(&json).unwrap();
466 assert_eq!(deserialized, DataType::ContactReport);
467 }
468
469 #[test]
470 fn test_model_update_large_size() {
471 let policy = DataType::ModelUpdate.default_policy();
473 assert_eq!(policy.max_size_bytes, Some(500 * 1024 * 1024)); }
475}