1use std::fmt::Debug;
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4use std::sync::Arc;
5
6use futures_lite::{Stream, StreamExt};
7use static_assertions::assert_impl_all;
8
9use crate::backend::{Backend, BackendType, DynBackend};
10use crate::device::DeviceFeatureHandle;
11use crate::{DeviceReader, DeviceReaderWriter, DeviceWriter, HidResult};
12
13#[non_exhaustive]
31#[derive(Debug, PartialEq, Eq, Clone, Hash)]
32pub enum DeviceId {
33 #[cfg(target_os = "windows")]
34 UncPath(windows::core::HSTRING),
35 #[cfg(target_os = "linux")]
36 DevPath(std::path::PathBuf),
37 #[cfg(target_os = "macos")]
38 RegistryEntryId(u64)
39}
40assert_impl_all!(DeviceId: Send, Sync, Unpin);
41
42#[derive(Debug, Clone, Hash, Eq, PartialEq)]
46pub struct DeviceInfo {
47 pub id: DeviceId,
49 pub name: String,
51 pub product_id: u16,
53 pub vendor_id: u16,
55 pub usage_id: u16,
57 pub usage_page: u16,
59 pub serial_number: Option<String>
61}
62assert_impl_all!(DeviceInfo: Send, Sync, Unpin);
63
64impl DeviceInfo {
65 pub fn matches(&self, usage_page: u16, usage_id: u16, vendor_id: u16, product_id: u16) -> bool {
67 self.usage_page == usage_page && self.usage_id == usage_id && self.vendor_id == vendor_id && self.product_id == product_id
68 }
69}
70
71#[derive(Debug, Clone, Hash, Eq, PartialEq)]
72pub enum DeviceEvent {
73 Connected(DeviceId),
74 Disconnected(DeviceId)
75}
76
77#[derive(Default, Clone)]
79pub struct HidBackend(Arc<DynBackend>);
80
81impl HidBackend {
82 pub fn new(backend: BackendType) -> Self {
85 Self(Arc::new(DynBackend::new(backend)))
86 }
87
88 pub async fn enumerate(&self) -> HidResult<impl Stream<Item = Device> + Send + Unpin + use<'_>> {
92 let steam = self.0.enumerate().await?.filter_map(|result| match result {
93 Ok(info) => Some(Device {
94 backend: self.0.clone(),
95 device_info: info
96 }),
97 Err(_) => None
98 });
99 Ok(steam)
100 }
101
102 pub async fn query_devices(&self, id: &DeviceId) -> HidResult<impl Iterator<Item = Device> + use<'_>> {
104 Ok(self.0.query_info(id).await?.into_iter().map(|info| Device {
105 backend: self.0.clone(),
106 device_info: info
107 }))
108 }
109
110 pub fn watch(&self) -> HidResult<impl Stream<Item = DeviceEvent> + Send + Unpin> {
114 self.0.watch()
115 }
116}
117
118pub struct Device {
120 backend: Arc<DynBackend>,
121 device_info: DeviceInfo
122}
123
124impl Debug for Device {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 f.debug_struct("Device")
127 .field("device_info", &self.device_info)
128 .finish_non_exhaustive()
129 }
130}
131
132impl PartialEq for Device {
133 fn eq(&self, other: &Self) -> bool {
134 Arc::ptr_eq(&self.backend, &other.backend) && DeviceInfo::eq(&self.device_info, &other.device_info)
135 }
136}
137impl Eq for Device {}
138
139impl Hash for Device {
140 fn hash<H: Hasher>(&self, state: &mut H) {
141 DeviceInfo::hash(&self.device_info, state)
142 }
143}
144
145impl Deref for Device {
146 type Target = DeviceInfo;
147
148 fn deref(&self) -> &Self::Target {
149 &self.device_info
150 }
151}
152
153impl Device {
154 pub fn to_device_info(self) -> DeviceInfo {
155 self.device_info
156 }
157
158 pub async fn open_readable(&self) -> HidResult<DeviceReader> {
160 let (r, _) = self.backend.open(&self.id, true, false).await?;
161 Ok(DeviceReader(r.unwrap()))
162 }
163
164 pub async fn open_writeable(&self) -> HidResult<DeviceWriter> {
167 let (_, w) = self.backend.open(&self.id, false, true).await?;
168 Ok(DeviceWriter(w.unwrap()))
169 }
170
171 pub async fn open(&self) -> HidResult<DeviceReaderWriter> {
173 let (r, w) = self.backend.open(&self.id, true, true).await?;
174 Ok((DeviceReader(r.unwrap()), DeviceWriter(w.unwrap())))
175 }
176
177 pub async fn open_feature_handle(&self) -> HidResult<DeviceFeatureHandle> {
179 let r = self.backend.open_feature_handle(&self.id).await?;
180 Ok(DeviceFeatureHandle(r))
181 }
182
183 pub async fn read_feature_report(&self, buf: &mut [u8]) -> HidResult<usize> {
185 self.backend.read_feature_report(&self.id, buf).await
186 }
187}