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 core::ops::Deref for InputFlags {
215    type Target = IoFlags;
216
217    fn deref(&self) -> &Self::Target {
218        &self.0
219    }
220}
221
222impl InputFlags {
223    /// Mark some flags as input flags, without checking if the bit pattern is sensible for an Input item.
224    pub fn from_unchecked(flags: IoFlags) -> Self {
225        Self(flags)
226    }
227
228    #[doc(hidden)]
229    #[deprecated = "`InputFlags` should not use the volatile bit"]
230    /// Attempt to prevent users from calling .volatile() on InputFlags, since that bit shouldn't be used.
231    pub fn is_volatile(&self) -> bool {
232        self.0.is_volatile()
233    }
234}
235
236/// A wrapper indicating `IoFlags` that should be interpreted as Output or Feature flags.
237#[derive(Clone, Copy, PartialEq)]
238pub struct OutputFeatureFlags(pub IoFlags);
239
240impl core::ops::Deref for OutputFeatureFlags {
241    type Target = IoFlags;
242
243    fn deref(&self) -> &Self::Target {
244        &self.0
245    }
246}
247
248impl From<IoFlags> for OutputFeatureFlags {
249    /// Convert an `IoFlags` value.
250    ///
251    /// Note that unline [`InputFlags`], all `IoFlags` values are valid Output or Feature flags.
252    fn from(flags: IoFlags) -> Self {
253        Self(flags)
254    }
255}
256
257#[cfg(feature = "std")]
258mod std_impls {
259    use super::*;
260
261    use std::fmt::{self, Debug};
262
263    fn debug_flags(is_input: bool, flags: IoFlags, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        if flags.data_or_constant() {
265            f.write_str("Constant ")?;
266        } else {
267            f.write_str("Data ")?;
268        }
269        if flags.array_or_variable() {
270            f.write_str("Variable ")?;
271        } else {
272            f.write_str("Array ")?;
273        }
274        if flags.absolute_or_relative() {
275            f.write_str("Relative ")?;
276        } else {
277            f.write_str("Absolute ")?;
278        }
279        if flags.no_wrap_or_wrap() {
280            f.write_str("Wrap ")?;
281        } else {
282            f.write_str("No-Wrap ")?;
283        }
284        if flags.linear_or_nonlinear() {
285            f.write_str("Non-Linear ")?;
286        } else {
287            f.write_str("Linear ")?;
288        }
289        if flags.preferred_or_no_preferred() {
290            f.write_str("No-Preferred ")?;
291        } else {
292            f.write_str("Preferred-State ")?;
293        }
294        if flags.no_null_position_or_null_state() {
295            f.write_str("Null-State ")?
296        } else {
297            f.write_str("No-Null-Position ")?;
298        }
299
300        // The `volatile` field is only valid for Output and Feature tags.
301        if flags.non_volatile_or_volatile() {
302            f.write_str("Volatile ")?;
303        } else {
304            if !is_input {
305                f.write_str("Non-Volatile ")?;
306            }
307        }
308
309        if flags.bitfield_or_buffered() {
310            f.write_str("Buffered-Bytes")?;
311        } else {
312            f.write_str("Bit-Field")?;
313        }
314        Ok(())
315    }
316
317    impl Debug for InputFlags {
318        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319            debug_flags(true, self.0, f)
320        }
321    }
322
323    impl Debug for OutputFeatureFlags {
324        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325            debug_flags(false, self.0, f)
326        }
327    }
328}
329
330#[cfg(test)]
331mod tests {
332    use super::*;
333
334    #[test]
335    fn test_ioflags() {
336        const DATA: IoFlags = IoFlags::data();
337        const CONSTANT: IoFlags = IoFlags::constant();
338
339        assert!(DATA.is_data());
340        assert!(!DATA.is_constant());
341        assert!(!CONSTANT.is_data());
342        assert!(CONSTANT.is_constant());
343
344        assert!(DATA.is_array());
345        assert!(!DATA.is_variable());
346        assert!(!DATA.variable().is_array());
347        assert!(DATA.variable().is_variable());
348
349        assert!(DATA.is_absolute());
350        assert!(!DATA.is_relative());
351        assert!(!DATA.relative().is_absolute());
352        assert!(DATA.relative().is_relative());
353
354        assert!(!DATA.wraps());
355        assert!(DATA.wrap().wraps());
356
357        assert!(DATA.is_linear());
358        assert!(!DATA.non_linear().is_linear());
359
360        assert!(DATA.has_preferred_state());
361        assert!(!DATA.no_preferred_state().has_preferred_state());
362
363        assert!(DATA.has_null_state());
364        assert!(!DATA.null_state().has_null_state());
365
366        assert!(!DATA.is_volatile());
367        assert!(DATA.volatile().is_volatile());
368
369        assert!(DATA.is_bitfield());
370        assert!(!DATA.is_buffered());
371        assert!(!DATA.buffered().is_bitfield());
372        assert!(DATA.buffered().is_buffered());
373    }
374}