use std::path::Path;
use mini_enigma::components::{
Plugboard, Reflector, Rotor, REFLECTOR_A, REFLECTOR_B, REFLECTOR_B_THIN, REFLECTOR_C,
REFLECTOR_C_THIN, ROTOR_BETA, ROTOR_GAMMA, ROTOR_I, ROTOR_II, ROTOR_III, ROTOR_IV, ROTOR_V,
ROTOR_VI, ROTOR_VII, ROTOR_VIII,
};
use mini_enigma::state_machine::EnigmaSettings;
use mini_enigma::utils::Letter;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum RingstellungJSON {
Int(Vec<u8>),
Str(Vec<char>),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EnigmaSettingsJSON {
pub name: String,
pub date: Option<u32>,
pub rotors: Vec<String>,
pub reflector: String,
pub ringstellung: RingstellungJSON,
pub grundstellung: Vec<char>,
pub plugboard: Vec<String>,
pub ciphertext: String,
pub plaintext: String,
}
fn get_rotor(name: String) -> Option<Rotor> {
match name.as_str() {
"I" => Some(ROTOR_I),
"II" => Some(ROTOR_II),
"III" => Some(ROTOR_III),
"IV" => Some(ROTOR_IV),
"V" => Some(ROTOR_V),
"VI" => Some(ROTOR_VI),
"VII" => Some(ROTOR_VII),
"VIII" => Some(ROTOR_VIII),
"beta" => Some(ROTOR_BETA),
"gamma" => Some(ROTOR_GAMMA),
_ => None,
}
}
fn get_reflector(name: String) -> Option<Reflector> {
match name.as_str() {
"A" => Some(REFLECTOR_A),
"B" => Some(REFLECTOR_B),
"C" => Some(REFLECTOR_C),
"B Thin" => Some(REFLECTOR_B_THIN),
"C Thin" => Some(REFLECTOR_C_THIN),
_ => None,
}
}
pub fn load_enigma_settings<P>(file_path: P) -> EnigmaSettingsJSON
where
P: AsRef<Path> + std::fmt::Display + Copy,
{
serde_json::from_str(
&std::fs::read_to_string(file_path).expect(&format!("File at {file_path} not found")),
)
.expect(&format!("Could not parse file {file_path}"))
}
impl<const ROTOR_NUM: usize> From<EnigmaSettingsJSON> for EnigmaSettings<ROTOR_NUM> {
fn from(value: EnigmaSettingsJSON) -> Self {
let mut rotors = [ROTOR_I; ROTOR_NUM];
for (i, name) in value.rotors.iter().enumerate() {
rotors[i] =
get_rotor(name.clone()).expect(format!("Invalid rotor name: {name}").as_str());
}
let reflector = get_reflector(value.reflector.clone())
.expect(format!("Invalid reflector name: {}", value.reflector).as_str());
let ringstellung: [u8; ROTOR_NUM] = {
let mut rs = [0u8; ROTOR_NUM];
match value.ringstellung {
RingstellungJSON::Int(x) => {
for (i, &ring) in x.iter().enumerate() {
rs[i] = ring
}
}
RingstellungJSON::Str(x) => {
for (i, &ring) in x.iter().enumerate() {
rs[i] = ring as u8 - 64
}
}
};
rs
};
let grundstellung = {
let mut gs = [Letter::A; ROTOR_NUM];
for (i, &ring) in value.grundstellung.iter().enumerate() {
gs[i] = Letter::try_from(ring).unwrap();
}
gs
};
let plugboard = {
let pairs = value
.plugboard
.iter()
.map(|x| {
(
Letter::try_from(x.as_bytes()[0] as char).unwrap(),
Letter::try_from(x.as_bytes()[1] as char).unwrap(),
)
})
.collect::<Vec<(Letter, Letter)>>();
Plugboard::new(&pairs)
};
EnigmaSettings {
rotors,
plugboard,
reflector,
ringstellung,
grundstellung,
}
}
}