use std::collections::HashSet;
use bevy::ecs::reflect::ReflectComponent;
use bevy::prelude::Component;
use bevy::prelude::Reflect;
use super::identity::DeviceIdSource;
use super::identity::DeviceKey;
use super::scheme::ReportedId;
#[derive(Clone, PartialEq, Eq, Hash, Debug, Reflect)]
pub enum ReportedSerial {
Provided(ReportedId),
NotExposedByUnit,
PlatformCannotReport,
}
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, Debug, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub enum IdentityVerdict {
Proven,
RestoreOnly,
Authored,
Displaced {
saved: DeviceKey,
},
WrongUnit {
authored: DeviceKey,
},
Unverified(UnverifiedReason),
}
impl IdentityVerdict {
pub(crate) fn concluded_from_scan(
key: &DeviceKey,
duplicate_keys: &HashSet<DeviceKey>,
) -> Self {
if duplicate_keys.contains(key) {
return Self::Unverified(UnverifiedReason::NotUniqueInScan);
}
match key.id {
DeviceIdSource::Reported { .. } => Self::Proven,
DeviceIdSource::Synthesized { .. } => Self::RestoreOnly,
DeviceIdSource::Authored { .. } => Self::Authored,
}
}
#[must_use]
pub(crate) const fn identified(&self) -> bool {
matches!(self, Self::Proven | Self::RestoreOnly | Self::Authored)
}
}
#[derive(Clone, Default, PartialEq, Eq, Debug, Reflect)]
pub enum IdentityDecisionOwed {
#[default]
Nothing,
HumanDecision(IdentityVerdict),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
pub enum UnverifiedReason {
NotExposedByUnit,
NotUniqueInScan,
PlatformCannotReport,
}
#[cfg(test)]
mod tests {
use std::error::Error;
use bevy::reflect::PartialReflect;
use super::IdentityVerdict;
use super::UnverifiedReason;
use crate::DeviceIdSource;
use crate::DeviceKey;
use crate::DeviceKind;
use crate::ReportedId;
use crate::SchemeName;
#[test]
fn identified_is_true_for_confirmed_identity_verdicts() {
for identity_verdict in [
IdentityVerdict::Proven,
IdentityVerdict::RestoreOnly,
IdentityVerdict::Authored,
] {
assert!(identity_verdict.identified());
}
}
#[test]
fn identified_is_false_for_verdicts_without_a_confirmed_identity() -> Result<(), Box<dyn Error>>
{
let saved = reported_display_key()?;
let displaced = IdentityVerdict::Displaced {
saved: saved.clone(),
};
let wrong_unit = IdentityVerdict::WrongUnit { authored: saved };
let unverified = IdentityVerdict::Unverified(UnverifiedReason::NotUniqueInScan);
assert!(!displaced.identified());
assert!(!wrong_unit.identified());
assert!(!unverified.identified());
Ok(())
}
#[test]
fn not_unique_in_scan_prevents_identification() {
let unverified = IdentityVerdict::Unverified(UnverifiedReason::NotUniqueInScan);
assert!(!unverified.identified());
}
#[test]
fn identity_verdicts_compare_by_their_conclusions() {
assert_eq!(IdentityVerdict::Proven, IdentityVerdict::Proven);
assert_ne!(IdentityVerdict::Proven, IdentityVerdict::RestoreOnly);
}
#[test]
fn identity_verdicts_compare_the_keys_they_carry() -> Result<(), Box<dyn Error>> {
let saved = reported_display_key()?;
let displaced = IdentityVerdict::Displaced {
saved: saved.clone(),
};
assert_eq!(
displaced,
IdentityVerdict::Displaced {
saved: saved.clone(),
}
);
assert_ne!(displaced, IdentityVerdict::WrongUnit { authored: saved });
Ok(())
}
#[test]
fn reflected_comparison_answers_for_equal_and_unequal_verdicts() {
assert_eq!(
IdentityVerdict::Proven.reflect_partial_eq(&IdentityVerdict::Proven),
Some(true)
);
assert_eq!(
IdentityVerdict::Proven.reflect_partial_eq(&IdentityVerdict::RestoreOnly),
Some(false)
);
}
fn reported_display_key() -> Result<DeviceKey, Box<dyn Error>> {
Ok(DeviceKey {
kind: DeviceKind::Display,
id: DeviceIdSource::Reported {
scheme: SchemeName::new("edid-serial")?,
value: ReportedId::new("DELL-U2723QE-9J4K2H3")?,
},
})
}
}