use alloc::{collections::BTreeMap, vec, vec::Vec};
use crate::{
item_tokenizer::{DescriptorItemTokenizer, ReportItem, ReportItemType},
report_data_types::{ReportCount, ReportSize, UsagePage},
u32_from_bytes, ArrayField, DesignatorIndex, DesignatorRange, LogicalMaximum, LogicalMinimum, PaddingField,
PhysicalMaximum, PhysicalMinimum, Report, ReportAttributes, ReportCollection, ReportDescriptor, ReportField,
ReportId, StringIndex, StringRange, Unit, UnitExponent, Usage, UsageRange, VariableField,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ReportDescriptorError {
InvalidMainItem,
InvalidGlobalItem,
InvalidLocalItem,
ReservedItemNotSupported,
InvalidPop,
DelimiterNotSupported,
InvalidReportNoSize,
InvalidReportNoCount,
InvalidReportNoUsage,
InvalidReportNoLogicalMin,
InvalidReportNoLogicalMax,
InvalidReportLogicalRange,
}
#[derive(Debug, Clone, Default)]
struct GlobalItemStateTable {
usage_page: Option<UsagePage>,
logical_minimum: Option<LogicalMinimum>,
logical_maximum: Option<LogicalMaximum>,
physical_minimum: Option<PhysicalMinimum>,
physical_maximum: Option<PhysicalMaximum>,
unit_exponent: Option<UnitExponent>,
unit: Option<Unit>,
report_size: Option<ReportSize>,
report_id: Option<ReportId>,
report_count: Option<ReportCount>,
}
#[derive(Debug, Clone, Default)]
struct LocalItemStateTable {
usages: Vec<UsageRange>,
usage_minimum: Option<u32>,
usage_maximum: Option<u32>,
designators: Vec<DesignatorRange>,
designator_minimum: Option<u32>,
designator_maximum: Option<u32>,
strings: Vec<StringRange>,
string_minimum: Option<u32>,
string_maximum: Option<u32>,
}
struct ReportData {
attributes: ReportAttributes,
global_state: GlobalItemStateTable,
local_state: LocalItemStateTable,
member_of: Vec<ReportCollection>,
}
impl ReportData {
fn new(
item_data: &[u8],
global_state: GlobalItemStateTable,
local_state: LocalItemStateTable,
active_collections: Vec<ReportCollection>,
) -> Self {
ReportData {
attributes: ReportAttributes::from(item_data),
global_state: global_state,
local_state: local_state,
member_of: active_collections,
}
}
}
pub struct ReportDescriptorParser {
global_state: Vec<GlobalItemStateTable>,
local_state: LocalItemStateTable,
active_collections: Vec<ReportCollection>,
input_reports: BTreeMap<Option<ReportId>, Vec<ReportData>>,
output_reports: BTreeMap<Option<ReportId>, Vec<ReportData>>,
features: BTreeMap<Option<ReportId>, Vec<ReportData>>,
}
impl ReportDescriptorParser {
fn new() -> Self {
ReportDescriptorParser {
global_state: vec![Default::default()],
local_state: Default::default(),
active_collections: Vec::new(),
input_reports: BTreeMap::new(),
output_reports: BTreeMap::new(),
features: BTreeMap::new(),
}
}
fn parse_main(&mut self, item: ReportItem) -> Result<(), ReportDescriptorError> {
let report_id = self.global_state[0].report_id;
match item.tag {
0b1000 => {
let mut input_vec = match self.input_reports.remove(&report_id) {
Some(vec) => vec,
None => Vec::new(),
};
input_vec.push(ReportData::new(
item.data,
self.global_state[0].clone(),
self.local_state.clone(),
self.active_collections.clone(),
));
self.input_reports.insert(report_id, input_vec);
}
0b1001 => {
let mut output_vec = match self.output_reports.remove(&report_id) {
Some(vec) => vec,
None => Vec::new(),
};
output_vec.push(ReportData::new(
item.data,
self.global_state[0].clone(),
self.local_state.clone(),
self.active_collections.clone(),
));
self.output_reports.insert(report_id, output_vec);
}
0b1011 => {
let mut feature_vec = match self.features.remove(&report_id) {
Some(vec) => vec,
None => Vec::new(),
};
feature_vec.push(ReportData::new(
item.data,
self.global_state[0].clone(),
self.local_state.clone(),
self.active_collections.clone(),
));
self.features.insert(report_id, feature_vec);
}
0b1010 => {
let usage_page = self.global_state[0].usage_page;
let usage_range = self.local_state.usages.get(0);
let usage_range_start = match usage_range {
Some(range) => range.start(),
None => 0,
};
let usage = Usage::from_page_and_id(usage_page, Usage::from(usage_range_start));
let designator = self.local_state.designators.get(0).map(|x| DesignatorIndex::from(x.start()));
let string = self.local_state.strings.get(0).map(|x| StringIndex::from(x.start()));
let collection =
ReportCollection { usage, designator, string, member_of: self.active_collections.clone() };
self.active_collections.push(collection);
}
0b1100 => {
self.active_collections.pop();
}
_ => return Err(ReportDescriptorError::InvalidMainItem),
}
self.local_state = Default::default();
Ok(())
}
fn parse_global(&mut self, item: ReportItem) -> Result<(), ReportDescriptorError> {
match item.tag {
0b0000 => self.global_state[0].usage_page = Some(UsagePage::from(item.data)),
0b0001 => self.global_state[0].logical_minimum = Some(LogicalMinimum::from(item.data)),
0b0010 => self.global_state[0].logical_maximum = Some(LogicalMaximum::from(item.data)),
0b0011 => self.global_state[0].physical_minimum = Some(PhysicalMinimum::from(item.data)),
0b0100 => self.global_state[0].physical_maximum = Some(PhysicalMaximum::from(item.data)),
0b0101 => self.global_state[0].unit_exponent = Some(UnitExponent::from(item.data)),
0b0110 => self.global_state[0].unit = Some(Unit::from(item.data)),
0b0111 => self.global_state[0].report_size = Some(ReportSize::from(item.data)),
0b1000 => self.global_state[0].report_id = Some(ReportId::from(item.data)),
0b1001 => self.global_state[0].report_count = Some(ReportCount::from(item.data)),
0b1010 => self.global_state.push(self.global_state[0].clone()),
0b1011 => {
if self.global_state.len() < 2 {
return Err(ReportDescriptorError::InvalidPop);
}
self.global_state.pop().ok_or(ReportDescriptorError::InvalidPop)?;
}
_ => return Err(ReportDescriptorError::InvalidGlobalItem),
};
Ok(())
}
fn parse_local(&mut self, item: ReportItem) -> Result<(), ReportDescriptorError> {
match item.tag {
0b0000 => {
let usage = u32_from_bytes(item.data);
self.local_state.usages.push(UsageRange::from(usage..=usage));
}
0b0001 => {
let min = u32_from_bytes(item.data);
if let Some(max) = self.local_state.usage_maximum.take() {
self.local_state.usages.push(UsageRange::from(min..=max));
} else {
self.local_state.usage_minimum = Some(min);
}
}
0b0010 => {
let max = u32_from_bytes(item.data);
if let Some(min) = self.local_state.usage_minimum.take() {
self.local_state.usages.push(UsageRange::from(min..=max));
} else {
self.local_state.usage_maximum = Some(max);
}
}
0b0011 => {
let designator = u32_from_bytes(item.data);
self.local_state.designators.push(DesignatorRange::from(designator..=designator));
}
0b0100 => {
let min = u32_from_bytes(item.data);
if let Some(max) = self.local_state.designator_maximum.take() {
self.local_state.designators.push(DesignatorRange::from(min..=max));
} else {
self.local_state.designator_minimum = Some(min);
}
}
0b0101 => {
let max = u32_from_bytes(item.data);
if let Some(min) = self.local_state.designator_minimum.take() {
self.local_state.designators.push(DesignatorRange::from(min..=max));
} else {
self.local_state.designator_maximum = Some(max);
}
}
0b0111 => {
let string_idx = u32_from_bytes(item.data);
self.local_state.strings.push(StringRange::from(string_idx..=string_idx));
}
0b1000 => {
let min = u32_from_bytes(item.data);
if let Some(max) = self.local_state.string_maximum.take() {
self.local_state.strings.push(StringRange::from(min..=max));
} else {
self.local_state.string_minimum = Some(min);
}
}
0b1001 => {
let max = u32_from_bytes(item.data);
if let Some(min) = self.local_state.string_minimum.take() {
self.local_state.strings.push(StringRange::from(min..=max));
} else {
self.local_state.string_maximum = Some(max);
}
}
0b1010 => return Err(ReportDescriptorError::DelimiterNotSupported), _ => return Err(ReportDescriptorError::InvalidLocalItem),
}
Ok(())
}
fn parse_item(&mut self, item: ReportItem) -> Result<(), ReportDescriptorError> {
match item.item_type {
ReportItemType::Main => self.parse_main(item),
ReportItemType::Global => self.parse_global(item),
ReportItemType::Local => self.parse_local(item),
ReportItemType::Reserved => Err(ReportDescriptorError::ReservedItemNotSupported),
}
}
fn process_reports(
&self,
report_records: &BTreeMap<Option<ReportId>, Vec<ReportData>>,
) -> (Vec<Report>, Vec<(Option<ReportId>, ReportDescriptorError)>) {
let mut reports = Vec::new();
let mut bad_reports = Vec::new();
for (id, report_data) in report_records {
let mut fields = Vec::new();
let mut bit_position: u32 = 0;
for data in report_data {
let report_count: u32 = match data.global_state.report_count {
Some(count) => count.into(),
None => {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportNoCount));
break;
}
};
let report_size: u32 = match data.global_state.report_size {
Some(size) => size.into(),
None => {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportNoSize));
break;
}
};
if data.local_state.usages.is_empty() {
let padding_size = report_count * report_size;
let bits = bit_position..(bit_position + padding_size);
bit_position += padding_size;
fields.push(ReportField::Padding(PaddingField { bits }));
continue;
}
let logical_min = match data.global_state.logical_minimum {
Some(min) => min,
None => {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportNoLogicalMin));
break;
}
};
let logical_max = match data.global_state.logical_maximum {
Some(max) => max,
None => {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportNoLogicalMax));
break;
}
};
if i32::from(logical_min).is_negative() {
if i32::from(logical_min) >= i32::from(logical_max) {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportLogicalRange));
break;
}
} else if u32::from(logical_min) >= u32::from(logical_max) {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportLogicalRange));
break;
}
if data.attributes.variable {
let mut usage_iterator =
data.local_state.usages.iter().flat_map(|x| x.range()).map(Usage::from).peekable();
let mut designator_iterator = data
.local_state
.designators
.iter()
.flat_map(|x| x.range())
.map(DesignatorIndex::from)
.peekable();
let mut string_iterator =
data.local_state.strings.iter().flat_map(|x| x.range()).map(StringIndex::from).peekable();
let mut usage = match usage_iterator.next() {
Some(usage) => usage,
None => {
bad_reports.push((id.clone(), ReportDescriptorError::InvalidReportNoUsage));
break;
}
};
let mut designator = designator_iterator.next();
let mut string_index = string_iterator.next();
for _ in 0..report_count {
let bits = bit_position..(bit_position + report_size);
bit_position += report_size;
let field = VariableField {
attributes: data.attributes,
bits,
usage: Usage::from_page_and_id(data.global_state.usage_page, usage),
logical_minimum: logical_min,
logical_maximum: logical_max,
physical_minimum: data.global_state.physical_minimum,
physical_maximum: data.global_state.physical_maximum,
unit_exponent: data.global_state.unit_exponent,
unit: data.global_state.unit,
designator_index: designator,
string_index,
member_of: data.member_of.clone(),
};
fields.push(ReportField::Variable(field));
if usage_iterator.peek().is_some() {
usage = usage_iterator.next().unwrap();
}
if designator_iterator.peek().is_some() {
designator = designator_iterator.next();
}
if string_iterator.peek().is_some() {
string_index = string_iterator.next();
}
}
} else {
for _ in 0..report_count {
let bits = bit_position..(bit_position + report_size);
bit_position += report_size;
let usage_list = data
.local_state
.usages
.clone()
.iter()
.map(|usage_range| {
let start = Usage::from(usage_range.start());
let end = Usage::from(usage_range.end());
let start = Usage::from_page_and_id(data.global_state.usage_page, start);
let end = Usage::from_page_and_id(data.global_state.usage_page, end);
UsageRange::from(start.into()..=end.into())
})
.collect();
let field = ArrayField {
attributes: data.attributes,
bits,
usage_list,
logical_minimum: logical_min,
logical_maximum: logical_max,
designator_list: data.local_state.designators.clone(),
string_list: data.local_state.strings.clone(),
member_of: data.member_of.clone(),
};
fields.push(ReportField::Array(field));
}
}
}
reports.push(Report { report_id: *id, size_in_bits: bit_position as usize, fields });
}
(reports, bad_reports)
}
pub fn parse(report_descriptor: &[u8]) -> Result<ReportDescriptor, ReportDescriptorError> {
let item_tokenizer = DescriptorItemTokenizer::new(report_descriptor);
let mut parser = Self::new();
for item in item_tokenizer {
parser.parse_item(item)?;
}
let (input_reports, bad_input_reports) = parser.process_reports(&parser.input_reports);
let (output_reports, bad_output_reports) = parser.process_reports(&parser.output_reports);
let (features, bad_features) = parser.process_reports(&parser.features);
Ok(ReportDescriptor {
input_reports,
bad_input_reports,
output_reports,
bad_output_reports,
features,
bad_features,
})
}
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use crate::{
report_data_types::{
LogicalMaximum, LogicalMinimum, PhysicalMaximum, PhysicalMinimum, ReportAttributes, ReportId, Unit,
UnitExponent, Usage, UsagePage, UsageRange,
},
report_descriptor_parser::ReportDescriptorError,
ReportDescriptor, ReportField,
};
use super::ReportDescriptorParser;
static DIGITIZER_REPORT_DESCRIPTOR: &[u8] = &[
0x05, 0x0d, 0x09, 0x04, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x22, 0xa1, 0x02, 0x09, 0x42, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0x81, 0x02, 0x95, 0x07, 0x81, 0x03, 0x75, 0x08, 0x09, 0x51, 0x95, 0x01, 0x81, 0x02, 0x05, 0x01, 0x26, 0xff, 0x0f, 0x75, 0x10, 0x55, 0x0e, 0x65, 0x13, 0x09, 0x30, 0x35, 0x00, 0x46, 0xb5, 0x04, 0x95, 0x02, 0x81, 0x02, 0x46, 0x8a, 0x03, 0x09, 0x31, 0x81, 0x02, 0x05, 0x0d, 0x09, 0x48, 0x09, 0x49, 0x81, 0x02, 0x95, 0x01, 0x55, 0x0C, 0x65, 0x12, 0x35, 0x00, 0x47, 0x6f, 0xf5, 0x00, 0x00, 0x15, 0x00, 0x27, 0x6f, 0xf5, 0x00, 0x00, 0x09, 0x3f, 0x81, 0x02, 0xc0, 0x09, 0x22, 0xa1, 0x02, 0x09, 0x42, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0x81, 0x02, 0x95, 0x07, 0x81, 0x03, 0x75, 0x08, 0x09, 0x51, 0x95, 0x01, 0x81, 0x02, 0x05, 0x01, 0x26, 0xff, 0x0f, 0x75, 0x10, 0x55, 0x0e, 0x65, 0x13, 0x09, 0x30, 0x35, 0x00, 0x46, 0xb5, 0x04, 0x95, 0x02, 0x81, 0x02, 0x46, 0x8a, 0x03, 0x09, 0x31, 0x81, 0x02, 0x05, 0x0d, 0x09, 0x48, 0x09, 0x49, 0x81, 0x02, 0x95, 0x01, 0x55, 0x0C, 0x65, 0x12, 0x35, 0x00, 0x47, 0x6f, 0xf5, 0x00, 0x00, 0x15, 0x00, 0x27, 0x6f, 0xf5, 0x00, 0x00, 0x09, 0x3f, 0x81, 0x02, 0xc0, 0x05, 0x0d, 0x55, 0x0C, 0x66, 0x01, 0x10, 0x47, 0xff, 0xff, 0x00, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x09, 0x56, 0x81, 0x02, 0x09, 0x54, 0x25, 0x7f, 0x95, 0x01, 0x75, 0x08, 0x81, 0x02, 0x85, 0x02, 0x09, 0x55, 0x95, 0x01, 0x25, 0x02, 0xb1, 0x02, 0x85, 0x44, 0x06, 0x00, 0xff, 0x09, 0xC5, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x96, 0x00, 0x01, 0xb1, 0x02, 0xc0, ];
#[test]
fn test_digitizer_report_descriptor() {
let report_descriptor = ReportDescriptorParser::parse(DIGITIZER_REPORT_DESCRIPTOR).unwrap();
assert_eq!(report_descriptor.input_reports.len(), 1);
let input_report = &report_descriptor.input_reports[0];
assert_eq!(input_report.fields.len(), 22);
assert_eq!(input_report.size_in_bits, 280);
let ReportField::Variable(field) = &input_report.fields[0] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 0..1);
assert_eq!(field.usage, Usage::from(0x000d0042));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(1));
assert_eq!(field.physical_minimum, None);
assert_eq!(field.physical_maximum, None);
assert_eq!(field.unit, None);
assert_eq!(field.unit_exponent, None);
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
let ReportField::Padding(field) = &input_report.fields[1] else { panic!("Incorrect Field type") };
assert_eq!(field.bits, 1..8);
let ReportField::Variable(field) = &input_report.fields[2] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 8..16);
assert_eq!(field.usage, Usage::from(0x000d0051));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(1));
assert_eq!(field.physical_minimum, None);
assert_eq!(field.physical_maximum, None);
assert_eq!(field.unit, None);
assert_eq!(field.unit_exponent, None);
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
let x_y_reports = [
(&input_report.fields[3], Usage::from(0x00010030), 16..32, PhysicalMaximum::from(1205)), (&input_report.fields[4], Usage::from(0x00010030), 32..48, PhysicalMaximum::from(1205)), (&input_report.fields[5], Usage::from(0x00010031), 48..64, PhysicalMaximum::from(906)), (&input_report.fields[6], Usage::from(0x00010031), 64..80, PhysicalMaximum::from(906)), ];
for (field, usage, bits, phy_max) in x_y_reports {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(4095));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(phy_max));
assert_eq!(field.unit, Some(Unit::from(19)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(14)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
}
let width_height_reports = [
(&input_report.fields[7], Usage::from(0x000d0048), 80..96),
(&input_report.fields[8], Usage::from(0x000d0049), 96..112),
];
for (field, usage, bits) in width_height_reports {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(4095));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(906)));
assert_eq!(field.unit, Some(Unit::from(19)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(14)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
}
let ReportField::Variable(field) = &input_report.fields[9] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 112..128);
assert_eq!(field.usage, Usage::from(0x000d003f));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(62831));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(62831)));
assert_eq!(field.unit, Some(Unit::from(18)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
let ReportField::Variable(field) = &input_report.fields[10] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 128..129);
assert_eq!(field.usage, Usage::from(0x000d0042));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(1));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(62831)));
assert_eq!(field.unit, Some(Unit::from(18)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
let ReportField::Padding(field) = &input_report.fields[11] else { panic!("Incorrect Field type") };
assert_eq!(field.bits, 129..136);
let ReportField::Variable(field) = &input_report.fields[12] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 136..144);
assert_eq!(field.usage, Usage::from(0x000d0051));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(1));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(62831)));
assert_eq!(field.unit, Some(Unit::from(18)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
let x_y_reports = [
(&input_report.fields[13], Usage::from(0x00010030), 144..160, PhysicalMaximum::from(1205)), (&input_report.fields[14], Usage::from(0x00010030), 160..176, PhysicalMaximum::from(1205)), (&input_report.fields[15], Usage::from(0x00010031), 176..192, PhysicalMaximum::from(906)), (&input_report.fields[16], Usage::from(0x00010031), 192..208, PhysicalMaximum::from(906)), ];
for (field, usage, bits, phy_max) in x_y_reports {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(4095));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(phy_max));
assert_eq!(field.unit, Some(Unit::from(19)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(14)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
}
let width_height_reports = [
(&input_report.fields[17], Usage::from(0x000d0048), 208..224),
(&input_report.fields[18], Usage::from(0x000d0049), 224..240),
];
for (field, usage, bits) in width_height_reports {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(4095));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(906)));
assert_eq!(field.unit, Some(Unit::from(19)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(14)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
}
let ReportField::Variable(field) = &input_report.fields[19] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 240..256);
assert_eq!(field.usage, Usage::from(0x000d003f));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(62831));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(62831)));
assert_eq!(field.unit, Some(Unit::from(18)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 2);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(member_of[1].usage, Usage::from(0x000d0022));
let ReportField::Variable(field) = &input_report.fields[20] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 256..272);
assert_eq!(field.usage, Usage::from(0x000d0056));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(65535));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(65535)));
assert_eq!(field.unit, Some(Unit::from(4097)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 1);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
let ReportField::Variable(field) = &input_report.fields[21] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 272..280);
assert_eq!(field.usage, Usage::from(0x000d0054));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(127));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(65535)));
assert_eq!(field.unit, Some(Unit::from(4097)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 1);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
assert_eq!(report_descriptor.output_reports.len(), 0);
assert_eq!(report_descriptor.features.len(), 2);
let feature_report = &report_descriptor.features[0];
assert_eq!(feature_report.fields.len(), 1);
let ReportField::Variable(field) = &feature_report.fields[0] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 0..8);
assert_eq!(field.usage, Usage::from(0x000d0055));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(2));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(65535)));
assert_eq!(field.unit, Some(Unit::from(4097)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 1);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
let feature_report = &report_descriptor.features[1];
assert_eq!(feature_report.fields.len(), 256);
for (index, field) in feature_report.fields.iter().enumerate() {
let index = index as u32;
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, index * 8..(index + 1) * 8);
assert_eq!(field.usage, Usage::from(0xff0000C5));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(255));
assert_eq!(field.physical_minimum, Some(PhysicalMinimum::from(0)));
assert_eq!(field.physical_maximum, Some(PhysicalMaximum::from(65535)));
assert_eq!(field.unit, Some(Unit::from(4097)));
assert_eq!(field.unit_exponent, Some(UnitExponent::from(12)));
assert_eq!(field.designator_index, None);
assert_eq!(field.string_index, None);
let member_of = &field.member_of;
assert_eq!(member_of.len(), 1);
assert_eq!(member_of[0].usage, Usage::from(0x000d0004));
}
}
static CFU_REPORT_DESCRIPTOR: &[u8] = &[
0x06, 0x00, 0xFA, 0x09, 0xF5, 0xA1, 0x01, 0x15, 0x00, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0x85, 0x20, 0x75, 0x08, 0x95, 0x01, 0x09, 0x52, 0x81, 0x02, 0x85, 0x22, 0x75, 0x20, 0x95, 0x04, 0x19, 0x26, 0x29, 0x29, 0x81, 0x02, 0x85, 0x25, 0x75, 0x20, 0x95, 0x04, 0x19, 0x1A, 0x29, 0x1D, 0x81, 0x02, 0x85, 0x20, 0x75, 0x08, 0x95, 0x3C, 0x09, 0x31, 0x92, 0x02, 0x01, 0x85, 0x25, 0x75, 0x20, 0x95, 0x04, 0x19, 0x1E, 0x29, 0x21, 0x91, 0x02, 0x85, 0x20, 0x75, 0x08, 0x95, 0x3C, 0x09, 0x42, 0xB2, 0x02, 0x01, 0xC0, ];
#[test]
fn test_cfu_report_descriptor() {
let report_descriptor = ReportDescriptorParser::parse(CFU_REPORT_DESCRIPTOR).unwrap();
assert_eq!(report_descriptor.input_reports.len(), 3);
let report = &report_descriptor.input_reports[0];
assert_eq!(report.report_id, Some(ReportId::from(0x20)));
assert_eq!(report.fields.len(), 1);
assert_eq!(report.size_in_bits, 8);
let ReportField::Variable(field) = &report.fields[0] else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, 0..8);
assert_eq!(field.usage, Usage::from(0xFA000052));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(-1));
let report = &report_descriptor.input_reports[1];
assert_eq!(report.report_id, Some(ReportId::from(0x22)));
assert_eq!(report.fields.len(), 4);
assert_eq!(report.size_in_bits, 128);
let fields = [
(&report.fields[0], 0..32, Usage::from(0xFA000026)),
(&report.fields[1], 32..64, Usage::from(0xFA000027)),
(&report.fields[2], 64..96, Usage::from(0xFA000028)),
(&report.fields[3], 96..128, Usage::from(0xFA000029)),
];
for (field, bits, usage) in fields {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(-1));
}
let report = &report_descriptor.input_reports[2];
assert_eq!(report.report_id, Some(ReportId::from(0x25)));
assert_eq!(report.fields.len(), 4);
assert_eq!(report.size_in_bits, 128);
let fields = [
(&report.fields[0], 0..32, Usage::from(0xFA00001A)),
(&report.fields[1], 32..64, Usage::from(0xFA00001B)),
(&report.fields[2], 64..96, Usage::from(0xFA00001C)),
(&report.fields[3], 96..128, Usage::from(0xFA00001D)),
];
for (field, bits, usage) in fields {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(-1));
}
assert_eq!(report_descriptor.output_reports.len(), 2);
let report = &report_descriptor.output_reports[0];
assert_eq!(report.report_id, Some(ReportId::from(0x20)));
assert_eq!(report.fields.len(), 60);
assert_eq!(report.size_in_bits, 480);
for (index, field) in report.fields.iter().enumerate() {
let index = index as u32;
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(
field.attributes,
ReportAttributes { variable: true, buffered_bytes: true, ..Default::default() }
);
assert_eq!(field.bits, index * 8..(index + 1) * 8);
assert_eq!(field.usage, Usage::from(0xFA000031));
}
let report = &report_descriptor.output_reports[1];
assert_eq!(report.report_id, Some(ReportId::from(0x25)));
assert_eq!(report.fields.len(), 4);
assert_eq!(report.size_in_bits, 128);
let fields = [
(&report.fields[0], 0..32, Usage::from(0xFA00001E)),
(&report.fields[1], 32..64, Usage::from(0xFA00001F)),
(&report.fields[2], 64..96, Usage::from(0xFA000020)),
(&report.fields[3], 96..128, Usage::from(0xFA000021)),
];
for (field, bits, usage) in fields {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bits);
assert_eq!(field.usage, usage);
}
assert_eq!(report_descriptor.features.len(), 1);
let report = &report_descriptor.features[0];
assert_eq!(report.report_id, Some(ReportId::from(0x20)));
assert_eq!(report.fields.len(), 60);
assert_eq!(report.size_in_bits, 480);
for (index, field) in report.fields.iter().enumerate() {
let index = index as u32;
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(
field.attributes,
ReportAttributes { variable: true, buffered_bytes: true, ..Default::default() }
);
assert_eq!(field.bits, index * 8..(index + 1) * 8);
assert_eq!(field.usage, Usage::from(0xFA000042));
}
}
static BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x02, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 00, 0x05, 0x07, 0x19, 0x00, 0x2a, 0xff, 00, 0x81, 0x00, 0xc0, ];
#[test]
fn test_keyboard_report_descriptor() {
let report_descriptor = ReportDescriptorParser::parse(BOOT_KEYBOARD_REPORT_DESCRIPTOR).unwrap();
assert_eq!(report_descriptor.input_reports.len(), 1);
let report = &report_descriptor.input_reports[0];
assert_eq!(report.report_id, None);
assert_eq!(report.fields.len(), 15);
assert_eq!(report.size_in_bits, 64);
let mut bit: u32 = 0;
for (field, usage) in report.fields[0..8].iter().zip(0xe0..0xe7) {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bit..bit + 1);
assert_eq!(field.usage, Usage::from_page_and_id(Some(UsagePage::from(0x07)), Usage::from(usage)));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(1));
bit += 1;
}
let ReportField::Padding(field) = &report.fields[8] else { panic!("Incorrect Field type") };
assert_eq!(field.bits, 8..16);
bit = 16;
for field in &report.fields[9..15] {
let ReportField::Array(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { ..Default::default() });
assert_eq!(field.bits, bit..bit + 8);
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(255));
assert_eq!(field.usage_list, Vec::from([UsageRange::from(0x00070000..=0x000700ff)]));
bit += 8;
}
assert_eq!(report_descriptor.output_reports.len(), 1);
let report = &report_descriptor.output_reports[0];
assert_eq!(report.report_id, None);
assert_eq!(report.fields.len(), 6);
assert_eq!(report.size_in_bits, 8);
bit = 0;
for (field, usage) in report.fields[0..5].iter().zip(0x01..0x05) {
let ReportField::Variable(field) = field else { panic!("Incorrect Field type") };
assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() });
assert_eq!(field.bits, bit..bit + 1);
assert_eq!(field.usage, Usage::from_page_and_id(Some(UsagePage::from(0x08)), Usage::from(usage)));
assert_eq!(field.logical_minimum, LogicalMinimum::from(0));
assert_eq!(field.logical_maximum, LogicalMaximum::from(1));
bit += 1;
}
}
static MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_MAIN_ITEM: &[u8] = &[
0xf0, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_GLOBAL_ITEM: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0xf5, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_LOCAL_ITEM: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0xf9, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_RESERVED_ITEM: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0xff, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_POP: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0xb4, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_DELIMITER: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0xA8, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_REPORT_SIZE: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_REPORT_COUNT: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_LOG_MIN: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x25, 0x01, 0x81, 0x02, 0xc0, ];
static BOGUS_MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_LOG_MAX: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x81, 0x02, 0xc0, ];
static MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_LOG_RANGE: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x01, 0x25, 0x00, 0x81, 0x02, 0xc0, ];
static MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_LOG_RANGE2: &[u8] = &[
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0xff, 0x25, 0xfe, 0x81, 0x02, 0xc0, ];
#[test]
fn test_bogus_descriptors_should_not_parse() {
let _ = ReportDescriptorParser::parse(MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR).unwrap();
assert_eq!(
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_MAIN_ITEM).err(),
Some(ReportDescriptorError::InvalidMainItem)
);
assert_eq!(
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_GLOBAL_ITEM).err(),
Some(ReportDescriptorError::InvalidGlobalItem)
);
assert_eq!(
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_LOCAL_ITEM).err(),
Some(ReportDescriptorError::InvalidLocalItem)
);
assert_eq!(
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_RESERVED_ITEM).err(),
Some(ReportDescriptorError::ReservedItemNotSupported)
);
assert_eq!(
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_POP).err(),
Some(ReportDescriptorError::InvalidPop,)
);
assert_eq!(
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_DELIMITER).err(),
Some(ReportDescriptorError::DelimiterNotSupported,)
);
let ReportDescriptor { mut bad_input_reports, .. } =
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_REPORT_SIZE).unwrap();
let (report_id, error) = bad_input_reports.pop().unwrap();
assert_eq!(None, report_id);
assert_eq!(ReportDescriptorError::InvalidReportNoSize, error);
let ReportDescriptor { mut bad_input_reports, .. } =
ReportDescriptorParser::parse(BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_REPORT_COUNT).unwrap();
let (report_id, error) = bad_input_reports.pop().unwrap();
assert_eq!(None, report_id);
assert_eq!(ReportDescriptorError::InvalidReportNoCount, error);
let ReportDescriptor { mut bad_input_reports, .. } =
ReportDescriptorParser::parse(BOGUS_MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_LOG_MIN).unwrap();
let (report_id, error) = bad_input_reports.pop().unwrap();
assert_eq!(None, report_id);
assert_eq!(ReportDescriptorError::InvalidReportNoLogicalMin, error);
let ReportDescriptor { mut bad_input_reports, .. } =
ReportDescriptorParser::parse(BOGUS_MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_LOG_MAX).unwrap();
let (report_id, error) = bad_input_reports.pop().unwrap();
assert_eq!(None, report_id);
assert_eq!(ReportDescriptorError::InvalidReportNoLogicalMax, error);
let ReportDescriptor { mut bad_input_reports, .. } =
ReportDescriptorParser::parse(MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_LOG_RANGE).unwrap();
let (report_id, error) = bad_input_reports.pop().unwrap();
assert_eq!(None, report_id);
assert_eq!(ReportDescriptorError::InvalidReportLogicalRange, error);
let ReportDescriptor { mut bad_input_reports, .. } =
ReportDescriptorParser::parse(MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_LOG_RANGE2).unwrap();
let (report_id, error) = bad_input_reports.pop().unwrap();
assert_eq!(None, report_id);
assert_eq!(ReportDescriptorError::InvalidReportLogicalRange, error);
}
#[test]
fn report_descriptors_parsed_from_same_buffer_should_be_equal() {
assert_eq!(
ReportDescriptorParser::parse(MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR),
ReportDescriptorParser::parse(MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR)
);
}
}