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 manufacturer: Option<String>,
53 pub product_id: u16,
55 pub vendor_id: u16,
57 pub usage_id: u16,
59 pub usage_page: u16,
61 pub serial_number: Option<String>
63}
64assert_impl_all!(DeviceInfo: Send, Sync, Unpin);
65
66impl DeviceInfo {
67 pub fn matches(&self, usage_page: u16, usage_id: u16, vendor_id: u16, product_id: u16) -> bool {
69 self.usage_page == usage_page && self.usage_id == usage_id && self.vendor_id == vendor_id && self.product_id == product_id
70 }
71}
72
73#[derive(Debug, Clone, Hash, Eq, PartialEq)]
74pub enum DeviceEvent {
75 Connected(DeviceId),
76 Disconnected(DeviceId)
77}
78
79#[derive(Default, Clone)]
81pub struct HidBackend(Arc<DynBackend>);
82
83impl HidBackend {
84 pub fn new(backend: BackendType) -> Self {
87 Self(Arc::new(DynBackend::new(backend)))
88 }
89
90 pub async fn enumerate(&self) -> HidResult<impl Stream<Item = Device> + Send + Unpin + use<'_>> {
94 let steam = self.0.enumerate().await?.filter_map(|result| match result {
95 Ok(info) => Some(Device {
96 backend: self.0.clone(),
97 device_info: info
98 }),
99 Err(_) => None
100 });
101 Ok(steam)
102 }
103
104 pub async fn query_devices(&self, id: &DeviceId) -> HidResult<impl Iterator<Item = Device> + use<'_>> {
106 Ok(self.0.query_info(id).await?.into_iter().map(|info| Device {
107 backend: self.0.clone(),
108 device_info: info
109 }))
110 }
111
112 pub fn watch(&self) -> HidResult<impl Stream<Item = DeviceEvent> + Send + Unpin> {
116 self.0.watch()
117 }
118}
119
120pub struct Device {
122 backend: Arc<DynBackend>,
123 device_info: DeviceInfo
124}
125
126impl Debug for Device {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 f.debug_struct("Device")
129 .field("device_info", &self.device_info)
130 .finish_non_exhaustive()
131 }
132}
133
134impl PartialEq for Device {
135 fn eq(&self, other: &Self) -> bool {
136 Arc::ptr_eq(&self.backend, &other.backend) && DeviceInfo::eq(&self.device_info, &other.device_info)
137 }
138}
139impl Eq for Device {}
140
141impl Hash for Device {
142 fn hash<H: Hasher>(&self, state: &mut H) {
143 DeviceInfo::hash(&self.device_info, state)
144 }
145}
146
147impl Deref for Device {
148 type Target = DeviceInfo;
149
150 fn deref(&self) -> &Self::Target {
151 &self.device_info
152 }
153}
154
155impl Device {
156 pub fn to_device_info(self) -> DeviceInfo {
157 self.device_info
158 }
159
160 pub async fn open_readable(&self) -> HidResult<DeviceReader> {
162 let (r, _) = self.backend.open(&self.id, true, false).await?;
163 Ok(DeviceReader(r.unwrap()))
164 }
165
166 pub async fn open_writeable(&self) -> HidResult<DeviceWriter> {
169 let (_, w) = self.backend.open(&self.id, false, true).await?;
170 Ok(DeviceWriter(w.unwrap()))
171 }
172
173 pub async fn open(&self) -> HidResult<DeviceReaderWriter> {
175 let (r, w) = self.backend.open(&self.id, true, true).await?;
176 Ok((DeviceReader(r.unwrap()), DeviceWriter(w.unwrap())))
177 }
178
179 pub async fn open_feature_handle(&self) -> HidResult<DeviceFeatureHandle> {
181 let r = self.backend.open_feature_handle(&self.id).await?;
182 Ok(DeviceFeatureHandle(r))
183 }
184
185 pub async fn read_feature_report(&self, buf: &mut [u8]) -> HidResult<usize> {
187 self.backend.read_feature_report(&self.id, buf).await
188 }
189}