use std::time::Duration;
use bevy::ecs::reflect::ReflectComponent;
use bevy::prelude::Component;
use bevy::prelude::Reflect;
use bevy::prelude::World;
use crate::AttachmentPath;
use crate::Capabilities;
use crate::Claim;
use crate::DeviceDescriptor;
use crate::DeviceKey;
use crate::PlatformDeviceHandle;
use crate::ReportedSerial;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub enum Presence {
Present,
Absent,
Unreachable {
since: Duration,
},
}
impl Presence {
pub(crate) const fn is_same_variant(self, other: Self) -> bool {
matches!(
(self, other),
(Self::Present, Self::Present)
| (Self::Absent, Self::Absent)
| (Self::Unreachable { .. }, Self::Unreachable { .. })
)
}
}
#[derive(Clone, PartialEq, Eq, Debug, Reflect)]
pub enum ReportedAs {
Keyed(DeviceKey),
MatchEvidenceOnly,
}
#[derive(Clone, PartialEq, Eq, Debug, Reflect)]
pub enum ReportedParent {
Root,
ChildOf(DeviceKey),
}
pub struct DeviceRecord {
pub reported_as: ReportedAs,
pub parent: ReportedParent,
pub presence: Presence,
pub claim: Claim,
pub capabilities: Capabilities,
pub serial: ReportedSerial,
pub platform_device_handle: PlatformDeviceHandle,
pub attachment: AttachmentPath,
pub descriptor: DeviceDescriptor,
}
pub enum DeviceScan {
Complete(Vec<DeviceRecord>),
CompleteWithProjection {
devices: Vec<DeviceRecord>,
report_acceptance_projection: ReportAcceptanceProjection,
},
Failed(crate::DeviceAccessError),
}
pub struct ReportAcceptanceProjection(Box<dyn FnOnce(&mut World) + Send + Sync + 'static>);
impl ReportAcceptanceProjection {
#[must_use]
pub fn new(publish: impl FnOnce(&mut World) + Send + Sync + 'static) -> Self {
Self(Box::new(publish))
}
pub(crate) fn publish(self, world: &mut World) { self.0(world); }
}
pub(crate) struct DeviceSet {
pub(crate) devices: Vec<DeviceRecord>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
#[reflect(opaque)]
pub struct ReporterId(pub(crate) u32);
#[cfg(test)]
mod tests {
use std::time::Duration;
use bevy::reflect::FromReflect;
use bevy::reflect::tuple_struct::DynamicTupleStruct;
use super::DeviceRecord;
use super::Presence;
use super::ReportedAs;
use super::ReportedParent;
use super::ReporterId;
use crate::AttachmentPath;
use crate::Capabilities;
use crate::Claim;
use crate::DeviceDescriptor;
use crate::PlatformDeviceHandle;
use crate::ReportedSerial;
#[test]
fn unreachable_presence_retains_when_the_reporter_lost_contact() {
let since = Duration::from_secs(6);
let presence = Presence::Unreachable { since };
assert_eq!(presence, Presence::Unreachable { since });
}
#[test]
fn evidence_only_record_has_no_reported_device_key() {
let device_record = DeviceRecord {
reported_as: ReportedAs::MatchEvidenceOnly,
parent: ReportedParent::Root,
presence: Presence::Present,
claim: Claim::NotApplicable,
capabilities: Capabilities::new(),
serial: ReportedSerial::NotExposedByUnit,
platform_device_handle: PlatformDeviceHandle::PlatformReportedNothing,
attachment: AttachmentPath::PlatformHasNoConcept,
descriptor: DeviceDescriptor::PlatformReportedNothing,
};
assert!(matches!(
device_record.reported_as,
ReportedAs::MatchEvidenceOnly
));
assert_eq!(device_record.parent, ReportedParent::Root);
}
#[test]
fn reflection_cannot_construct_reporter_id() {
let mut dynamic_reporter_id = DynamicTupleStruct::default();
dynamic_reporter_id.insert(0_u32);
assert!(ReporterId::from_reflect(&dynamic_reporter_id).is_none());
}
}