mini_enigma/utils/
letter_mapping.rs

1use core::mem::MaybeUninit;
2
3use super::{letter::Letter, ROTOR_SIZE};
4
5/// Represents the internal wiring of an Enigma component.
6/// Essentially a substitution cipher where the substitution
7/// of a letter is the value at its index
8pub type LetterMapping = [Letter; ROTOR_SIZE];
9
10impl core::ops::Index<Letter> for [Letter] {
11    type Output = Letter;
12
13    fn index(&self, index: Letter) -> &Self::Output {
14        &self[index as u8 as usize]
15    }
16}
17
18impl core::ops::IndexMut<Letter> for [Letter] {
19    fn index_mut(&mut self, index: Letter) -> &mut Self::Output {
20        &mut self[index as u8 as usize]
21    }
22}
23
24impl core::ops::Index<Letter> for [MaybeUninit<Letter>] {
25    type Output = MaybeUninit<Letter>;
26
27    fn index(&self, index: Letter) -> &Self::Output {
28        &self[index as u8 as usize]
29    }
30}
31
32impl core::ops::IndexMut<Letter> for [MaybeUninit<Letter>] {
33    fn index_mut(&mut self, index: Letter) -> &mut Self::Output {
34        &mut self[index as u8 as usize]
35    }
36}
37
38/// A `LetterMapping` where all letters map to themselves
39#[allow(clippy::cast_possible_truncation)]
40pub const UNIT_LETTER_MAP: LetterMapping = {
41    let mut wiring: [MaybeUninit<Letter>; ROTOR_SIZE] =
42        unsafe { MaybeUninit::uninit().assume_init() };
43    let mut i = 0;
44    while i < ROTOR_SIZE {
45        wiring[i] = MaybeUninit::new(Letter::const_from_u8(i as u8));
46        i += 1;
47    }
48    unsafe { core::mem::transmute::<_, LetterMapping>(wiring) }
49};
50
51/// Creates a `LetterMapping` from a string where `mapping[i] = string[i]`
52#[must_use]
53#[allow(clippy::cast_possible_truncation)]
54pub const fn string_to_letter_map(string: &'static str) -> LetterMapping {
55    let mut wiring: [MaybeUninit<Letter>; ROTOR_SIZE] =
56        unsafe { MaybeUninit::uninit().assume_init() };
57    let mut i = 0;
58    while i < ROTOR_SIZE {
59        wiring[i] = MaybeUninit::new(Letter::const_from_char(string.as_bytes()[i] as char));
60        i += 1;
61    }
62    unsafe { core::mem::transmute::<_, LetterMapping>(wiring) }
63}
64
65/// Creates a `LetterMapping` from a string that is the exact opposite of `string_to_letter_map`
66///
67/// # Examples
68/// ```
69/// # use mini_enigma::utils::{string_to_inv_letter_map, string_to_letter_map};
70/// # use mini_enigma::utils::Letter;
71/// # let foo = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
72/// let map = string_to_letter_map(foo);
73/// let inv_map = string_to_inv_letter_map(foo);
74/// let val = map[Letter::H];
75/// assert_eq!(inv_map[val], Letter::H);
76/// ```
77#[must_use]
78#[allow(clippy::cast_possible_truncation)]
79pub const fn string_to_inv_letter_map(string: &'static str) -> LetterMapping {
80    let mut wiring: [MaybeUninit<Letter>; ROTOR_SIZE] =
81        unsafe { MaybeUninit::uninit().assume_init() };
82    let mut i = 0;
83    while i < ROTOR_SIZE {
84        wiring[Letter::const_from_char(string.as_bytes()[i] as char) as usize] =
85            MaybeUninit::new(Letter::const_from_u8(i as u8));
86        i += 1;
87    }
88    unsafe { core::mem::transmute::<_, LetterMapping>(wiring) }
89}