monitoring kit
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
#![feature(let_chains, iter_array_chunks, array_chunks, portable_simd, iter_chain)]
use anyhow::Result;
use std::collections::VecDeque;
use std::io::Write;
use std::iter::zip;
use std::simd::prelude::*;
use termion::color::*;
use termion::{clear, cursor};

pub struct Grapher {
    pub buffer: Vec<u8>,
    pub data: VecDeque<f64>,
}
impl Grapher {
    pub fn new() -> Result<Self> {
        Ok(Self {
            buffer: Vec::with_capacity(1 << 20),
            data: VecDeque::from(vec![0.0; termion::terminal_size()?.1 as usize * 2]),
        })
    }
    pub fn push_point(&mut self, x: f64) {
        self.data.push_front(x);
        self.data.pop_back();
    }

    pub fn draw(&mut self, mut color: impl FnMut(u16) -> Option<[u8; 3]>) -> Result<&mut Vec<u8>> {
        let Grapher {
            buffer: output,
            data,
        } = self;
        output.clear();
        let (w, h) = termion::terminal_size()?;
        if w * 2 < data.len() as u16 {
            for _ in 0..data.len() as u16 - w * 2 {
                data.pop_back();
            }
        }
        if w * 2 > data.len() as u16 {
            for _ in 0..w * 2 - data.len() as u16 {
                data.push_back(0.0);
            }
        }
        assert_eq!(data.len(), (w * 2) as usize);

        let string = data
            .iter()
            .rev()
            .array_chunks::<2>()
            .map(|column| {
                let mut data = [vec![false; (h * 4) as usize], vec![false; (h * 4) as usize]];
                for (e, c) in zip(column, &mut data) {
                    let clen = c.len();
                    c[clen - ((h as f64 * e * 4.0).round().min(h as f64 * 4.0) as usize)..]
                        .fill(true);
                }
                let a = zip(data[0].array_chunks::<4>(), data[1].array_chunks::<4>())
                    .map(|(a, b)| braille([*a, *b]))
                    .collect::<Vec<u8>>();
                assert_eq!(a.len(), h as usize);
                a
            })
            .collect::<Vec<_>>();
        assert_eq!(string.len(), w as usize);
        write!(output, "\x1B[?7h{}{}", clear::All, cursor::Goto(1, 1))?;
        for y in 0..h as usize {
            if let Some([r, g, b]) = color(y as u16) {
                write!(output, "{}", Rgb(r, g, b).fg_string())?;
            }

            for x in 0..w as usize {
                output.extend(bl(string[x][y]));
            }
            if y as u16 != h - 1 {
                output.extend(b"\r\n");
            }
        }
        Ok(output)
    }
}

fn braille(dots: [[bool; 4]; 2]) -> u8 {
    let x = unsafe { dots.as_ptr().cast::<u8x8>().read_unaligned() };
    let x = simd_swizzle!(x, [0, 1, 2, /* */ 4, 5, 6, /* */ 3, 7]);
    x.simd_eq(Simd::splat(1)).to_bitmask() as u8
}

fn bl(x: u8) -> [u8; 3] {
    let mut b = [0; 3];
    char::from_u32(0x2800 + x as u32)
        .unwrap()
        .encode_utf8(&mut b);
    b
}