#![no_std]
#![deny(missing_docs)]
extern crate alloc;
extern crate core as std;
mod error;
mod global_items;
mod local_items;
mod macros;
mod main_items;
mod privates;
mod reserved;
use alloc::{
format,
string::{String, ToString},
vec::Vec,
};
use std::fmt::Display;
pub use error::*;
pub use global_items::*;
pub use local_items::*;
pub use main_items::*;
pub(crate) use privates::*;
pub use reserved::*;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReportItem {
Input(Input),
Output(Output),
Feature(Feature),
Collection(Collection),
EndCollection(EndCollection),
UsagePage(UsagePage),
LogicalMinimum(LogicalMinimum),
LogicalMaximum(LogicalMaximum),
PhysicalMinimum(PhysicalMinimum),
PhysicalMaximum(PhysicalMaximum),
UnitExponent(UnitExponent),
Unit(Unit),
ReportSize(ReportSize),
ReportId(ReportId),
ReportCount(ReportCount),
Push(Push),
Pop(Pop),
Usage(Usage),
UsageMinimum(UsageMinimum),
UsageMaximum(UsageMaximum),
DesignatorIndex(DesignatorIndex),
DesignatorMinimum(DesignatorMinimum),
DesignatorMaximum(DesignatorMaximum),
StringIndex(StringIndex),
StringMinimum(StringMinimum),
StringMaximum(StringMaximum),
Delimiter(Delimiter),
Reserved(Reserved),
}
impl AsRef<[u8]> for ReportItem {
fn as_ref(&self) -> &[u8] {
match self {
ReportItem::Input(inner) => inner.as_ref(),
ReportItem::Output(inner) => inner.as_ref(),
ReportItem::Feature(inner) => inner.as_ref(),
ReportItem::Collection(inner) => inner.as_ref(),
ReportItem::EndCollection(inner) => inner.as_ref(),
ReportItem::UsagePage(inner) => inner.as_ref(),
ReportItem::LogicalMinimum(inner) => inner.as_ref(),
ReportItem::LogicalMaximum(inner) => inner.as_ref(),
ReportItem::PhysicalMinimum(inner) => inner.as_ref(),
ReportItem::PhysicalMaximum(inner) => inner.as_ref(),
ReportItem::UnitExponent(inner) => inner.as_ref(),
ReportItem::Unit(inner) => inner.as_ref(),
ReportItem::ReportSize(inner) => inner.as_ref(),
ReportItem::ReportId(inner) => inner.as_ref(),
ReportItem::ReportCount(inner) => inner.as_ref(),
ReportItem::Push(inner) => inner.as_ref(),
ReportItem::Pop(inner) => inner.as_ref(),
ReportItem::Usage(inner) => inner.as_ref(),
ReportItem::UsageMinimum(inner) => inner.as_ref(),
ReportItem::UsageMaximum(inner) => inner.as_ref(),
ReportItem::DesignatorIndex(inner) => inner.as_ref(),
ReportItem::DesignatorMinimum(inner) => inner.as_ref(),
ReportItem::DesignatorMaximum(inner) => inner.as_ref(),
ReportItem::StringIndex(inner) => inner.as_ref(),
ReportItem::StringMinimum(inner) => inner.as_ref(),
ReportItem::StringMaximum(inner) => inner.as_ref(),
ReportItem::Delimiter(inner) => inner.as_ref(),
ReportItem::Reserved(inner) => inner.as_ref(),
}
}
}
impl Display for ReportItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ReportItem::Input(inner) => inner.fmt(f),
ReportItem::Output(inner) => inner.fmt(f),
ReportItem::Feature(inner) => inner.fmt(f),
ReportItem::Collection(inner) => inner.fmt(f),
ReportItem::EndCollection(inner) => inner.fmt(f),
ReportItem::UsagePage(inner) => inner.fmt(f),
ReportItem::LogicalMinimum(inner) => inner.fmt(f),
ReportItem::LogicalMaximum(inner) => inner.fmt(f),
ReportItem::PhysicalMinimum(inner) => inner.fmt(f),
ReportItem::PhysicalMaximum(inner) => inner.fmt(f),
ReportItem::UnitExponent(inner) => inner.fmt(f),
ReportItem::Unit(inner) => inner.fmt(f),
ReportItem::ReportSize(inner) => inner.fmt(f),
ReportItem::ReportId(inner) => inner.fmt(f),
ReportItem::ReportCount(inner) => inner.fmt(f),
ReportItem::Push(inner) => inner.fmt(f),
ReportItem::Pop(inner) => inner.fmt(f),
ReportItem::Usage(inner) => inner.fmt(f),
ReportItem::UsageMinimum(inner) => inner.fmt(f),
ReportItem::UsageMaximum(inner) => inner.fmt(f),
ReportItem::DesignatorIndex(inner) => inner.fmt(f),
ReportItem::DesignatorMinimum(inner) => inner.fmt(f),
ReportItem::DesignatorMaximum(inner) => inner.fmt(f),
ReportItem::StringIndex(inner) => inner.fmt(f),
ReportItem::StringMinimum(inner) => inner.fmt(f),
ReportItem::StringMaximum(inner) => inner.fmt(f),
ReportItem::Delimiter(inner) => inner.fmt(f),
ReportItem::Reserved(inner) => inner.fmt(f),
}
}
}
impl ReportItem {
pub fn new(raw: &[u8]) -> Result<Self, HidError> {
if raw.is_empty() {
return Err(HidError::EmptyRawInput);
};
let expected = __data_size(raw[0]);
if expected + 1 != raw.len() {
return Err(HidError::DataSizeNotMatch {
expected,
provided: raw.len() - 1,
});
};
unsafe {
Ok(match raw[0] & 0b1111_1100 {
Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
EndCollection::PREFIX => {
ReportItem::EndCollection(EndCollection::new_unchecked(raw))
}
UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
LogicalMinimum::PREFIX => {
ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
}
LogicalMaximum::PREFIX => {
ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
}
PhysicalMinimum::PREFIX => {
ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
}
PhysicalMaximum::PREFIX => {
ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
}
UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
DesignatorIndex::PREFIX => {
ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
}
DesignatorMinimum::PREFIX => {
ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
}
DesignatorMaximum::PREFIX => {
ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
}
StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
StringMinimum::PREFIX => {
ReportItem::StringMinimum(StringMinimum::new_unchecked(raw))
}
StringMaximum::PREFIX => {
ReportItem::StringMaximum(StringMaximum::new_unchecked(raw))
}
Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
_ => ReportItem::Reserved(Reserved::new_unchecked(raw)),
})
}
}
pub fn new_strict(raw: &[u8]) -> Result<Self, crate::HidError> {
if raw.is_empty() {
return Err(crate::HidError::EmptyRawInput);
};
let expected = __data_size(raw[0]);
if expected + 1 != raw.len() {
return Err(HidError::DataSizeNotMatch {
expected,
provided: raw.len() - 1,
});
};
unsafe {
Ok(match raw[0] & 0b1111_1100 {
Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
EndCollection::PREFIX => {
ReportItem::EndCollection(EndCollection::new_unchecked(raw))
}
UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
LogicalMinimum::PREFIX => {
ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
}
LogicalMaximum::PREFIX => {
ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
}
PhysicalMinimum::PREFIX => {
ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
}
PhysicalMaximum::PREFIX => {
ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
}
UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
DesignatorIndex::PREFIX => {
ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
}
DesignatorMinimum::PREFIX => {
ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
}
DesignatorMaximum::PREFIX => {
ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
}
StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
StringMinimum::PREFIX => {
ReportItem::StringMinimum(StringMinimum::new_unchecked(raw))
}
StringMaximum::PREFIX => {
ReportItem::StringMaximum(StringMaximum::new_unchecked(raw))
}
Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
_ => return Err(HidError::ReservedItem(Reserved::new_unchecked(raw))),
})
}
}
pub unsafe fn new_unchecked(raw: &[u8]) -> Self {
match raw[0] & 0b1111_1100 {
Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
EndCollection::PREFIX => ReportItem::EndCollection(EndCollection::new_unchecked(raw)),
UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
LogicalMinimum::PREFIX => {
ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
}
LogicalMaximum::PREFIX => {
ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
}
PhysicalMinimum::PREFIX => {
ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
}
PhysicalMaximum::PREFIX => {
ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
}
UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
DesignatorIndex::PREFIX => {
ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
}
DesignatorMinimum::PREFIX => {
ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
}
DesignatorMaximum::PREFIX => {
ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
}
StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
StringMinimum::PREFIX => ReportItem::StringMinimum(StringMinimum::new_unchecked(raw)),
StringMaximum::PREFIX => ReportItem::StringMaximum(StringMaximum::new_unchecked(raw)),
Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
_ => ReportItem::Reserved(Reserved::new_unchecked(raw)),
}
}
pub unsafe fn new_strict_unchecked(raw: &[u8]) -> Result<Self, HidError> {
Ok(match raw[0] & 0b1111_1100 {
Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
EndCollection::PREFIX => ReportItem::EndCollection(EndCollection::new_unchecked(raw)),
UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
LogicalMinimum::PREFIX => {
ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
}
LogicalMaximum::PREFIX => {
ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
}
PhysicalMinimum::PREFIX => {
ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
}
PhysicalMaximum::PREFIX => {
ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
}
UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
DesignatorIndex::PREFIX => {
ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
}
DesignatorMinimum::PREFIX => {
ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
}
DesignatorMaximum::PREFIX => {
ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
}
StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
StringMinimum::PREFIX => ReportItem::StringMinimum(StringMinimum::new_unchecked(raw)),
StringMaximum::PREFIX => ReportItem::StringMaximum(StringMaximum::new_unchecked(raw)),
Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
_ => return Err(HidError::ReservedItem(Reserved::new_unchecked(raw))),
})
}
pub fn prefix(&self) -> u8 {
self.as_ref()[0]
}
pub fn data(&self) -> &[u8] {
&self.as_ref()[1..]
}
}
struct Iter<ByteStreamIter: Iterator<Item = u8>> {
byte_stream_iter: ByteStreamIter,
usage_page: Option<UsagePage>,
}
struct StrictIter<ByteStreamIter: Iterator<Item = u8>> {
byte_stream_iter: ByteStreamIter,
usage_page: Option<UsagePage>,
}
impl<ByteStreamIter: Iterator<Item = u8>> Iterator for Iter<ByteStreamIter> {
type Item = ReportItem;
fn next(&mut self) -> Option<Self::Item> {
let prefix = self.byte_stream_iter.next()?;
let size = __data_size(prefix);
let mut storage = [0u8; 5];
storage[0] = prefix;
for i in 0..size {
storage[i + 1] = self.byte_stream_iter.next()?;
}
let mut item = unsafe { ReportItem::new_unchecked(&storage) };
if let ReportItem::UsagePage(usage_page) = &item {
self.usage_page = Some(usage_page.clone());
}
if let Some(usage_page) = &self.usage_page {
match &mut item {
ReportItem::Usage(usage) => usage.set_usage_page(usage_page.clone()),
ReportItem::UsageMinimum(usage_minimum) => {
usage_minimum.set_usage_page(usage_page.clone())
}
ReportItem::UsageMaximum(usage_maximum) => {
usage_maximum.set_usage_page(usage_page.clone())
}
_ => (),
}
}
Some(item)
}
}
impl<ByteStreamIter: Iterator<Item = u8>> Iterator for StrictIter<ByteStreamIter> {
type Item = Result<ReportItem, HidError>;
fn next(&mut self) -> Option<Self::Item> {
let prefix = self.byte_stream_iter.next()?;
let size = __data_size(prefix);
let mut storage = [0u8; 5];
storage[0] = prefix;
for i in 0..size {
storage[i + 1] = self.byte_stream_iter.next()?;
}
let mut item = unsafe { ReportItem::new_strict_unchecked(&storage) };
if let Ok(ReportItem::UsagePage(usage_page)) = &item {
self.usage_page = Some(usage_page.clone());
}
if let Some(usage_page) = &self.usage_page {
match &mut item {
Ok(ReportItem::Usage(usage)) => usage.set_usage_page(usage_page.clone()),
Ok(ReportItem::UsageMinimum(usage_minimum)) => {
usage_minimum.set_usage_page(usage_page.clone())
}
Ok(ReportItem::UsageMaximum(usage_maximum)) => {
usage_maximum.set_usage_page(usage_page.clone())
}
_ => (),
}
}
Some(item)
}
}
pub fn parse<ByteStream: IntoIterator<Item = u8>>(
byte_stream: ByteStream,
) -> impl Iterator<Item = ReportItem> {
Iter {
byte_stream_iter: byte_stream.into_iter(),
usage_page: None,
}
}
pub fn parse_strict<ByteStream: IntoIterator<Item = u8>>(
byte_stream: ByteStream,
) -> impl Iterator<Item = Result<ReportItem, HidError>> {
StrictIter {
byte_stream_iter: byte_stream.into_iter(),
usage_page: None,
}
}
pub fn dump<'a, ItemStream: IntoIterator<Item = &'a ReportItem>>(
item_stream: ItemStream,
) -> Vec<u8> {
let mut v = Vec::new();
for item in item_stream {
v.extend_from_slice(item.as_ref());
}
v
}
pub fn pretty_print<'a, ItemStream: IntoIterator<Item = &'a ReportItem>>(
item_stream: ItemStream,
) -> String {
let mut max_len = 0;
let mut tmp = Vec::new();
let mut tab: usize = 0;
for item in item_stream {
match item {
ReportItem::Collection(_) | ReportItem::Push(_) => tab += 1,
ReportItem::EndCollection(_) | ReportItem::Pop(_) => tab = tab.saturating_sub(1),
_ => (),
}
max_len = std::cmp::max(max_len, item.as_ref().len());
tmp.push((
item.as_ref()
.iter()
.map(|byte| format!("{:#04X}", byte))
.collect::<Vec<_>>()
.join(", "),
item.to_string(),
tab * 2 + 1,
));
}
let width_of_raw = max_len * 6;
tmp.into_iter()
.map(|(raw, comment, tab)| format!("{:<width_of_raw$}//{:<tab$}{}", raw, ' ', comment))
.collect::<Vec<_>>()
.join("\n")
}