hid_types/id/ident.rs
1//! A utility for handling well-known IDs and reserved values.
2
3/// A container that holds either a known variant, or an integer value with unknown meaning.
4///
5/// # Example
6///
7/// ```rust
8/// #[repr(u8)]
9/// enum KnownColor {
10/// Red = 0,
11/// Green = 1,
12/// Blue = 2,
13/// }
14///
15/// // This can be autogenerated using something like `num_enum::TryFromPrimitive`.
16/// impl TryFrom<u8> for KnownColor {
17/// type Error = Unrecognized;
18///
19/// fn try_from(value: u8) -> Result<Self, Self::Error> {
20/// match value {
21/// 0 => Ok(KnownColor::Red),
22/// 1 => Ok(KnownColor::Green),
23/// 2 => Ok(KnownColor::Blue),
24/// _ => Err(Unrecognized),
25/// }
26/// }
27/// }
28/// struct Unrecognized;
29///
30/// # use hid_types::Ident;
31/// type Color = Ident<KnownColor, u8>;
32///
33/// let green = Color::from_integer(1);
34/// assert!(matches!(green, Color::Known(KnownColor::Green)));
35///
36/// let orange = Color::from_integer(5);
37/// assert!(matches!(orange, Color::Reserved(5)));
38/// ```
39///
40#[derive(Clone, Copy, PartialEq)]
41pub enum Ident<T, Repr> {
42 /// A well-known value.
43 Known(T),
44 /// A reserved value.
45 ///
46 /// This can be used to identify vendor-specific types.
47 Reserved(Repr),
48}
49
50/// Conversion from the "known" type to the `Ident::Known` variant.
51impl<T, Repr> From<T> for Ident<T, Repr> {
52 fn from(value: T) -> Self {
53 Self::Known(value)
54 }
55}
56
57#[cfg(feature = "std")]
58mod std_impls {
59 use super::*;
60
61 use std::fmt::{self, Debug, UpperHex};
62
63 impl<T, Repr> Debug for Ident<T, Repr>
64 where
65 T: Clone + Copy + PartialEq + Debug,
66 Repr: Clone + Copy + PartialEq + Debug + UpperHex,
67 {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 Self::Known(id) => id.fmt(f),
71 Self::Reserved(id) => f
72 .debug_tuple("Reserved")
73 .field(
74 // FIXME: it would be nice to compute the number of leading zeroes
75 // for the Repr type.
76 &format_args!("{:#04X}", id),
77 )
78 .finish(),
79 }
80 }
81 }
82}
83
84impl<T, Repr> Ident<T, Repr> {
85 /// Test if the value is reserved.
86 pub fn is_reserved(&self) -> bool {
87 matches!(self, Self::Reserved(_))
88 }
89}
90
91impl<T, Repr> Ident<T, Repr>
92where
93 T: TryFrom<Repr>,
94 Repr: Clone + Copy,
95{
96 /// Try to decode a known identifier; if that fails store the raw number as a "reserved" value.
97 pub fn from_integer(value: Repr) -> Self {
98 match T::try_from(value) {
99 Ok(id) => Self::Known(id),
100 Err(_) => Self::Reserved(value),
101 }
102 }
103}
104
105impl<T, Repr> Ident<T, Repr>
106where
107 T: Into<Repr>,
108{
109 /// Convert the identifier to an integer.
110 pub fn to_integer(self) -> Repr {
111 match self {
112 Ident::Known(id) => id.into(),
113 Ident::Reserved(id) => id,
114 }
115 }
116}