1use std::fmt::Debug;
2use std::future::Future;
3use std::hash::Hash;
4
5use futures_lite::stream::Boxed;
6
7use crate::device_info::DeviceId;
8use crate::traits::{AsyncHidFeatureHandle, AsyncHidRead, AsyncHidWrite};
9use crate::{DeviceEvent, DeviceInfo, HidResult};
10
11pub type DeviceInfoStream = Boxed<HidResult<DeviceInfo>>;
12pub trait Backend: Sized + Default {
13 type Reader: AsyncHidRead + Send + Sync;
14 type Writer: AsyncHidWrite + Send + Sync;
15 type FeatureHandle: AsyncHidFeatureHandle + Send + Sync;
16
17 fn enumerate(&self) -> impl Future<Output = HidResult<DeviceInfoStream>> + Send;
18 fn watch(&self) -> HidResult<Boxed<DeviceEvent>>;
19
20 fn query_info(&self, id: &DeviceId) -> impl Future<Output = HidResult<Vec<DeviceInfo>>> + Send;
21
22 #[allow(clippy::type_complexity)]
23 fn open(&self, id: &DeviceId, read: bool, write: bool) -> impl Future<Output = HidResult<(Option<Self::Reader>, Option<Self::Writer>)>> + Send;
24 fn open_feature_handle(&self, id: &DeviceId) -> impl Future<Output = HidResult<Self::FeatureHandle>> + Send;
25
26 async fn read_feature_report(&self, id: &DeviceId, buf: &mut [u8]) -> HidResult<usize> {
27 let mut feature_buffer = self.open_feature_handle(id).await?;
28 feature_buffer.read_feature_report(buf).await
29 }
30}
31
32macro_rules! dyn_backend_impl {
33 {
34 $(
35 $(#[$module_attrs:meta])*
36 mod $module:ident {
37 $(#[$item_attrs:meta])*
38 $name:ident($backend:ty)
39 }
40 )+
41 } => {
42 $(
43 $(#[$module_attrs])*
44 mod $module;
45 )+
46
47 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
48 #[non_exhaustive]
49 pub enum BackendType {
50 $(
51 $(#[$module_attrs])*$(#[$item_attrs])*
52 $name,
53 )+
54 }
55
56 pub enum DynReader {
57 $(
58 $(#[$module_attrs])*$(#[$item_attrs])*
59 $name(<$backend as Backend>::Reader),
60 )+
61 }
62 impl AsyncHidRead for DynReader {
63 async fn read_input_report<'a>(&'a mut self, buf: &'a mut [u8]) -> HidResult<usize> {
64 match self {
65 $(
66 $(#[$module_attrs])*$(#[$item_attrs])*
67 Self::$name(i) => i.read_input_report(buf).await,
68 )+
69 }
70 }
71 }
72
73 pub enum DynWriter {
74 $(
75 $(#[$module_attrs])*$(#[$item_attrs])*
76 $name(<$backend as Backend>::Writer),
77 )+
78 }
79 impl AsyncHidWrite for DynWriter {
80 async fn write_output_report<'a>(&'a mut self, buf: &'a [u8]) -> HidResult<()> {
81 match self {
82 $(
83 $(#[$module_attrs])*$(#[$item_attrs])*
84 Self::$name(i) => i.write_output_report(buf).await,
85 )+
86 }
87 }
88 }
89
90 pub enum DynFeatureHandle {
91 $(
92 $(#[$module_attrs])*$(#[$item_attrs])*
93 $name(<$backend as Backend>::FeatureHandle),
94 )+
95 }
96 impl AsyncHidFeatureHandle for DynFeatureHandle {
97 async fn read_feature_report<'a>(&'a mut self, buf: &'a mut [u8]) -> HidResult<usize> {
98 match self {
99 $(
100 $(#[$module_attrs])*$(#[$item_attrs])*
101 Self::$name(i) => i.read_feature_report(buf).await,
102 )+
103 }
104 }
105
106 async fn write_feature_report<'a>(&'a mut self, buf: &'a [u8]) -> HidResult<()> {
107 match self {
108 $(
109 $(#[$module_attrs])*$(#[$item_attrs])*
110 Self::$name(i) => i.write_feature_report(buf).await,
111 )+
112 }
113 }
114 }
115
116 pub enum DynBackend {
117 $(
118 $(#[$module_attrs])*$(#[$item_attrs])*
119 $name($backend),
120 )+
121 }
122 impl DynBackend {
123 pub fn new(backend: BackendType) -> DynBackend {
124 match backend {
125 $(
126 $(#[$module_attrs])*$(#[$item_attrs])*
127 BackendType::$name => Self::$name(<$backend as Default>::default()),
128 )+
129 }
130 }
131 }
132 impl Backend for DynBackend {
133 type Reader = DynReader;
134 type Writer = DynWriter;
135 type FeatureHandle = DynFeatureHandle;
136
137 async fn enumerate(&self) -> HidResult<DeviceInfoStream> {
138 match self {
139 $(
140 $(#[$module_attrs])*$(#[$item_attrs])*
141 Self::$name(i) => i.enumerate().await,
142 )+
143 }
144 }
145
146 fn watch(&self) -> HidResult<Boxed<DeviceEvent>> {
147 match self {
148 $(
149 $(#[$module_attrs])*$(#[$item_attrs])*
150 Self::$name(i) => i.watch(),
151 )+
152 }
153 }
154
155 async fn query_info(&self, id: &DeviceId) -> HidResult<Vec<DeviceInfo>> {
156 match self {
157 $(
158 $(#[$module_attrs])*$(#[$item_attrs])*
159 Self::$name(i) => i.query_info(id).await,
160 )+
161 }
162 }
163
164 async fn open(&self, id: &DeviceId, read: bool, write: bool) -> HidResult<(Option<Self::Reader>, Option<Self::Writer>)> {
165 match self {
166 $(
167 $(#[$module_attrs])*$(#[$item_attrs])*
168 Self::$name(i) => i.open(id, read, write).await.map(|(r, w)| (r.map(DynReader::$name), w.map(DynWriter::$name))),
169 )+
170 }
171 }
172
173 async fn open_feature_handle(&self, id: &DeviceId) -> HidResult<Self::FeatureHandle> {
174 match self {
175 $(
176 $(#[$module_attrs])*$(#[$item_attrs])*
177 Self::$name(i) => i.open_feature_handle(id).await.map(DynFeatureHandle::$name),
178 )+
179 }
180 }
181 }
182 };
183}
184
185#[cfg(rustfmt)]
187mod hidraw;
188#[cfg(rustfmt)]
189mod iohidmanager;
190#[cfg(rustfmt)]
191mod win32;
192#[cfg(rustfmt)]
193mod winrt;
194
195dyn_backend_impl! {
198 #[cfg(all(target_os = "windows", feature = "win32"))]
199 mod win32 {
200 Win32(win32::Win32Backend)
201 }
202 #[cfg(all(target_os = "windows", feature = "winrt"))]
203 mod winrt {
204 WinRt(winrt::WinRtBackend)
205 }
206 #[cfg(target_os = "linux")]
207 mod hidraw {
208 HidRaw(hidraw::HidRawBackend)
209 }
210 #[cfg(target_os = "macos")]
211 mod iohidmanager {
212 IoHidManager(iohidmanager::IoHidManagerBackend)
213 }
214}
215
216impl Default for DynBackend {
217 #[allow(unreachable_code)]
218 fn default() -> Self {
219 #[cfg(target_os = "windows")]
220 {
221 #[cfg(feature = "win32")]
222 return Self::new(BackendType::Win32);
223 #[cfg(feature = "winrt")]
224 return Self::new(BackendType::WinRt);
225 }
226 #[cfg(target_os = "linux")]
227 {
228 return Self::new(BackendType::HidRaw);
229 }
230 #[cfg(target_os = "macos")]
231 {
232 return Self::new(BackendType::IoHidManager);
233 }
234 panic!("No suitable backend found");
235 }
236}