use serde::Serialize;
use std::collections::BTreeSet;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
pub enum SourceKind {
GnssL1,
GnssL5,
GnssMultiBand,
Inertial,
Clock,
Terrain,
Gravity,
Magnetic,
SignalOfOpportunity,
Eloran,
}
impl SourceKind {
pub fn is_gnss_rf(self) -> bool {
matches!(
self,
SourceKind::GnssL1 | SourceKind::GnssL5 | SourceKind::GnssMultiBand
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
pub enum TechniqueCategory {
Obfuscate,
Limit,
Verify,
Isolate,
Diversify,
Mitigate,
Recover,
}
impl TechniqueCategory {
pub fn all() -> [TechniqueCategory; 7] {
use TechniqueCategory::*;
[
Obfuscate, Limit, Verify, Isolate, Diversify, Mitigate, Recover,
]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
pub enum RdrrFunction {
Resist,
Detect,
Respond,
Recover,
}
impl RdrrFunction {
pub fn all() -> [RdrrFunction; 4] {
use RdrrFunction::*;
[Resist, Detect, Respond, Recover]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
pub enum YangCriterion {
Availability,
Reliability,
Continuity,
Accuracy,
}
impl YangCriterion {
pub fn all() -> [YangCriterion; 4] {
use YangCriterion::*;
[Availability, Reliability, Continuity, Accuracy]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
pub struct PntSource {
pub kind: SourceKind,
pub independence_group: u32,
pub quality: f64,
}
impl PntSource {
pub fn new(kind: SourceKind, independence_group: u32, quality: f64) -> Self {
PntSource {
kind,
independence_group,
quality,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct PntArchitecture {
pub name: String,
pub sources: Vec<PntSource>,
pub techniques: BTreeSet<TechniqueCategory>,
}
impl PntArchitecture {
pub fn new(
name: impl Into<String>,
sources: Vec<PntSource>,
techniques: impl IntoIterator<Item = TechniqueCategory>,
) -> Self {
PntArchitecture {
name: name.into(),
sources,
techniques: techniques.into_iter().collect(),
}
}
pub fn independent_group_count(&self) -> usize {
self.sources
.iter()
.map(|s| s.independence_group)
.collect::<BTreeSet<_>>()
.len()
}
pub fn has(&self, t: TechniqueCategory) -> bool {
self.techniques.contains(&t)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn arch() -> PntArchitecture {
PntArchitecture::new(
"test",
vec![
PntSource::new(SourceKind::GnssL1, 1, 1.0),
PntSource::new(SourceKind::GnssL5, 1, 1.0),
PntSource::new(SourceKind::Inertial, 2, 0.6),
],
[TechniqueCategory::Verify, TechniqueCategory::Diversify],
)
}
#[test]
fn independent_group_count_counts_distinct_failure_domains() {
assert_eq!(arch().independent_group_count(), 2);
}
#[test]
fn has_reports_technique_membership() {
let a = arch();
assert!(a.has(TechniqueCategory::Verify));
assert!(a.has(TechniqueCategory::Diversify));
assert!(!a.has(TechniqueCategory::Recover));
}
#[test]
fn gnss_rf_common_mode_classification() {
assert!(SourceKind::GnssL1.is_gnss_rf());
assert!(SourceKind::GnssMultiBand.is_gnss_rf());
assert!(!SourceKind::Inertial.is_gnss_rf());
assert!(!SourceKind::Eloran.is_gnss_rf());
}
#[test]
fn category_sets_are_complete() {
assert_eq!(TechniqueCategory::all().len(), 7);
assert_eq!(RdrrFunction::all().len(), 4);
assert_eq!(YangCriterion::all().len(), 4);
}
}