57 lines
1.4 KiB
Rust
57 lines
1.4 KiB
Rust
use crate::util;
|
|
|
|
pub struct CaesarCipher {
|
|
alphabet: Vec<char>,
|
|
offset: i64,
|
|
}
|
|
|
|
impl CaesarCipher {
|
|
pub fn new(alphabet: &str, offset: i64) -> anyhow::Result<Self> {
|
|
let alphabet = alphabet.chars().collect::<Vec<_>>();
|
|
let offset = offset % alphabet.len() as i64;
|
|
|
|
util::verify_alphabet(&alphabet)?;
|
|
|
|
Ok(Self { alphabet, offset })
|
|
}
|
|
|
|
pub fn encode(&self, input: &str) -> anyhow::Result<String> {
|
|
let mut output = String::with_capacity(input.len());
|
|
|
|
for c in input.chars() {
|
|
let index = self.get_index(c, self.offset)?;
|
|
output.push(self.alphabet[index])
|
|
}
|
|
|
|
Ok(output)
|
|
}
|
|
|
|
pub fn decode(&self, input: &str) -> anyhow::Result<String> {
|
|
let mut output = String::with_capacity(input.len());
|
|
|
|
for c in input.chars() {
|
|
let index = self.get_index(c, -self.offset)?;
|
|
output.push(self.alphabet[index])
|
|
}
|
|
|
|
Ok(output)
|
|
}
|
|
|
|
fn get_index(&self, c: char, offset: i64) -> anyhow::Result<usize> {
|
|
let mut index =
|
|
self.alphabet
|
|
.iter()
|
|
.position(|&x| x == c)
|
|
.ok_or(anyhow::anyhow!("cannot encode character {:?}", c))? as i64
|
|
+ offset;
|
|
|
|
while index < 0 {
|
|
index += self.alphabet.len() as i64;
|
|
}
|
|
|
|
index %= self.alphabet.len() as i64;
|
|
|
|
Ok(index as usize)
|
|
}
|
|
}
|