use crate::{input, Cipher, CipherResult, TABULA_RECTA};
pub struct Autokey {
key: String,
}
impl Autokey {
pub fn new(key: &str) -> Self {
input::is_alpha(key).expect("`key` must be alphabetic");
Self {
key: key.to_ascii_uppercase(),
}
}
}
impl Cipher for Autokey {
fn encipher(&self, ptext: &str) -> CipherResult {
input::is_alpha(ptext)?;
let ptext = ptext.to_ascii_uppercase();
let key = self.key.as_bytes();
let ptext: Vec<u8> = ptext.bytes().collect();
let ctext: Vec<u8> = ptext
.iter()
.enumerate()
.map(|(i, c)| {
let y = match i {
i if i < key.len() => key[i] as usize - 65,
_ => ptext[i - key.len()] as usize - 65,
};
TABULA_RECTA[y][*c as usize - 65]
})
.collect();
Ok(String::from_utf8(ctext).unwrap())
}
fn decipher(&self, ctext: &str) -> CipherResult {
input::is_alpha(ctext)?;
let ctext = ctext.to_ascii_uppercase();
let key = self.key.as_bytes();
let ctext: Vec<u8> = ctext.bytes().collect();
let mut ptext: Vec<u8> = Vec::with_capacity(ctext.len());
for (i, c) in ctext.iter().enumerate() {
let y = match i {
i if i < key.len() => key[i] as usize - 65,
_ => ptext[i - key.len()] as usize - 65,
};
ptext.push(TABULA_RECTA[y].iter().position(|&j| j == *c).unwrap() as u8 + 65);
}
Ok(String::from_utf8(ptext).unwrap())
}
}