byteserde/utils/
hex.rs

1fn is_printable(c: u8) -> bool {
2    (c > 0x21 && c < 0x7e) || (c > 0xa0)
3}
4fn map_2_printable(c: u8) -> char {
5    if is_printable(c) {
6        char::from(c)
7    } else {
8        '.'
9    }
10}
11pub fn to_hex_line(bytes: &[u8]) -> String {
12    // todo make pretty inline
13    to_hex_pretty(bytes).replace('\n', " ").replace("   ", "")
14}
15pub fn to_hex_pretty(bytes: &[u8]) -> String {
16    struct HexAscii {
17        hex: String,
18        asc: String,
19    }
20    let hex: Vec<HexAscii> = bytes
21        .iter()
22        .map(|v| HexAscii {
23            hex: format!("{:02x}", v),
24            asc: format!("{}", map_2_printable(*v)),
25        })
26        .collect();
27    let mut result = String::new();
28
29    for (idx, chunk16) in hex.chunks(16).enumerate() {
30        let mut hex_view = String::new();
31        let mut asc_view = String::new();
32        for chunk4 in chunk16.chunks(4) {
33            for ha in chunk4 {
34                hex_view.push_str(&format!("{} ", ha.hex));
35                asc_view.push_str(&format!("{} ", ha.asc));
36            }
37            hex_view.push(' ');
38            asc_view.push(' ');
39        }
40        let asc_view = asc_view.trim_end();
41        result.push_str(&format!("{idx:<04}: {hex_view:<52}| {asc_view}\n"));
42    }
43    result
44}
45
46#[cfg(test)]
47mod tests {
48
49    use super::*;
50    use crate::unittest;
51    use text_diff::{diff, print_diff};
52
53    #[test]
54    fn hex() {
55        unittest::setup::log::configure();
56        let mut v: Vec<u8> = Vec::new();
57        for i in 0..=255 {
58            v.push(i);
59        }
60        for i in 0..10 {
61            v.push(i);
62        }
63
64        let expected = r#"0000: 00 01 02 03  04 05 06 07  08 09 0a 0b  0c 0d 0e 0f  | . . . .  . . . .  . . . .  . . . .
650001: 10 11 12 13  14 15 16 17  18 19 1a 1b  1c 1d 1e 1f  | . . . .  . . . .  . . . .  . . . .
660002: 20 21 22 23  24 25 26 27  28 29 2a 2b  2c 2d 2e 2f  | . . " #  $ % & '  ( ) * +  , - . /
670003: 30 31 32 33  34 35 36 37  38 39 3a 3b  3c 3d 3e 3f  | 0 1 2 3  4 5 6 7  8 9 : ;  < = > ?
680004: 40 41 42 43  44 45 46 47  48 49 4a 4b  4c 4d 4e 4f  | @ A B C  D E F G  H I J K  L M N O
690005: 50 51 52 53  54 55 56 57  58 59 5a 5b  5c 5d 5e 5f  | P Q R S  T U V W  X Y Z [  \ ] ^ _
700006: 60 61 62 63  64 65 66 67  68 69 6a 6b  6c 6d 6e 6f  | ` a b c  d e f g  h i j k  l m n o
710007: 70 71 72 73  74 75 76 77  78 79 7a 7b  7c 7d 7e 7f  | p q r s  t u v w  x y z {  | } . .
720008: 80 81 82 83  84 85 86 87  88 89 8a 8b  8c 8d 8e 8f  | . . . .  . . . .  . . . .  . . . .
730009: 90 91 92 93  94 95 96 97  98 99 9a 9b  9c 9d 9e 9f  | . . . .  . . . .  . . . .  . . . .
740010: a0 a1 a2 a3  a4 a5 a6 a7  a8 a9 aa ab  ac ad ae af  | . ¡ ¢ £  ¤ ¥ ¦ §  ¨ © ª «  ¬ ­ ® ¯
750011: b0 b1 b2 b3  b4 b5 b6 b7  b8 b9 ba bb  bc bd be bf  | ° ± ² ³  ´ µ ¶ ·  ¸ ¹ º »  ¼ ½ ¾ ¿
760012: c0 c1 c2 c3  c4 c5 c6 c7  c8 c9 ca cb  cc cd ce cf  | À Á Â Ã  Ä Å Æ Ç  È É Ê Ë  Ì Í Î Ï
770013: d0 d1 d2 d3  d4 d5 d6 d7  d8 d9 da db  dc dd de df  | Ð Ñ Ò Ó  Ô Õ Ö ×  Ø Ù Ú Û  Ü Ý Þ ß
780014: e0 e1 e2 e3  e4 e5 e6 e7  e8 e9 ea eb  ec ed ee ef  | à á â ã  ä å æ ç  è é ê ë  ì í î ï
790015: f0 f1 f2 f3  f4 f5 f6 f7  f8 f9 fa fb  fc fd fe ff  | ð ñ ò ó  ô õ ö ÷  ø ù ú û  ü ý þ ÿ
800016: 00 01 02 03  04 05 06 07  08 09                     | . . . .  . . . .  . ."#;
81        let actual = to_hex_pretty(&v);
82        let diff_res = diff(expected, actual.as_str(), "\n");
83        print_diff(expected, actual.as_str(), "\n");
84        assert_eq!(diff_res.0, 1);
85    }
86
87    #[test]
88    fn hex_line() {
89        unittest::setup::log::configure();
90        let mut v: Vec<u8> = Vec::new();
91        for i in 0..=18 {
92            v.push(i);
93        }
94        let expected = "0000: 00 01 02 03  04 05 06 07  08 09 0a 0b  0c 0d 0e 0f  | . . . .  . . . .  . . . .  . . . . 0001: 10 11 12  | . . . ";
95        let actual = to_hex_line(&v);
96        let diff_res = diff(expected, actual.as_str(), "\n");
97        print_diff(expected, actual.as_str(), "\n");
98        assert_eq!(diff_res.0, 0);
99    }
100}