const HEADERS: [&[u8]; 3] = [b"asd", b"adf", b"ads"]; const HOME_RIGHT: [u8; 4] = [b'a',b's',b'd',b'f']; const HOME_LEFT: [u8; 4] = [b'h',b'j',b'k',b'l']; const ABOVE_RIGHT: [u8; 4] = [b'w',b'e',b'r',b't']; const ABOVE_LEFT: [u8; 4] = [b'u',b'i',b'o',b'p']; pub fn encode(buf: &[u8]) -> Vec { let mut out = Vec::new(); let h = HEADERS[fastrand::usize(..HEADERS.len())]; for s in h { out.push(*s); } for byte in buf { let stuff = encode_byte(*byte); for b in stuff { out.push(b); } } out } fn encode_byte(byte: u8) -> [u8; 4] { [some_dict()[((byte & 0b11000000) >> 6) as usize], some_dict()[((byte & 0b00110000) >> 4) as usize], some_dict()[((byte & 0b00001100) >> 2) as usize], some_dict()[(byte & 0b00000011) as usize] ] } fn some_dict() -> &'static [u8; 4] { let q = fastrand::usize(0..10); if q < 4 { return &HOME_RIGHT } if q < 8 { return &HOME_LEFT } if q < 9 { return &ABOVE_RIGHT } return &ABOVE_LEFT } pub fn decode(buf: &[u8]) -> Vec { let buf = &buf[3..]; let mut out = Vec::new(); for pair in buf.chunks(4) { if pair.len() != 4 { continue; } match (decode_sym(pair[0]), decode_sym(pair[1]), decode_sym(pair[2]), decode_sym(pair[3])) { (Some(zero), Some(one), Some(two), Some(three)) => out.push((zero << 6) + (one << 4) + (two << 2) + three), (_, _, _, _) => { // U+FFFD � REPLACEMENT CHARACTER out.push(0xFF); out.push(0xFD); } } } out } pub fn decode_sym(sym: u8) -> Option { let find = |d: &[u8; 4]| -> Option { d.iter().enumerate().find(|s| s.1 == &sym).map(|s| s.0 as u8) }; find(&HOME_RIGHT) .or_else(|| find(&HOME_LEFT)) .or_else(|| find(&ABOVE_RIGHT)) .or_else(|| find(&ABOVE_LEFT)) } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let hello = b"hello, world!"; assert_eq!(&hello[..], &decode(&encode(hello))); } #[test] fn random() { for _ in 0..1000 { let mut buf = vec![0; fastrand::usize(..1000)]; buf.iter_mut().for_each(|s| *s = fastrand::u8(..)); assert_eq!(&buf[..], &decode(&encode(&buf))); } } }