Skip to main content

hid_types/id/
iof.rs

1//! Types used in Input/Output/Feature items.
2
3use bitfield_struct::bitfield;
4
5/// Flags that can be used with Input, Output, or Feature items.
6///
7/// # Example
8///
9/// ```rust
10/// # use hid_types::id::IoFlags;
11/// let flags = IoFlags::data().variable().null_state();
12/// assert_eq!(u32::from(flags), 0x42);
13/// ```
14#[bitfield(u32, debug = false, new = false)]
15#[derive(PartialEq)]
16pub struct IoFlags {
17    #[bits(1)]
18    data_or_constant: bool,
19    #[bits(1)]
20    array_or_variable: bool,
21    #[bits(1)]
22    absolute_or_relative: bool,
23    #[bits(1)]
24    no_wrap_or_wrap: bool,
25    #[bits(1)]
26    linear_or_nonlinear: bool,
27    #[bits(1)]
28    preferred_or_no_preferred: bool,
29    #[bits(1)]
30    no_null_position_or_null_state: bool,
31    // Note: `volatile` is only valid for Output and Feature (not Input)
32    #[bits(1)]
33    non_volatile_or_volatile: bool,
34    #[bits(1)]
35    bitfield_or_buffered: bool,
36    #[bits(23)]
37    _reserved: u32,
38}
39
40impl IoFlags {
41    const fn new() -> Self {
42        Self(0)
43    }
44
45    /// Construct a new `IoFlags` for a data field.
46    pub const fn data() -> Self {
47        Self::new()
48    }
49
50    /// Construct a new `IoFlags` for a constant field.
51    pub const fn constant() -> Self {
52        Self::new().with_data_or_constant(true)
53    }
54
55    /// Test if this is a constant field.
56    pub const fn is_constant(self) -> bool {
57        self.data_or_constant()
58    }
59    /// Test if this is a data field.
60    pub const fn is_data(self) -> bool {
61        !self.is_constant()
62    }
63
64    /// The field stores a variable.
65    ///
66    /// By default fields store an array.
67    pub const fn variable(self) -> Self {
68        self.with_array_or_variable(true)
69    }
70
71    /// Test if this is a variable field.
72    pub const fn is_variable(self) -> bool {
73        self.array_or_variable()
74    }
75    /// Test if this is an array field.
76    pub const fn is_array(self) -> bool {
77        !self.is_variable()
78    }
79
80    /// The field holds a relative value.
81    ///
82    /// By default values are absolute.
83    pub const fn relative(self) -> Self {
84        self.with_absolute_or_relative(true)
85    }
86
87    /// Test if this field is relative.
88    pub const fn is_relative(self) -> bool {
89        self.absolute_or_relative()
90    }
91    /// Test if this field is absolute.
92    pub const fn is_absolute(self) -> bool {
93        !self.is_relative()
94    }
95
96    /// The value wraps around in the positive and negative directions.
97    ///
98    /// By default values do not wrap.
99    pub const fn wrap(self) -> Self {
100        self.with_no_wrap_or_wrap(true)
101    }
102
103    /// Test if this field wraps.
104    pub const fn wraps(self) -> bool {
105        self.no_wrap_or_wrap()
106    }
107
108    /// The value is non-linear.
109    ///
110    /// By default values are linear.
111    pub const fn non_linear(self) -> Self {
112        self.with_linear_or_nonlinear(true)
113    }
114
115    /// Test if this field is linear.
116    pub const fn is_linear(self) -> bool {
117        !self.linear_or_nonlinear()
118    }
119
120    /// The value has no preferred state.
121    ///
122    /// Preferred state means that a control will return to some state
123    /// when it's not being used. Buttons or joysticks are examples of
124    /// controls with a preferred state.
125    ///
126    /// By default values have a preferred state.
127    pub const fn no_preferred_state(self) -> Self {
128        self.with_preferred_or_no_preferred(true)
129    }
130
131    /// Test if this field has a preferred state.
132    pub const fn has_preferred_state(self) -> bool {
133        !self.preferred_or_no_preferred()
134    }
135
136    /// The control has a null state.
137    ///
138    /// A null state is a value outside the logical minimum-maximum range,
139    /// used to indicate that the control is not active (such as a hat switch).
140    ///
141    /// By default controls have no null position.
142    pub const fn null_state(self) -> Self {
143        self.with_no_null_position_or_null_state(true)
144    }
145
146    /// Test if this field has a null state.
147    pub const fn has_null_state(self) -> bool {
148        !self.no_null_position_or_null_state()
149    }
150
151    /// The value is volatile.
152    ///
153    /// A volatile value is one that can change without host interaction.
154    ///
155    /// By default a value is non-volatile.
156    ///
157    /// This flag is only used for Output or Feature items.
158    pub const fn volatile(self) -> Self {
159        self.with_non_volatile_or_volatile(true)
160    }
161
162    /// Test if this field is volatile.
163    pub const fn is_volatile(self) -> bool {
164        self.non_volatile_or_volatile()
165    }
166
167    /// The value is buffered.
168    ///
169    /// Buffered data is not a single numeric quantity, but instead
170    /// part of a stream of bytes (for example data from a barcode reader).
171    ///
172    /// By default a value is a bit field.
173    pub const fn buffered(self) -> Self {
174        self.with_bitfield_or_buffered(true)
175    }
176
177    /// Test if this field is buffered.
178    pub const fn is_buffered(self) -> bool {
179        self.bitfield_or_buffered()
180    }
181    /// Test if this field is a bit field.
182    pub const fn is_bitfield(self) -> bool {
183        !self.is_buffered()
184    }
185}
186
187/// A collection of shorthand types for specifying input/output/feature item flags.
188///
189/// These are not required ([`IoFlags`] may be used instead) but because it may not
190/// be clear what the default flags are, these values may improve readability.
191pub mod ioflags {
192    use super::IoFlags;
193
194    /// Input/Output/Feature flags, using the terminology common in USB HID standards.
195    ///
196    /// This is shorthand for `IoFlags::data().variable()`.
197    pub const DATA_VARIABLE_ABSOLUTE: IoFlags = IoFlags::data().variable();
198
199    /// Input/Output/Feature flags for a constant, using the terminology common in USB HID standards.
200    ///
201    /// This is shorthand for `IoFlags::constant()`. It is commonly used to declare padding bits or bytes.
202    pub const CONSTANT: IoFlags = IoFlags::constant();
203
204    /// Input/Output/Feature flags for a data array, using the terminology common in USB HID standards.
205    ///
206    /// This is shorthand for `IoFlags::data()` (Note: the flag defaults to "array").
207    pub const ARRAY: IoFlags = IoFlags::data();
208}
209
210/// A wrapper indicating `IoFlags` that should be interpreted as Input flags.
211#[derive(Clone, Copy, PartialEq)]
212pub struct InputFlags(pub IoFlags);
213
214impl InputFlags {
215    /// Mark some flags as input flags, without checking if the bit pattern is sensible for an Input item.
216    pub fn from_unchecked(flags: IoFlags) -> Self {
217        Self(flags)
218    }
219}
220
221/// A wrapper indicating `IoFlags` that should be interpreted as Output or Feature flags.
222#[derive(Clone, Copy, PartialEq)]
223pub struct OutputFeatureFlags(pub IoFlags);
224
225impl From<IoFlags> for OutputFeatureFlags {
226    /// Convert an `IoFlags` value.
227    ///
228    /// Note that unline [`InputFlags`], all `IoFlags` values are valid Output or Feature flags.
229    fn from(flags: IoFlags) -> Self {
230        Self(flags)
231    }
232}
233
234#[cfg(feature = "std")]
235mod std_impls {
236    use super::*;
237
238    use std::fmt::{self, Debug};
239
240    fn debug_flags(is_input: bool, flags: IoFlags, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        if flags.data_or_constant() {
242            f.write_str("Constant ")?;
243        } else {
244            f.write_str("Data ")?;
245        }
246        if flags.array_or_variable() {
247            f.write_str("Variable ")?;
248        } else {
249            f.write_str("Array ")?;
250        }
251        if flags.absolute_or_relative() {
252            f.write_str("Relative ")?;
253        } else {
254            f.write_str("Absolute ")?;
255        }
256        if flags.no_wrap_or_wrap() {
257            f.write_str("Wrap ")?;
258        } else {
259            f.write_str("No-Wrap ")?;
260        }
261        if flags.linear_or_nonlinear() {
262            f.write_str("Non-Linear ")?;
263        } else {
264            f.write_str("Linear ")?;
265        }
266        if flags.preferred_or_no_preferred() {
267            f.write_str("No-Preferred ")?;
268        } else {
269            f.write_str("Preferred-State ")?;
270        }
271        if flags.no_null_position_or_null_state() {
272            f.write_str("Null-State ")?
273        } else {
274            f.write_str("No-Null-Position ")?;
275        }
276
277        // The `volatile` field is only valid for Output and Feature tags.
278        if flags.non_volatile_or_volatile() {
279            f.write_str("Volatile ")?;
280        } else {
281            if !is_input {
282                f.write_str("Non-Volatile ")?;
283            }
284        }
285
286        if flags.bitfield_or_buffered() {
287            f.write_str("Buffered-Bytes")?;
288        } else {
289            f.write_str("Bit-Field")?;
290        }
291        Ok(())
292    }
293
294    impl Debug for InputFlags {
295        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296            debug_flags(true, self.0, f)
297        }
298    }
299
300    impl Debug for OutputFeatureFlags {
301        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302            debug_flags(false, self.0, f)
303        }
304    }
305}
306
307#[cfg(test)]
308mod tests {
309    use super::*;
310
311    #[test]
312    fn test_ioflags() {
313        const DATA: IoFlags = IoFlags::data();
314        const CONSTANT: IoFlags = IoFlags::constant();
315
316        assert!(DATA.is_data());
317        assert!(!DATA.is_constant());
318        assert!(!CONSTANT.is_data());
319        assert!(CONSTANT.is_constant());
320
321        assert!(DATA.is_array());
322        assert!(!DATA.is_variable());
323        assert!(!DATA.variable().is_array());
324        assert!(DATA.variable().is_variable());
325
326        assert!(DATA.is_absolute());
327        assert!(!DATA.is_relative());
328        assert!(!DATA.relative().is_absolute());
329        assert!(DATA.relative().is_relative());
330
331        assert!(!DATA.wraps());
332        assert!(DATA.wrap().wraps());
333
334        assert!(DATA.is_linear());
335        assert!(!DATA.non_linear().is_linear());
336
337        assert!(DATA.has_preferred_state());
338        assert!(!DATA.no_preferred_state().has_preferred_state());
339
340        assert!(DATA.has_null_state());
341        assert!(!DATA.null_state().has_null_state());
342
343        assert!(!DATA.is_volatile());
344        assert!(DATA.volatile().is_volatile());
345
346        assert!(DATA.is_bitfield());
347        assert!(!DATA.is_buffered());
348        assert!(!DATA.buffered().is_bitfield());
349        assert!(DATA.buffered().is_buffered());
350    }
351}