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
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//!
//! # Hex Dump API
//!
//! Converts a vector of bytst to hex dump string format
//!

/// Takes a u8 array of bytes and converts to hex dump
#[allow(clippy::needless_range_loop)]
pub fn bytes_to_hex_dump(record: &[u8]) -> String {
    let cols = 16;
    let record_cnt = record.len();
    let mut result = String::new();
    let mut collector = String::new();

    for row_idx in 0..record_cnt {
        // colunn index
        if row_idx % cols == 0 {
            result.push_str(&format!("{:08x}", row_idx));
        }

        // spacing half way
        if row_idx % (cols / 2) == 0 {
            result.push(' ');
        }

        // convert and add character to collector
        collector.push_str(&byte_to_string(&record[row_idx]));

        // push binary
        result.push_str(&format!(" {:02x}", record[row_idx]));

        // push characters
        if (row_idx + 1) % cols == 0 {
            result.push_str(&format!("  |{}|\n", collector));
            collector = String::new();
        }
    }

    // if collect not empty, fill-in gap and add characters
    if !collector.is_empty() {
        let last_char_idx = record_cnt % cols;
        if last_char_idx <= cols / 2 {
            result.push_str(&" ".to_owned());
        }
        for _ in last_char_idx..cols {
            collector.push_str(&" ".to_owned());
            result.push_str(&"   ".to_owned());
        }

        result.push_str(&format!("  |{}|\n", collector));
    }

    result
}

/// Converts a byte to string character
fn byte_to_string(byte: &u8) -> String {
    if 0x20 <= *byte && *byte < 0x7f {
        format!("{}", *byte as char)
    } else if *byte == 0xa {
        ".".to_owned()
    } else {
        " ".to_owned()
    }
}

/// Return separator for hex dump
pub fn hex_dump_separator() -> String {
    "------------------------------------------------------------------------------\n".to_owned()
}

#[cfg(test)]
mod test {
    use super::bytes_to_hex_dump;

    #[test]
    fn test_bytes_to_hex_dump() {
        let records: Vec<u8> = vec![
            123, 10, 32, 32, 32, 32, 34, 112, 97, 114, 116, 105, 116, 105, 111, 110, 115, 34, 58,
            32, 91, 10, 32, 32, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
            32, 32, 32, 32, 34, 105, 100, 34, 58, 32, 48, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32,
            32, 32, 32, 32, 34, 114, 101, 112, 108, 105, 99, 97, 115, 34, 58, 32, 91, 10, 32, 32,
            32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 53, 48, 48, 49, 44, 10, 32, 32,
            32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 53, 48, 48, 50, 44, 10, 32, 32,
            32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 53, 48, 48, 51, 10, 32, 32, 32,
            32, 32, 32, 32, 32, 32, 32, 32, 32, 93, 10, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10,
            32, 32, 32, 32, 93, 10, 125,
        ];

        let expected = r#"00000000  7b 0a 20 20 20 20 22 70  61 72 74 69 74 69 6f 6e  |{.    "partition|
00000010  73 22 3a 20 5b 0a 20 20  20 20 20 20 20 20 7b 0a  |s": [.        {.|
00000020  20 20 20 20 20 20 20 20  20 20 20 20 22 69 64 22  |            "id"|
00000030  3a 20 30 2c 0a 20 20 20  20 20 20 20 20 20 20 20  |: 0,.           |
00000040  20 22 72 65 70 6c 69 63  61 73 22 3a 20 5b 0a 20  | "replicas": [. |
00000050  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 35  |               5|
00000060  30 30 31 2c 0a 20 20 20  20 20 20 20 20 20 20 20  |001,.           |
00000070  20 20 20 20 20 35 30 30  32 2c 0a 20 20 20 20 20  |     5002,.     |
00000080  20 20 20 20 20 20 20 20  20 20 20 35 30 30 33 0a  |           5003.|
00000090  20 20 20 20 20 20 20 20  20 20 20 20 5d 0a 20 20  |            ].  |
000000a0  20 20 20 20 20 20 7d 0a  20 20 20 20 5d 0a 7d     |      }.    ].} |
"#;

        let result = bytes_to_hex_dump(&records);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_bytes_to_hex_dump_half_row() {
        let records: Vec<u8> = vec![123, 10, 32, 32, 32, 32, 34, 112];

        let expected = r#"00000000  7b 0a 20 20 20 20 22 70                           |{.    "p        |
"#;

        let result = bytes_to_hex_dump(&records);
        assert_eq!(result, expected);
    }
}