1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#![forbid(unsafe_code)]
#![cfg_attr(all(test, feature = "bench"), feature(test))]
#![cfg_attr(feature = "strict", deny(warnings))]
#![cfg_attr(not(any(test, feature = "std")), no_std)]
// #![warn(missing_docs)]

pub mod table;

extern crate alloc;

use core::fmt::{self, Display, Formatter, Write};

#[cfg(feature = "std")]
use std::io;

use crate::table::{Table, DEFAULT};

pub struct Dumper {
    pub address: usize,
    pub buffer: [u8; 16],
    pub len: usize,
    table: &'static Table,
    use_rich: bool,
}

impl Dumper {
    pub fn new(table: &'static Table, use_rich: bool) -> Self {
        Self {
            address: 0,
            buffer: [0; 16],
            len: 0,
            table,
            use_rich,
        }
    }
}

#[cfg(feature = "std")]
impl Dumper {
    pub fn read(&mut self, source: &mut impl io::Read) -> io::Result<usize> {
        self.address += self.len;
        self.len = 0;

        while self.len < self.buffer.len() {
            self.len += match source.read(&mut self.buffer[self.len..])? {
                0 => return Ok(self.len),
                x => x,
            };
        }

        Ok(self.len)
    }
}

impl Default for Dumper {
    fn default() -> Self {
        Self::new(&DEFAULT, true)
    }
}

impl Display for Dumper {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut offset = 0;
        let mut column = 0;

        while offset < self.len {
            write!(f, "{:02X} ", self.buffer[offset])?;
            offset += 1;
            column += 3;

            if offset % 4 == 0 {
                f.write_char(' ')?;
                column += 1;
            }
        }

        // <ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  >
        f.write_str(&"                                                    "[column..])?;

        if self.use_rich {
            for &byte in &self.buffer[..self.len] {
                Display::fmt(&self.table.inner[usize::from(byte)], f)?;
            }
        } else {
            for &byte in &self.buffer[..self.len] {
                Display::fmt(&self.table.inner[usize::from(byte)].scalar, f)?;
            }
        }

        // <0123456789abcdef  >
        f.write_str(&"                  "[self.len..])?;

        write!(f, "{:X}\n", self.address)?;

        Ok(())
    }
}