use bitvec::prelude::*; use std::fmt; use std::ops::{Deref, DerefMut}; /// A collection of bits representing either device capability or state. /// /// This can be used to iterate across all keys supported by a keyboard, or all buttons supported /// by a joystick. You can also query directly whether a specific bit is set (corresponding to /// whether a key or button is depressed). #[repr(transparent)] pub struct AttributeSetRef { _indexer: std::marker::PhantomData, bitslice: BitSlice, } impl AttributeSetRef { #[inline] fn new(bitslice: &BitSlice) -> &Self { // SAFETY: for AttributeSet is repr(transparent) over BitSlice unsafe { &*(bitslice as *const BitSlice as *const Self) } } #[inline] fn new_mut(bitslice: &mut BitSlice) -> &mut Self { // SAFETY: for AttributeSet is repr(transparent) over BitSlice unsafe { &mut *(bitslice as *mut BitSlice as *mut Self) } } /// Returns `true` if this AttributeSet contains the passed T. #[inline] pub fn contains(&self, attr: T) -> bool { self.bitslice.get(attr.to_index()).map_or(false, |b| *b) } /// Provides an iterator over all "set" bits in the collection. #[inline] pub fn iter(&self) -> impl Iterator + '_ { self.bitslice.iter_ones().map(T::from_index) } #[inline] pub(crate) fn slice(&self, start: T) -> &Self { Self::new(&self.bitslice[start.to_index()..]) } pub fn insert(&mut self, attr: T) { self.set(attr, true) } pub fn remove(&mut self, attr: T) { self.set(attr, false) } // TODO: figure out a good name for this if we make it public #[inline] pub(crate) fn set(&mut self, attr: T, on: bool) { self.bitslice.set(attr.to_index(), on) } } impl fmt::Debug for AttributeSetRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_set().entries(self.iter()).finish() } } pub struct AttributeSet { container: T::Array, } impl AttributeSet { pub fn new() -> Self { Self { container: T::zeroed_array(), } } fn as_bitslice(&self) -> &BitSlice { T::array_as_slice(&self.container) } fn as_mut_bitslice(&mut self) -> &mut BitSlice { T::array_as_slice_mut(&mut self.container) } #[inline] pub(crate) fn as_mut_raw_slice(&mut self) -> &mut [u8] { T::array_as_buf(&mut self.container) } } impl Default for AttributeSet { fn default() -> Self { Self::new() } } impl Deref for AttributeSet { type Target = AttributeSetRef; fn deref(&self) -> &AttributeSetRef { AttributeSetRef::new(self.as_bitslice()) } } impl DerefMut for AttributeSet { fn deref_mut(&mut self) -> &mut AttributeSetRef { AttributeSetRef::new_mut(self.as_mut_bitslice()) } } impl Clone for AttributeSet where T::Array: Clone, { fn clone(&self) -> Self { Self { container: self.container.clone(), } } fn clone_from(&mut self, other: &Self) { self.container.clone_from(&other.container) } } impl fmt::Debug for AttributeSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } } pub trait EvdevEnum: Copy + 'static { fn from_index(i: usize) -> Self; fn to_index(self) -> usize; } pub trait ArrayedEvdevEnum: EvdevEnum { type Array; fn array_as_slice(arr: &Self::Array) -> &BitSlice; fn array_as_slice_mut(arr: &mut Self::Array) -> &mut BitSlice; fn array_as_buf(arr: &mut Self::Array) -> &mut [u8]; fn zeroed_array() -> Self::Array; } macro_rules! evdev_enum { ($t:ty, Array, $($(#[$attr:meta])* $c:ident = $val:expr,)*) => { evdev_enum!( $t, Array:bitvec::BitArr!(for <$t>::COUNT, in u8), |x| x, |x| x, bitvec::array::BitArray::as_mut_raw_slice, bitvec::array::BitArray::zeroed, $($(#[$attr])* $c = $val,)* ); }; ( $t:ty, Array: $Array:ty, $arr_as_slice:expr, $arr_as_slice_mut:expr, $arr_as_buf:expr, $zero:expr, $($(#[$attr:meta])* $c:ident = $val:expr,)* ) => { impl $crate::attribute_set::ArrayedEvdevEnum for $t { type Array = $Array; fn array_as_slice(arr: &Self::Array) -> &bitvec::slice::BitSlice { let f: fn(&Self::Array) -> &bitvec::slice::BitSlice = $arr_as_slice; f(arr) } fn array_as_slice_mut(arr: &mut Self::Array) -> &mut bitvec::slice::BitSlice { let f: fn(&mut Self::Array) -> &mut bitvec::slice::BitSlice = $arr_as_slice_mut; f(arr) } fn array_as_buf(arr: &mut Self::Array) -> &mut [u8] { let f: fn(&mut Self::Array) -> &mut [u8] = $arr_as_buf; f(arr) } fn zeroed_array() -> Self::Array { $zero() } } evdev_enum!($t, $($(#[$attr])* $c = $val,)*); }; ($t:ty, $($(#[$attr:meta])* $c:ident = $val:expr,)*) => { impl $t { $($(#[$attr])* pub const $c: Self = Self($val);)* } impl std::str::FromStr for $t { type Err = crate::EnumParseError; fn from_str(s: &str) -> Result { let map: &[(&'static str, $t)] = &[ $((stringify!($c), Self::$c),)* ]; match map.iter().find(|e| e.0 == s) { Some(e) => Ok(e.1), None => Err(crate::EnumParseError(())), } } } impl std::fmt::Debug for $t { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { #[allow(unreachable_patterns)] match *self { $(Self::$c => f.pad(stringify!($c)),)* _ => write!(f, "unknown key: {}", self.0), } } } impl $crate::attribute_set::EvdevEnum for $t { #[inline] fn from_index(i: usize) -> Self { Self(i as _) } #[inline] fn to_index(self) -> usize { self.0 as _ } } } }