usb_ids/lib.rs
1//!
2//! Rust wrappers for the [USB ID Repository](http://www.linux-usb.org/usb-ids.html).
3//!
4//! The USB ID Repository is the canonical source of USB device information for most
5//! Linux userspaces; this crate vendors the USB ID database to allow non-Linux hosts to
6//! access the same canonical information.
7//!
8//! # Usage
9//!
10//! Iterating over all known vendors:
11//!
12//! ```rust
13//! use usb_ids::Vendors;
14//!
15//! for vendor in Vendors::iter() {
16//! for device in vendor.devices() {
17//! println!("vendor: {}, device: {}", vendor.name(), device.name());
18//! }
19//! }
20//! ```
21//!
22//! Iterating over all known classes:
23//!
24//! ```rust
25//! use usb_ids::Classes;
26//!
27//! for class in Classes::iter() {
28//! println!("class: {}", class.name());
29//! for subclass in class.sub_classes() {
30//! println!("\tsubclass: {}", subclass.name());
31//! for protocol in subclass.protocols() {
32//! println!("\t\tprotocol: {}", protocol.name());
33//! }
34//! }
35//! }
36//! ```
37//!
38//! See the individual documentation for each structure for more details.
39//!
40
41#![warn(missing_docs)]
42
43include!(concat!(env!("OUT_DIR"), "/usb_ids.cg.rs"));
44
45/// Represents a generic USB ID in the USB database.
46///
47/// Not designed to be used directly; use one of the type aliases instead.
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub struct UsbId<const ID: u8, T> {
50 id: T,
51 name: &'static str,
52}
53
54impl<const ID: u8, T: Copy> UsbId<ID, T> {
55 /// Returns the type's ID.
56 pub fn id(&self) -> T {
57 self.id
58 }
59
60 /// Returns the type's name.
61 pub fn name(&self) -> &'static str {
62 self.name
63 }
64}
65
66/// Represents a generic USB ID in the USB database with children IDs.
67///
68/// Not designed to be used directly; use one of the type aliases instead.
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub struct UsbIdWithChildren<T: Copy, C: 'static> {
71 id: T,
72 name: &'static str,
73 children: &'static [C],
74}
75
76impl<T: Copy, C: 'static> UsbIdWithChildren<T, C> {
77 /// Returns the type's ID.
78 pub fn id(&self) -> T {
79 self.id
80 }
81
82 /// Returns the type's name.
83 pub fn name(&self) -> &'static str {
84 self.name
85 }
86
87 /// Returns an iterator over the type's children.
88 fn children(&self) -> impl Iterator<Item = &'static C> {
89 self.children.iter()
90 }
91}
92
93/// An abstraction for iterating over all vendors in the USB database.
94pub struct Vendors;
95impl Vendors {
96 /// Returns an iterator over all vendors in the USB database.
97 pub fn iter() -> impl Iterator<Item = &'static Vendor> {
98 USB_IDS.values()
99 }
100}
101
102/// An abstraction for iterating over all classes in the USB database.
103pub struct Classes;
104impl Classes {
105 /// Returns an iterator over all classes in the USB database.
106 pub fn iter() -> impl Iterator<Item = &'static Class> {
107 USB_CLASSES.values()
108 }
109}
110
111/// An abstraction for iterating over all languages in the USB database.
112///
113/// ```
114/// use usb_ids::Languages;
115/// for language in Languages::iter() {
116/// println!("language: {}", language.name());
117/// for dialect in language.dialects() {
118/// println!("\tdialect: {}", dialect.name());
119/// }
120/// }
121/// ```
122pub struct Languages;
123impl Languages {
124 /// Returns an iterator over all languages in the USB database.
125 pub fn iter() -> impl Iterator<Item = &'static Language> {
126 USB_LANGS.values()
127 }
128}
129
130/// An abstraction for iterating over all HID usage pages in the USB database.
131///
132/// ```
133/// use usb_ids::HidUsagePages;
134///
135/// for page in HidUsagePages::iter() {
136/// println!("page: {}", page.name());
137/// for usage in page.usages() {
138/// println!("\tusage: {}", usage.name());
139/// }
140/// }
141/// ```
142pub struct HidUsagePages;
143impl HidUsagePages {
144 /// Returns an iterator over all HID usage pages in the USB database.
145 pub fn iter() -> impl Iterator<Item = &'static HidUsagePage> {
146 USB_HUTS.values()
147 }
148}
149
150/// Represents a USB device vendor in the USB database.
151///
152/// Every device vendor has a vendor ID, a pretty name, and a
153/// list of associated [`Device`]s.
154#[derive(Clone, Copy, Debug, PartialEq, Eq)]
155pub struct Vendor {
156 id: u16,
157 name: &'static str,
158 devices: &'static [Device],
159}
160
161impl Vendor {
162 /// Returns the vendor's ID.
163 pub fn id(&self) -> u16 {
164 self.id
165 }
166
167 /// Returns the vendor's name.
168 pub fn name(&self) -> &'static str {
169 self.name
170 }
171
172 /// Returns an iterator over the vendor's [`Device`]s.
173 pub fn devices(&self) -> impl Iterator<Item = &'static Device> {
174 self.devices.iter()
175 }
176}
177
178/// Represents a single device in the USB database.
179///
180/// Every device has a corresponding vendor, a device ID, a pretty name,
181/// and a list of associated [`Interface`]s.
182#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183pub struct Device {
184 vendor_id: u16,
185 id: u16,
186 name: &'static str,
187 interfaces: &'static [Interface],
188}
189
190impl Device {
191 /// Returns the [`Device`] corresponding to the given vendor and product IDs,
192 /// or `None` if no such device exists in the DB.
193 ///
194 /// ```
195 /// use usb_ids::Device;
196 /// let device = Device::from_vid_pid(0x1d6b, 0x0003).unwrap();
197 /// assert_eq!(device.name(), "3.0 root hub");
198 /// ```
199 pub fn from_vid_pid(vid: u16, pid: u16) -> Option<&'static Device> {
200 let vendor = Vendor::from_id(vid);
201
202 vendor.and_then(|v| v.devices().find(|d| d.id == pid))
203 }
204
205 /// Returns the [`Vendor`] that this device belongs to.
206 ///
207 /// Looking up a vendor by device is cheap (`O(1)`).
208 pub fn vendor(&self) -> &'static Vendor {
209 USB_IDS.get(&self.vendor_id).unwrap()
210 }
211
212 /// Returns a tuple of (vendor id, device/"product" id) for this device.
213 ///
214 /// This is convenient for interactions with other USB libraries.
215 pub fn as_vid_pid(&self) -> (u16, u16) {
216 (self.vendor_id, self.id)
217 }
218
219 /// Returns the device's ID.
220 pub fn id(&self) -> u16 {
221 self.id
222 }
223
224 /// Returns the device's name.
225 pub fn name(&self) -> &'static str {
226 self.name
227 }
228
229 /// Returns an iterator over the device's [`Interface`]s.
230 ///
231 /// **NOTE**: The USB database does not include interface information for
232 /// most devices. This list is not authoritative.
233 pub fn interfaces(&self) -> impl Iterator<Item = &'static Interface> {
234 self.interfaces.iter()
235 }
236}
237
238/// Represents an interface to a USB device in the USB database.
239///
240/// Every interface has an interface ID (which is an index on the device)
241/// and a pretty name.
242///
243/// **NOTE**: The USB database is not a canonical or authoritative source
244/// of interface information for devices. Users who wish to discover interfaces
245/// on their USB devices should query those devices directly.
246#[derive(Clone, Copy, Debug, PartialEq, Eq)]
247pub struct Interface {
248 id: u8,
249 name: &'static str,
250}
251
252impl Interface {
253 /// Returns the interface's ID.
254 pub fn id(&self) -> u8 {
255 self.id
256 }
257
258 /// Returns the interface's name.
259 pub fn name(&self) -> &'static str {
260 self.name
261 }
262}
263
264/// Represents a USB device class in the USB database.
265///
266/// Every device class has a class ID, a pretty name, and a
267/// list of associated [`SubClass`]s.
268///
269/// ```
270/// use usb_ids::{Class, Classes, FromId};
271/// let class = Class::from_id(0x03).unwrap();
272/// assert_eq!(class.name(), "Human Interface Device");
273/// ```
274#[derive(Clone, Copy, Debug, PartialEq, Eq)]
275pub struct Class {
276 id: u8,
277 name: &'static str,
278 sub_classes: &'static [SubClass],
279}
280
281impl Class {
282 /// Returns the class's ID.
283 pub fn id(&self) -> u8 {
284 self.id
285 }
286
287 /// Returns the class's name.
288 pub fn name(&self) -> &'static str {
289 self.name
290 }
291
292 /// Returns an iterator over the class's [`SubClass`]s.
293 pub fn sub_classes(&self) -> impl Iterator<Item = &'static SubClass> {
294 self.sub_classes.iter()
295 }
296}
297
298/// Represents a class subclass in the USB database. Subclasses are part of the
299/// USB class code triplet (base class, subclass, protocol).
300///
301/// Contained within a [`Class`] and may contain a list of associated
302/// [`Protocol`]s.
303#[derive(Clone, Copy, Debug, PartialEq, Eq)]
304pub struct SubClass {
305 class_id: u8,
306 id: u8,
307 name: &'static str,
308 protocols: &'static [Protocol],
309}
310
311impl SubClass {
312 /// Returns the [`SubClass`] corresponding to the given class and subclass IDs,
313 /// or `None` if no such subclass exists in the DB.
314 ///
315 /// ```
316 /// use usb_ids::SubClass;
317 /// let subclass = SubClass::from_cid_scid(0x02, 0x03).unwrap();
318 /// assert_eq!(subclass.name(), "Telephone");
319 ///
320 /// assert!(SubClass::from_cid_scid(0x3c, 0x02).is_none());
321 /// ```
322 pub fn from_cid_scid(class_id: u8, id: u8) -> Option<&'static Self> {
323 let class = Class::from_id(class_id);
324
325 class.and_then(|c| c.sub_classes().find(|s| s.id == id))
326 }
327
328 /// Returns the [`Class`] that this subclass belongs to.
329 ///
330 /// Looking up a class by subclass is cheap (`O(1)`).
331 ///
332 /// ```
333 /// use usb_ids::SubClass;
334 /// let subclass = SubClass::from_cid_scid(0x02, 0x03).unwrap();
335 /// let class = subclass.class();
336 /// assert_eq!(class.id(), 0x02);
337 /// ```
338 pub fn class(&self) -> &'static Class {
339 USB_CLASSES.get(&self.class_id).unwrap()
340 }
341
342 /// Returns a tuple of (class id, subclass id) for this subclass.
343 ///
344 /// This is convenient for interactions with other USB libraries.
345 pub fn as_cid_scid(&self) -> (u8, u8) {
346 (self.class_id, self.id)
347 }
348
349 /// Returns the subclass' ID.
350 pub fn id(&self) -> u8 {
351 self.id
352 }
353
354 /// Returns the subclass' name.
355 pub fn name(&self) -> &'static str {
356 self.name
357 }
358
359 /// Returns an iterator over the subclasses's [`Protocol`]s.
360 ///
361 /// **NOTE**: The USB database nor USB-IF includes protocol information for
362 /// all subclassess. This list is not authoritative.
363 pub fn protocols(&self) -> impl Iterator<Item = &'static Protocol> {
364 self.protocols.iter()
365 }
366}
367
368/// These are tags for UsbId type aliases to make them unique and allow a
369/// [`FromId`] for each alias. The values are arbitrary but must be unique.
370///
371/// [`std::marker::PhantomData`] would be nicer but was unable to figure out a
372/// generic way to add the _tag: PhantomData in the ToToken trait
373/// implementation within build.rs
374const PROTOCOL_TAG: u8 = 0;
375const AT_TAG: u8 = 1;
376const HID_TAG: u8 = 2;
377const HID_TYPE_TAG: u8 = 3;
378const HID_USAGE_TAG: u8 = 4;
379const BIAS_TAG: u8 = 5;
380const PHY_TAG: u8 = 6;
381const DIALECT_TAG: u8 = 7;
382const HCC_TAG: u8 = 8;
383const VT_TAG: u8 = 9;
384
385/// Represents a subclass protocol in the USB database.
386///
387/// Protocols are part of the USB class code triplet (base class, subclass,
388/// protocol), contained within a [`SubClass`].
389pub type Protocol = UsbId<PROTOCOL_TAG, u8>;
390
391impl Protocol {
392 /// Returns the [`Protocol`] corresponding to the given class, subclass, and protocol IDs,
393 /// or `None` if no such protocol exists in the DB.
394 ///
395 /// ```
396 /// use usb_ids::Protocol;
397 /// let protocol = Protocol::from_cid_scid_pid(0x02, 0x02, 0x05).unwrap();
398 /// assert_eq!(protocol.name(), "AT-commands (3G)");
399 /// ```
400 pub fn from_cid_scid_pid(class_id: u8, subclass_id: u8, id: u8) -> Option<&'static Self> {
401 let subclass = SubClass::from_cid_scid(class_id, subclass_id);
402
403 subclass.and_then(|s| s.protocols().find(|p| p.id == id))
404 }
405}
406
407/// Represents an audio terminal type in the USB database.
408///
409/// ```
410/// use usb_ids::{AudioTerminal, FromId};
411/// let audio_terminal = AudioTerminal::from_id(0x0201).unwrap();
412/// assert_eq!(audio_terminal.name(), "Microphone");
413/// ```
414pub type AudioTerminal = UsbId<AT_TAG, u16>;
415
416/// Represents a HID descriptor type in the USB database.
417///
418/// ```
419/// use usb_ids::{Hid, FromId};
420/// let hid = Hid::from_id(0x22).unwrap();
421/// assert_eq!(hid.name(), "Report");
422/// ```
423pub type Hid = UsbId<HID_TAG, u8>;
424
425/// Represents a HID descriptor item type in the USB database.
426///
427/// ```
428/// use usb_ids::{HidItemType, FromId};
429/// let hid_item_type = HidItemType::from_id(0xb4).unwrap();
430/// assert_eq!(hid_item_type.name(), "Pop");
431/// ```
432pub type HidItemType = UsbId<HID_TYPE_TAG, u8>;
433
434/// Represents a HID usage page in the USB database.
435///
436/// Every HID usage page has a usage page ID, a pretty name, and a list of
437/// associated [`HidUsage`]s.
438///
439/// ```
440/// use usb_ids::{HidUsagePage, FromId};
441/// let hid_usage_page = HidUsagePage::from_id(0x01).unwrap();
442/// assert_eq!(hid_usage_page.name(), "Generic Desktop Controls");
443///
444/// for usage in hid_usage_page.usages() {
445/// println!("usage: {}", usage.name());
446/// }
447/// ```
448pub type HidUsagePage = UsbIdWithChildren<u8, HidUsage>;
449
450impl HidUsagePage {
451 /// Returns an iterator over the page's [`HidUsage`]s.
452 pub fn usages(&self) -> impl Iterator<Item = &'static HidUsage> {
453 self.children()
454 }
455}
456
457/// Represents a HID usage type in the USB database.
458///
459/// ```
460/// use usb_ids::{HidUsage, HidUsagePage, FromId};
461///
462/// let hid_usage_page = HidUsagePage::from_id(0x01).unwrap();
463/// for usage in hid_usage_page.usages() {
464/// println!("usage: {}", usage.name());
465/// }
466/// ```
467pub type HidUsage = UsbId<HID_USAGE_TAG, u16>;
468
469impl HidUsage {
470 /// Returns the [`HidUsage`] corresponding to the given usage page and usage ID,
471 /// or `None` if no such usage exists in the DB.
472 ///
473 /// ```
474 /// use usb_ids::HidUsage;
475 /// let hid_usage = HidUsage::from_pageid_uid(0x01, 0x002).unwrap();
476 /// assert_eq!(hid_usage.name(), "Mouse");
477 /// ```
478 pub fn from_pageid_uid(page_id: u8, id: u16) -> Option<&'static Self> {
479 let page = HidUsagePage::from_id(page_id)?;
480
481 page.children().find(|u| u.id() == id)
482 }
483}
484
485/// Represents physical descriptor bias type in the USB database.
486///
487/// ```
488/// use usb_ids::{Bias, FromId};
489/// let bias = Bias::from_id(0x02).unwrap();
490/// assert_eq!(bias.name(), "Left Hand");
491/// ```
492pub type Bias = UsbId<BIAS_TAG, u8>;
493
494/// Represents physical descriptor item type in the USB database.
495///
496/// ```
497/// use usb_ids::{Phy, FromId};
498/// let phy = Phy::from_id(0x25).unwrap();
499/// assert_eq!(phy.name(), "Fifth Toe");
500/// ```
501pub type Phy = UsbId<PHY_TAG, u8>;
502
503/// Represents a language type in the USB database.
504///
505/// Languages have a language ID, a pretty name, and a list of associated
506/// [`Dialect`]s.
507///
508/// ```
509/// use usb_ids::{Language, FromId};
510/// let language = Language::from_id(0x000c).unwrap();
511/// assert_eq!(language.name(), "French");
512///
513/// for dialect in language.dialects() {
514/// println!("dialect: {}", dialect.name());
515/// }
516/// ```
517pub type Language = UsbIdWithChildren<u16, Dialect>;
518
519impl Language {
520 /// Returns an iterator over the language's [`Dialect`]s.
521 pub fn dialects(&self) -> impl Iterator<Item = &'static Dialect> {
522 self.children()
523 }
524}
525
526/// Represents a language dialect in the USB database.
527///
528/// ```
529/// use usb_ids::{Dialect, Language, FromId};
530/// let lang = Language::from_id(0x0007).unwrap();
531///
532/// println!("language: {}", lang.name());
533/// for dialect in lang.dialects() {
534/// println!("\tdialect: {}", dialect.name());
535/// }
536/// ```
537pub type Dialect = UsbId<DIALECT_TAG, u8>;
538
539impl Dialect {
540 /// Returns the [`Dialect`] corresponding to the given language and dialect IDs,
541 /// or `None` if no such dialect exists in the DB.
542 ///
543 /// ```
544 /// use usb_ids::Dialect;
545 /// let dialect = Dialect::from_lid_did(0x0007, 0x02).unwrap();
546 /// assert_eq!(dialect.name(), "Swiss");
547 /// ```
548 pub fn from_lid_did(language_id: u16, id: u8) -> Option<&'static Self> {
549 let language = Language::from_id(language_id)?;
550
551 language.children().find(|d| d.id() == id)
552 }
553}
554
555/// Represents a HID descriptor country code in the USB database.
556///
557/// ```
558/// use usb_ids::{HidCountryCode, FromId};
559/// let hid_country_code = HidCountryCode::from_id(0x29).unwrap();
560/// assert_eq!(hid_country_code.name(), "Switzerland");
561/// ```
562pub type HidCountryCode = UsbId<HCC_TAG, u8>;
563
564/// Represents a video class terminal type in the USB database.
565///
566/// ```
567/// use usb_ids::{VideoTerminal, FromId};
568/// let video_terminal = VideoTerminal::from_id(0x0101).unwrap();
569/// assert_eq!(video_terminal.name(), "USB Streaming");
570/// ```
571pub type VideoTerminal = UsbId<VT_TAG, u16>;
572
573/// A convenience trait for retrieving a top-level entity (like a [`Vendor`]) from the USB
574/// database by its unique ID.
575///
576/// ```
577/// use usb_ids::{FromId, Vendor};
578/// let vendor = Vendor::from_id(0x1d6b).unwrap();
579/// assert_eq!(vendor.name(), "Linux Foundation");
580/// ```
581pub trait FromId<T> {
582 /// Returns the entity corresponding to `id`, or `None` if none exists.
583 fn from_id(id: T) -> Option<&'static Self>;
584}
585
586impl FromId<u16> for Vendor {
587 fn from_id(id: u16) -> Option<&'static Self> {
588 USB_IDS.get(&id)
589 }
590}
591
592impl FromId<u8> for Class {
593 fn from_id(id: u8) -> Option<&'static Self> {
594 USB_CLASSES.get(&id)
595 }
596}
597
598impl FromId<u16> for AudioTerminal {
599 fn from_id(id: u16) -> Option<&'static Self> {
600 USB_AUDIO_TERMINALS.get(&id)
601 }
602}
603
604impl FromId<u8> for Hid {
605 fn from_id(id: u8) -> Option<&'static Self> {
606 USB_HID_IDS.get(&id)
607 }
608}
609
610impl FromId<u8> for HidItemType {
611 fn from_id(id: u8) -> Option<&'static Self> {
612 USB_HID_R_TYPES.get(&id)
613 }
614}
615
616impl FromId<u8> for HidUsagePage {
617 fn from_id(id: u8) -> Option<&'static Self> {
618 USB_HUTS.get(&id)
619 }
620}
621
622impl FromId<u8> for Bias {
623 fn from_id(id: u8) -> Option<&'static Self> {
624 USB_BIASES.get(&id)
625 }
626}
627
628impl FromId<u8> for Phy {
629 fn from_id(id: u8) -> Option<&'static Self> {
630 USB_PHYS.get(&id)
631 }
632}
633
634impl FromId<u16> for Language {
635 fn from_id(id: u16) -> Option<&'static Self> {
636 USB_LANGS.get(&id)
637 }
638}
639
640impl FromId<u8> for HidCountryCode {
641 fn from_id(id: u8) -> Option<&'static Self> {
642 USB_HID_CCS.get(&id)
643 }
644}
645
646impl FromId<u16> for VideoTerminal {
647 fn from_id(id: u16) -> Option<&'static Self> {
648 USB_VIDEO_TERMINALS.get(&id)
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use super::*;
655
656 #[test]
657 fn test_from_id() {
658 let vendor = Vendor::from_id(0x1d6b).unwrap();
659
660 assert_eq!(vendor.name(), "Linux Foundation");
661 assert_eq!(vendor.id(), 0x1d6b);
662 }
663
664 #[test]
665 fn test_vendor_devices() {
666 let vendor = Vendor::from_id(0x1d6b).unwrap();
667
668 for device in vendor.devices() {
669 assert_eq!(device.vendor(), vendor);
670 assert!(!device.name().is_empty());
671 }
672 }
673
674 #[test]
675 fn test_from_vid_pid() {
676 let device = Device::from_vid_pid(0x1d6b, 0x0003).unwrap();
677
678 assert_eq!(device.name(), "3.0 root hub");
679
680 let (vid, pid) = device.as_vid_pid();
681
682 assert_eq!(vid, device.vendor().id());
683 assert_eq!(pid, device.id());
684
685 let device2 = Device::from_vid_pid(vid, pid).unwrap();
686
687 assert_eq!(device, device2);
688
689 let last_device = Device::from_vid_pid(0xffee, 0x0100).unwrap();
690 assert_eq!(
691 last_device.name(),
692 "Card Reader Controller RTS5101/RTS5111/RTS5116"
693 );
694 }
695
696 #[test]
697 fn test_class_from_id() {
698 let class = Class::from_id(0x03).unwrap();
699
700 assert_eq!(class.name(), "Human Interface Device");
701 assert_eq!(class.id(), 0x03);
702 }
703
704 #[test]
705 fn test_subclass_from_cid_scid() {
706 let subclass = SubClass::from_cid_scid(0x03, 0x01).unwrap();
707
708 assert_eq!(subclass.name(), "Boot Interface Subclass");
709 assert_eq!(subclass.id(), 0x01);
710 }
711
712 #[test]
713 fn test_protocol_from_cid_scid_pid() {
714 let protocol = Protocol::from_cid_scid_pid(0x03, 0x01, 0x01).unwrap();
715
716 assert_eq!(protocol.name(), "Keyboard");
717 assert_eq!(protocol.id(), 0x01);
718
719 let protocol = Protocol::from_cid_scid_pid(0x07, 0x01, 0x03).unwrap();
720
721 assert_eq!(protocol.name(), "IEEE 1284.4 compatible bidirectional");
722 assert_eq!(protocol.id(), 0x03);
723
724 let protocol = Protocol::from_cid_scid_pid(0xff, 0xff, 0xff).unwrap();
725
726 // check last entry for parsing
727 assert_eq!(protocol.name(), "Vendor Specific Protocol");
728 assert_eq!(protocol.id(), 0xff);
729 }
730
731 #[test]
732 fn test_at_from_id() {
733 let at = AudioTerminal::from_id(0x0713).unwrap();
734
735 assert_eq!(at.name(), "Synthesizer");
736 assert_eq!(at.id(), 0x0713);
737 }
738
739 #[test]
740 fn test_hid_from_id() {
741 let hid = Hid::from_id(0x23).unwrap();
742
743 assert_eq!(hid.name(), "Physical");
744 assert_eq!(hid.id(), 0x23);
745 }
746
747 #[test]
748 fn test_hid_type_from_id() {
749 let hid_type = HidItemType::from_id(0xc0).unwrap();
750
751 assert_eq!(hid_type.name(), "End Collection");
752 assert_eq!(hid_type.id(), 0xc0);
753 }
754
755 #[test]
756 fn test_bias_from_id() {
757 let bias = Bias::from_id(0x04).unwrap();
758
759 assert_eq!(bias.name(), "Either Hand");
760 assert_eq!(bias.id(), 0x04);
761 }
762
763 #[test]
764 fn test_phy_from_id() {
765 let phy = Phy::from_id(0x27).unwrap();
766
767 assert_eq!(phy.name(), "Cheek");
768 assert_eq!(phy.id(), 0x27);
769 }
770
771 #[test]
772 fn test_hid_usages_from_id() {
773 let hid_usage_page = HidUsagePage::from_id(0x0d).unwrap();
774
775 assert_eq!(hid_usage_page.name(), "Digitizer");
776 assert_eq!(hid_usage_page.id(), 0x0d);
777
778 let hid_usage = HidUsage::from_pageid_uid(0x0d, 0x01).unwrap();
779
780 assert_eq!(hid_usage.name(), "Digitizer");
781 assert_eq!(hid_usage.id(), 0x01);
782 }
783
784 #[test]
785 fn test_language_from_id() {
786 let language = Language::from_id(0x0007).unwrap();
787
788 assert_eq!(language.name(), "German");
789 assert_eq!(language.id(), 0x0007);
790
791 let dialect = language.dialects().find(|d| d.id() == 0x02).unwrap();
792
793 assert_eq!(dialect.name(), "Swiss");
794 assert_eq!(dialect.id(), 0x02);
795 }
796
797 #[test]
798 fn test_hid_country_code_from_id() {
799 let hid_country_code = HidCountryCode::from_id(0x29).unwrap();
800
801 assert_eq!(hid_country_code.name(), "Switzerland");
802 assert_eq!(hid_country_code.id(), 0x29);
803
804 let hid_country_code = HidCountryCode::from_id(0x00).unwrap();
805 assert_eq!(hid_country_code.name(), "Not supported");
806 }
807
808 #[test]
809 fn test_video_terminal_from_id() {
810 let video_terminal = VideoTerminal::from_id(0x0100).unwrap();
811
812 assert_eq!(video_terminal.name(), "USB Vendor Specific");
813 assert_eq!(video_terminal.id(), 0x0100);
814
815 let video_terminal = VideoTerminal::from_id(0x0403).unwrap();
816 assert_eq!(video_terminal.name(), "Component Video");
817 }
818}