1use std::hash::Hash;
2use std::ops::Deref;
3use std::sync::Arc;
4
5use futures_lite::{Stream, StreamExt};
6use static_assertions::assert_impl_all;
7
8use crate::backend::{Backend, BackendType, DynBackend};
9use crate::{DeviceReader, DeviceReaderWriter, DeviceWriter, HidResult};
10
11#[non_exhaustive]
29#[derive(Debug, PartialEq, Eq, Clone, Hash)]
30pub enum DeviceId {
31 #[cfg(target_os = "windows")]
32 UncPath(windows::core::HSTRING),
33 #[cfg(target_os = "linux")]
34 DevPath(std::path::PathBuf),
35 #[cfg(target_os = "macos")]
36 RegistryEntryId(u64)
37}
38assert_impl_all!(DeviceId: Send, Sync, Unpin);
39
40#[derive(Debug, Clone, Hash, Eq, PartialEq)]
44pub struct DeviceInfo {
45 pub id: DeviceId,
47 pub name: String,
49 pub product_id: u16,
51 pub vendor_id: u16,
53 pub usage_id: u16,
55 pub usage_page: u16,
57 pub serial_number: Option<String>
59}
60assert_impl_all!(DeviceInfo: Send, Sync, Unpin);
61
62impl DeviceInfo {
63 pub fn matches(&self, usage_page: u16, usage_id: u16, vendor_id: u16, product_id: u16) -> bool {
65 self.usage_page == usage_page && self.usage_id == usage_id && self.vendor_id == vendor_id && self.product_id == product_id
66 }
67}
68
69#[derive(Default, Clone)]
71pub struct HidBackend(Arc<DynBackend>);
72
73impl HidBackend {
74 pub fn new(backend: BackendType) -> Self {
77 Self(Arc::new(DynBackend::new(backend)))
78 }
79
80 pub async fn enumerate(&self) -> HidResult<impl Stream<Item = Device> + Send + Unpin + '_> {
84 let steam = self.0.enumerate().await?.filter_map(|result| match result {
85 Ok(info) => Some(Device {
86 backend: self.0.clone(),
87 device_info: info
88 }),
89 Err(_) => None
90 });
91 Ok(steam)
92 }
93}
94
95pub struct Device {
97 backend: Arc<DynBackend>,
98 device_info: DeviceInfo
99}
100
101impl Deref for Device {
102 type Target = DeviceInfo;
103
104 fn deref(&self) -> &Self::Target {
105 &self.device_info
106 }
107}
108
109impl Device {
110 pub async fn open_readable(&self) -> HidResult<DeviceReader> {
112 let (r, _) = self.backend.open(&self.id, true, false).await?;
113 Ok(DeviceReader(r.unwrap()))
114 }
115
116 pub async fn open_writeable(&self) -> HidResult<DeviceWriter> {
119 let (_, w) = self.backend.open(&self.id, false, true).await?;
120 Ok(DeviceWriter(w.unwrap()))
121 }
122
123 pub async fn open(&self) -> HidResult<DeviceReaderWriter> {
125 let (r, w) = self.backend.open(&self.id, true, true).await?;
126 Ok((DeviceReader(r.unwrap()), DeviceWriter(w.unwrap())))
127 }
128}