#![warn(clippy::print_stderr, clippy::print_stdout, clippy::dbg_macro)]
#![warn(clippy::todo)]
#![warn(missing_docs)]
use std::io::Write;
use hid_types::item::Item;
use crate::item::{DecoderContext, decode_one};
pub use crate::item::LengthError;
pub mod item;
pub struct ItemDecoder<'a> {
iter: std::iter::Copied<std::slice::Iter<'a, u8>>,
context: DecoderContext,
}
impl<'a> ItemDecoder<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
let iter = bytes.iter().copied();
Self {
iter,
context: Default::default(),
}
}
}
impl<'a> Iterator for ItemDecoder<'a> {
type Item = Result<Item, LengthError>;
fn next(&mut self) -> Option<Self::Item> {
decode_one(&mut self.iter, &mut self.context)
.map(|item_maybe| item_maybe.map(|item| item.item))
}
}
pub fn decode_items(bytes: &[u8]) -> Result<Vec<Item>, LengthError> {
ItemDecoder::new(bytes).collect()
}
pub fn decode<W>(writer: W, bytes: &[u8]) -> std::io::Result<()>
where
W: Write,
{
TextDecoder::new(writer).decode(bytes)
}
#[derive(Default, Debug, Clone)]
struct OutputOptions {
pub display_tag_type: bool,
pub display_raw_bytes: bool,
}
#[derive(Clone)]
pub struct TextDecoder<W> {
writer: W,
output_options: OutputOptions,
context: DecoderContext,
}
impl<W> TextDecoder<W>
where
W: Write,
{
pub fn new(writer: W) -> Self {
Self {
writer,
output_options: Default::default(),
context: Default::default(),
}
}
pub fn display_tag_type(mut self) -> Self {
self.output_options.display_tag_type = true;
self
}
pub fn display_raw_bytes(mut self) -> Self {
self.output_options.display_raw_bytes = true;
self
}
pub fn decode(mut self, bytes: &[u8]) -> std::io::Result<()> {
let mut iter = bytes.iter().copied();
loop {
match decode_one(&mut iter, &mut self.context) {
None => break,
Some(Ok(item)) => {
if self.output_options.display_raw_bytes {
let mut hex = String::new();
for byte in item.bytes {
use std::fmt::Write;
write!(hex, "{byte:02x} ").unwrap();
}
write!(self.writer, "{hex:9} ")?;
}
if self.output_options.display_tag_type {
write!(self.writer, "{:9}", item.item.type_note())?;
}
writeln!(self.writer, "{}", item.item)?;
}
Some(Err(_e)) => return Err(std::io::Error::other("decoding failed")),
}
}
Ok(())
}
}