1#![doc = include_str!("../README.md")]
2
3mod backend;
4mod error;
5
6use std::fmt::{Debug, Formatter};
7use std::future::Future;
8use std::hash::{Hash, Hasher};
9
10use futures_core::Stream;
11use static_assertions::assert_impl_all;
12use crate::backend::{BackendDevice, BackendDeviceId, BackendPrivateData};
13pub use crate::error::{ErrorSource, HidError, HidResult};
14
15#[derive(Debug, Clone)]
19pub struct DeviceInfo {
20 pub id: DeviceId,
22 pub name: String,
24 pub product_id: u16,
26 pub vendor_id: u16,
28 pub usage_id: u16,
30 pub usage_page: u16,
32
33 pub(crate) private_data: BackendPrivateData,
34}
35
36impl DeviceInfo {
37 pub fn enumerate() -> impl Future<Output = HidResult<impl Stream<Item = DeviceInfo> + Unpin + Send>> {
42 backend::enumerate()
43 }
44
45 pub async fn open(&self, mode: AccessMode) -> HidResult<Device> {
47 let dev = backend::open(&self.id.0, mode).await?;
48 Ok(Device {
49 inner: dev,
50 info: self.clone(),
51 mode
52 })
53 }
54
55 pub fn matches(&self, usage_page: u16, usage_id: u16, vendor_id: u16, product_id: u16) -> bool {
57 self.usage_page == usage_page && self.usage_id == usage_id && self.vendor_id == vendor_id && self.product_id == product_id
58 }
59}
60
61impl Hash for DeviceInfo {
62 fn hash<H: Hasher>(&self, state: &mut H) {
63 self.id.hash(state);
64 self.name.hash(state);
65 self.product_id.hash(state);
66 self.vendor_id.hash(state);
67 self.usage_id.hash(state);
68 self.usage_page.hash(state);
69 }
70}
71
72impl PartialEq for DeviceInfo {
73 fn eq(&self, other: &Self) -> bool {
74 self.id == other.id
75 && self.name == other.name
76 && self.product_id == other.product_id
77 && self.vendor_id == other.vendor_id
78 && self.usage_id == other.usage_id
79 && self.usage_page == other.usage_page
80 }
81}
82
83impl Eq for DeviceInfo {}
84
85pub trait SerialNumberExt {
86 fn serial_number(&self) -> Option<&str>;
87}
88
89pub struct Device {
93 inner: BackendDevice,
94 info: DeviceInfo,
95 mode: AccessMode
96}
97
98impl Device {
99 pub fn read_input_report<'a>(&'a self, buf: &'a mut [u8]) -> impl Future<Output = HidResult<usize>> + Send + 'a {
101 debug_assert!(self.mode.readable());
102 self.inner.read_input_report(buf)
103 }
104
105 pub fn write_output_report<'a>(&'a self, buf: &'a [u8]) -> impl Future<Output = HidResult<()>> + Send + 'a {
107 debug_assert!(self.mode.writeable());
108 self.inner.write_output_report(buf)
109 }
110
111 pub fn info(&self) -> &DeviceInfo {
113 &self.info
114 }
115}
116
117#[derive(Hash, Clone, Eq, PartialEq)]
119#[repr(transparent)]
120pub struct DeviceId(BackendDeviceId);
121
122impl From<BackendDeviceId> for DeviceId {
123 fn from(value: BackendDeviceId) -> Self {
124 Self(value)
125 }
126}
127
128impl Debug for DeviceId {
129 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
130 write!(f, "{:?}", self.0)
131 }
132}
133
134#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
141pub enum AccessMode {
142 Read,
143 Write,
144 #[default]
145 ReadWrite
146}
147
148impl AccessMode {
149 pub fn readable(self) -> bool {
150 matches!(self, Self::Read | Self::ReadWrite)
151 }
152 pub fn writeable(self) -> bool {
153 matches!(self, Self::Write | Self::ReadWrite)
154 }
155}
156
157assert_impl_all!(Device: Send, Sync);
158assert_impl_all!(DeviceInfo: Send, Sync);