visual_hashing/
randomart.rs1const WIDTH: usize = 17;
12const HEIGHT: usize = 9;
13
14const VALUES: &[u8] = b" .o+=*BOX@%&#/^";
17
18pub fn randomart(data: &[u8], label: &str) -> String {
23 let start_x = WIDTH / 2;
24 let start_y = HEIGHT / 2;
25 let mut grid = [[0u32; WIDTH]; HEIGHT];
26 let (mut x, mut y) = (start_x, start_y);
27
28 for &byte in data {
29 for shift in [0u32, 2, 4, 6] {
30 match (byte >> shift) & 0x3 {
31 0 => {
32 y = y.saturating_sub(1);
33 x = x.saturating_sub(1);
34 }
35 1 => {
36 y = y.saturating_sub(1);
37 x = (x + 1).min(WIDTH - 1);
38 }
39 2 => {
40 y = (y + 1).min(HEIGHT - 1);
41 x = x.saturating_sub(1);
42 }
43 _ => {
44 y = (y + 1).min(HEIGHT - 1);
45 x = (x + 1).min(WIDTH - 1);
46 }
47 }
48 grid[y][x] += 1;
49 }
50 }
51
52 let (end_x, end_y) = (x, y);
53 grid[start_y][start_x] = 0;
54 grid[end_y][end_x] = (VALUES.len() - 1) as u32;
55
56 let mut lines: Vec<String> = Vec::with_capacity(HEIGHT + 2);
57 lines.push(if label.is_empty() {
58 "+----------------+".to_string()
59 } else {
60 format!("+--[{label:<14}]+")
62 });
63
64 for (row_idx, row) in grid.iter().enumerate() {
65 let mut line = String::with_capacity(WIDTH + 2);
66 line.push('|');
67 for (col_idx, &count) in row.iter().enumerate() {
68 if row_idx == start_y && col_idx == start_x {
69 line.push('S');
70 } else if row_idx == end_y && col_idx == end_x {
71 line.push('E');
72 } else {
73 line.push(VALUES[(count as usize).min(VALUES.len() - 1)] as char);
74 }
75 }
76 line.push('|');
77 lines.push(line);
78 }
79
80 lines.push("+----------------+".to_string());
81 lines.join("\n")
82}