use thiserror::Error;
pub fn render(data: &[u8]) -> String {
let mut grid = [[0u8; 17]; 9];
let mut bishop: [usize; 2] = [8, 4];
grid[bishop[1]][bishop[0]] = 15;
for byte in data {
for i in 0..4 {
let bit_pair = (byte >> i & 1, byte >> (i + 1) & 1);
let mut moved = false;
match bit_pair {
(0, 0) => {
if !(bishop[0] == 0 || bishop[1] == 0) {
bishop[0] -= 1;
bishop[1] -= 1;
moved = true;
}
}
(0, 1) => {
if !(bishop[0] == 16 || bishop[1] == 0) {
bishop[0] += 1;
bishop[1] -= 1;
moved = true;
}
}
(1, 0) => {
if !(bishop[0] == 0 || bishop[1] == 8) {
bishop[0] -= 1;
bishop[1] += 1;
moved = true;
}
}
(1, 1) => {
if !(bishop[0] == 16 || bishop[1] == 8) {
bishop[0] += 1;
bishop[1] += 1;
moved = true;
}
}
_ => {} };
if moved {
grid[bishop[1]][bishop[0]] += 1;
}
if grid[bishop[1]][bishop[0]] > 14 {
grid[bishop[1]][bishop[0]] = 0;
}
}
}
grid[bishop[1]][bishop[0]] = 16;
let mut out = String::new();
for row in grid {
for value in row {
out.push(match value {
0 => ' ',
1 => '.',
2 => 'o',
3 => '+',
4 => '=',
5 => '*',
6 => 'B',
7 => 'O',
8 => 'X',
9 => '@',
10 => '%',
11 => '&',
12 => '#',
13 => '/',
14 => '^',
15 => 'S',
16 => 'E',
_ => '!',
});
}
out.push('\n');
}
out.strip_suffix('\n').unwrap_or(&out).to_owned()
}
#[derive(Error, Debug)]
pub enum RenderError {
#[error("Hex string could not be parsed")]
HexParsingError,
}
#[cfg(feature="hexparse")]
pub fn render_from_hex(data: &str) -> Result<String, RenderError> {
if let Ok(bytes) = hex::decode(data) {
Ok(render(bytes.as_slice()))
}
else {
Err(RenderError::HexParsingError)
}
}
#[cfg(feature="hash")]
pub fn render_s256(data: &str) -> String {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(data);
let bytes = hasher.finalize();
render(&bytes[..])
}
#[cfg(test)]
mod tests {
use super::*;
static BACK_AND_FORTH_OUT: &'static str = " . \n o \n o \n o \n E \n \n \n \n ";
#[test]
fn back_and_forth() {
assert_eq!(BACK_AND_FORTH_OUT, render(&[0, 255]));
}
#[test]
fn hello_world() {
assert_eq!(" o \n o o . \n . + + \n o = . \n = = S \n . * + \n E \n . o \n o ", render(&[72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 46]));
}
#[test]
#[cfg(feature="hexparse")]
fn hexparse() {
assert_eq!(BACK_AND_FORTH_OUT, render_from_hex("00ff").unwrap());
}
#[test]
#[cfg(feature="hexparse")]
#[should_panic(expected="should crash")]
fn hexparse_err() {
render_from_hex("zzzz").expect("should crash");
}
#[test]
#[cfg(feature="hash")]
fn hash() {
assert_eq!(" o o o \n . E + o \n . o o = \n . o = O o \n . = @ * \n + + % \n * + = =\n . + X * \n O ", render_s256("0 -> localhost"));
}
}