Skip to main content

hid_types/
hid.rs

1//! HID descriptor items.
2
3use bitfield_struct::bitfield;
4use num_enum::{IntoPrimitive, TryFromPrimitive};
5
6use crate::Ident;
7
8/// A one-byte tag+type+size value
9#[bitfield(u32, debug = false)]
10pub struct IoFlags {
11    #[bits(1)]
12    data_or_constant: bool,
13    #[bits(1)]
14    array_or_variable: bool,
15    #[bits(1)]
16    absolute_or_relative: bool,
17    #[bits(1)]
18    wrap: bool,
19    #[bits(1)]
20    non_linear: bool,
21    #[bits(1)]
22    no_preferred: bool,
23    #[bits(1)]
24    null_state: bool,
25    // Note: `volatile` is only valid for Output and Feature (not Input)
26    #[bits(1)]
27    volatile: bool,
28    #[bits(1)]
29    bitfield_or_buffered: bool,
30    #[bits(23)]
31    reserved: u32,
32}
33
34impl IoFlags {
35    /// Construct a new `IoFlags` for a data field.
36    pub const fn data() -> Self {
37        Self::new()
38    }
39
40    /// Construct a new `IoFlags` for a constant field.
41    pub const fn constant() -> Self {
42        Self::new().with_data_or_constant(true)
43    }
44
45    /// The field stores a variable (otherwise it will store an array)
46    pub const fn variable(self) -> Self {
47        self.with_array_or_variable(true)
48    }
49
50    /// The field holds a relative value (by default values are absolute)
51    pub const fn relative(self) -> Self {
52        self.with_absolute_or_relative(true)
53    }
54}
55
56/// A collection of shorthand types for specifying input/output/feature item flags.
57///
58/// These are not required ([`IoFlags`] may be used instead) but because it may not
59/// be clear what the default flags are, these values may improve readability.
60pub mod ioflags {
61    use super::IoFlags;
62
63    /// Input/Output/Feature flags, using the terminology common in USB HID standards.
64    ///
65    /// This is shorthand for `IoFlags::data().variable()`.
66    pub const DATA_VARIABLE_ABSOLUTE: IoFlags = IoFlags::data().variable();
67
68    /// Input/Output/Feature flags for a constant, using the terminology common in USB HID standards.
69    ///
70    /// This is shorthand for `IoFlags::constant()`. It is commonly used to declare padding bits or bytes.
71    pub const CONSTANT: IoFlags = IoFlags::constant();
72
73    /// Input/Output/Feature flags for a data array, using the terminology common in USB HID standards.
74    ///
75    /// This is shorthand for `IoFlags::data()` (Note: the flag defaults to "array").
76    pub const ARRAY: IoFlags = IoFlags::data();
77}
78
79/// A wrapper indicating `IoFlags` that should be interpreted as Input flags.
80#[derive(Clone, Copy)]
81pub struct InputFlags(pub IoFlags);
82
83/// A wrapper indicating `IoFlags` that should be interpreted as Output or Feature flags.
84#[derive(Clone, Copy)]
85pub struct OutputFeatureFlags(pub IoFlags);
86
87/// A known __Collection__ type.
88#[expect(missing_docs)]
89#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
90#[repr(u8)]
91pub enum KnownCollectionType {
92    Physical = 0,
93    Application = 1,
94    Logical = 2,
95    Report = 3,
96    NamedArray = 4,
97    UsageSwitch = 5,
98    UsageModifier = 6,
99}
100
101/// A __Collection__ type.
102pub type CollectionType = Ident<KnownCollectionType, u8>;
103
104/// Some known unit values.
105///
106/// Note: this type is incomplete, and does not represent all
107/// the possible unit values.
108#[expect(missing_docs)]
109#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive)]
110#[repr(u32)]
111#[non_exhaustive]
112pub enum KnownUnit {
113    // Length^1 in SI Linear (1)
114    Centimeter = 0x11,
115    // Length^1 in SI Rotation (2)
116    Radian = 0x12,
117    // Length^1 in English Linear (3)
118    Inch = 0x13,
119    // Length^1 in English Rotation(4)
120    Degree = 0x14,
121}
122
123/// A __Unit__ value.
124pub type Unit = Ident<KnownUnit, u32>;
125
126#[cfg(feature = "std")]
127mod std_impls {
128    use super::*;
129
130    use std::fmt::{self, Debug};
131
132    fn debug_flags(is_input: bool, flags: IoFlags, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        if flags.data_or_constant() {
134            f.write_str("Constant ")?;
135        } else {
136            f.write_str("Data ")?;
137        }
138        if flags.array_or_variable() {
139            f.write_str("Variable ")?;
140        } else {
141            f.write_str("Array ")?;
142        }
143        if flags.absolute_or_relative() {
144            f.write_str("Relative ")?;
145        } else {
146            f.write_str("Absolute ")?;
147        }
148        if flags.wrap() {
149            f.write_str("Wrap ")?;
150        } else {
151            f.write_str("No-Wrap ")?;
152        }
153        if flags.non_linear() {
154            f.write_str("Non-Linear ")?;
155        } else {
156            f.write_str("Linear ")?;
157        }
158        if flags.no_preferred() {
159            f.write_str("No-Preferred ")?;
160        } else {
161            f.write_str("Preferred-State ")?;
162        }
163        if flags.null_state() {
164            f.write_str("Null-State ")?
165        } else {
166            f.write_str("No-Null-Position ")?;
167        }
168
169        // The `volatile` field is only valid for Output and Feature tags.
170        if flags.volatile() {
171            f.write_str("Volatile ")?;
172        } else {
173            if !is_input {
174                f.write_str("Non-Volatile ")?;
175            }
176        }
177
178        if flags.bitfield_or_buffered() {
179            f.write_str("Buffered-Bytes")?;
180        } else {
181            f.write_str("Bit-Field")?;
182        }
183        Ok(())
184    }
185
186    impl Debug for InputFlags {
187        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188            debug_flags(true, self.0, f)
189        }
190    }
191
192    impl Debug for OutputFeatureFlags {
193        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194            debug_flags(false, self.0, f)
195        }
196    }
197}