1#![warn(clippy::print_stderr, clippy::print_stdout, clippy::dbg_macro)]
52#![warn(clippy::todo)]
53#![warn(missing_docs)]
54
55pub use hid_types;
58
59pub use encode::EncodeItem;
61
62use hid_types::id::{CollectionType, InputFlags, IoFlags, Unit, UnitExponent, UsagePage};
63use hid_types::item::usage::{ExtendedUsage, Usage};
64use hid_types::item::{Global, Item, Local, Main};
65use tinyvec::TinyVec;
66
67use std::path::Path;
68
69mod encode;
70
71pub type DescriptorBytes = TinyVec<[u8; 4]>;
73
74pub fn encode_items(items: &[Item]) -> Vec<u8> {
76 items.iter().flat_map(|item| item.encode()).collect()
77}
78
79pub fn usage_page(usage_page: impl Into<UsagePage>) -> DescriptorBytes {
81 let usage_page: UsagePage = usage_page.into();
82 Global::UsagePage(usage_page).encode()
83}
84
85pub fn collection(value: impl Into<CollectionType>) -> DescriptorBytes {
87 Main::Collection(value.into()).encode()
88}
89
90pub fn end_collection() -> DescriptorBytes {
92 Main::EndCollection.encode()
93}
94
95pub fn logical_minimum(value: i32) -> DescriptorBytes {
97 Global::LogicalMinimum(value).encode()
98}
99
100pub fn logical_maximum(value: i32) -> DescriptorBytes {
102 Global::LogicalMaximum(value).encode()
103}
104
105pub fn physical_minimum(value: i32) -> DescriptorBytes {
107 Global::PhysicalMinimum(value).encode()
108}
109
110pub fn physical_maximum(value: i32) -> DescriptorBytes {
112 Global::PhysicalMaximum(value).encode()
113}
114
115pub fn unit(unit: impl Into<Unit>) -> DescriptorBytes {
117 let unit: Unit = unit.into();
118 Global::Unit(unit).encode()
119}
120
121pub fn unit_exponent(unit_exponent: impl Into<UnitExponent>) -> DescriptorBytes {
123 let unit: UnitExponent = unit_exponent.into();
124 Global::UnitExponent(unit).encode()
125}
126
127pub fn report_id(value: u8) -> DescriptorBytes {
138 Global::ReportId(value).encode()
139}
140
141pub fn report_size(value: u32) -> DescriptorBytes {
143 Global::ReportSize(value).encode()
144}
145
146pub fn report_count(value: u32) -> DescriptorBytes {
148 Global::ReportCount(value).encode()
149}
150
151pub fn push() -> DescriptorBytes {
153 Global::Push.encode()
154}
155
156pub fn pop() -> DescriptorBytes {
158 Global::Pop.encode()
159}
160
161pub fn input(flags: impl Into<IoFlags>) -> DescriptorBytes {
163 let flags = flags.into();
164 Main::Input(InputFlags::from_unchecked(flags)).encode()
165}
166
167pub fn output(flags: impl Into<IoFlags>) -> DescriptorBytes {
169 let flags = flags.into();
170 Main::Output(flags.into()).encode()
171}
172
173pub fn feature(flags: impl Into<IoFlags>) -> DescriptorBytes {
175 let flags = flags.into();
176 Main::Feature(flags.into()).encode()
177}
178
179pub fn usage(value: impl Into<u16>) -> DescriptorBytes {
183 let usage = Usage::without_page(value.into());
184 Local::Usage(usage).encode()
185}
186
187pub fn extended_usage(usage_page: impl Into<UsagePage>, usage: impl Into<u16>) -> DescriptorBytes {
189 let extended_usage: ExtendedUsage = ExtendedUsage::new(usage_page.into(), usage.into());
190 Local::ExtendedUsage(extended_usage).encode()
191}
192
193pub fn usage_minimum(value: impl Into<u16>) -> DescriptorBytes {
197 let value = value.into();
198 Local::UsageMinimum(value.into()).encode()
199}
200
201pub fn usage_maximum(value: impl Into<u16>) -> DescriptorBytes {
205 let value = value.into();
206 Local::UsageMaximum(value.into()).encode()
207}
208
209pub fn designator_index(value: u32) -> DescriptorBytes {
211 Local::DesignatorIndex(value).encode()
212}
213
214pub fn designator_minimum(value: u32) -> DescriptorBytes {
216 Local::DesignatorMinimum(value).encode()
217}
218
219pub fn designator_maximum(value: u32) -> DescriptorBytes {
221 Local::DesignatorMaximum(value).encode()
222}
223
224pub fn string_index(value: u32) -> DescriptorBytes {
226 Local::StringIndex(value).encode()
227}
228
229pub fn string_minimum(value: u32) -> DescriptorBytes {
231 Local::StringMinimum(value).encode()
232}
233
234pub fn string_maximum(value: u32) -> DescriptorBytes {
236 Local::StringMaximum(value).encode()
237}
238
239pub fn string_(value: bool) -> DescriptorBytes {
241 Local::Delimiter(value).encode()
242}
243
244pub fn concatenate_bytes(
248 items: impl IntoIterator<Item = impl IntoIterator<Item = u8>>,
249) -> impl Iterator<Item = u8> {
250 items.into_iter().flatten()
251}
252
253pub fn write_to_file(
258 items: impl IntoIterator<Item = impl IntoIterator<Item = u8>>,
259 path: impl AsRef<Path>,
260) -> std::io::Result<()> {
261 let descriptor: Vec<u8> = items.into_iter().flatten().collect();
262 std::fs::write(path, descriptor)
263}
264
265#[cfg(test)]
266mod tests {
267 use hid_types::id::{KnownCollectionType, KnownUsagePage};
268
269 use super::*;
270
271 #[test]
272 fn test_usage_page() {
273 let bytes = usage_page(KnownUsagePage::GenericDesktop);
274 assert_eq!(bytes.as_slice(), &[0x05, 0x01]);
275
276 let bytes = usage_page(UsagePage::Reserved(0xFF00));
277 assert_eq!(bytes.as_slice(), &[0x06, 0x00, 0xFF]);
278
279 let bytes = usage_page(UsagePage::Reserved(0x00FF));
281 assert_eq!(bytes.as_slice(), &[0x05, 0xFF]);
282 }
283
284 #[test]
285 fn concatenate() {
286 use hid_types::id::usage::generic_desktop::KnownUsage as Usage;
287
288 let bytes = [
289 usage_page(KnownUsagePage::GenericDesktop),
290 usage(Usage::Joystick),
291 collection(KnownCollectionType::Application),
292 usage(Usage::Pointer),
293 collection(KnownCollectionType::Physical),
294 usage(Usage::X),
295 usage(Usage::Y),
296 logical_minimum(-1),
297 logical_maximum(255),
298 report_size(8),
299 report_count(2),
300 input(IoFlags::data().variable()),
301 end_collection(),
302 usage_page(KnownUsagePage::Button),
303 usage_minimum(1u16),
304 usage_maximum(8u16),
305 logical_minimum(0),
306 logical_maximum(1),
307 report_size(1),
308 report_count(8),
309 input(IoFlags::data().variable()),
310 end_collection(),
311 ];
312 let desc: Vec<u8> = concatenate_bytes(bytes).collect();
313 assert_eq!(
314 desc,
315 &[
316 0x05, 0x01, 0x09, 0x04, 0xA1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30, 0x09, 0x31, 0x15, 0xFF, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x02, 0x81, 0x02, 0xc0, 0x05, 0x09, 0x19, 0x01, 0x29, 0x08, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0xc0, ]
339 );
340 }
341}