mini-enigma 0.3.0

#[no-std] (and no alloc) zero dependency implementation of the M3 Enigma
Documentation
use core::mem::MaybeUninit;

use super::{letter::Letter, ROTOR_SIZE};

/// Represents the internal wiring of an Enigma component.
/// Essentially a substitution cipher where the substitution
/// of a letter is the value at its index
pub type LetterMapping = [Letter; ROTOR_SIZE];

impl core::ops::Index<Letter> for [Letter] {
    type Output = Letter;

    fn index(&self, index: Letter) -> &Self::Output {
        &self[index as u8 as usize]
    }
}

impl core::ops::IndexMut<Letter> for [Letter] {
    fn index_mut(&mut self, index: Letter) -> &mut Self::Output {
        &mut self[index as u8 as usize]
    }
}

impl core::ops::Index<Letter> for [MaybeUninit<Letter>] {
    type Output = MaybeUninit<Letter>;

    fn index(&self, index: Letter) -> &Self::Output {
        &self[index as u8 as usize]
    }
}

impl core::ops::IndexMut<Letter> for [MaybeUninit<Letter>] {
    fn index_mut(&mut self, index: Letter) -> &mut Self::Output {
        &mut self[index as u8 as usize]
    }
}

/// A `LetterMapping` where all letters map to themselves
#[allow(clippy::cast_possible_truncation)]
pub const UNIT_LETTER_MAP: LetterMapping = {
    let mut wiring: [MaybeUninit<Letter>; ROTOR_SIZE] =
        unsafe { MaybeUninit::uninit().assume_init() };
    let mut i = 0;
    while i < ROTOR_SIZE {
        wiring[i] = MaybeUninit::new(Letter::const_from_u8(i as u8));
        i += 1;
    }
    unsafe { core::mem::transmute::<_, LetterMapping>(wiring) }
};

/// Creates a `LetterMapping` from a string where `mapping[i] = string[i]`
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub const fn string_to_letter_map(string: &'static str) -> LetterMapping {
    let mut wiring: [MaybeUninit<Letter>; ROTOR_SIZE] =
        unsafe { MaybeUninit::uninit().assume_init() };
    let mut i = 0;
    while i < ROTOR_SIZE {
        wiring[i] = MaybeUninit::new(Letter::const_from_char(string.as_bytes()[i] as char));
        i += 1;
    }
    unsafe { core::mem::transmute::<_, LetterMapping>(wiring) }
}

/// Creates a `LetterMapping` from a string that is the exact opposite of `string_to_letter_map`
///
/// # Examples
/// ```
/// # use mini_enigma::utils::{string_to_inv_letter_map, string_to_letter_map};
/// # use mini_enigma::utils::Letter;
/// # let foo = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/// let map = string_to_letter_map(foo);
/// let inv_map = string_to_inv_letter_map(foo);
/// let val = map[Letter::H];
/// assert_eq!(inv_map[val], Letter::H);
/// ```
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub const fn string_to_inv_letter_map(string: &'static str) -> LetterMapping {
    let mut wiring: [MaybeUninit<Letter>; ROTOR_SIZE] =
        unsafe { MaybeUninit::uninit().assume_init() };
    let mut i = 0;
    while i < ROTOR_SIZE {
        wiring[Letter::const_from_char(string.as_bytes()[i] as char) as usize] =
            MaybeUninit::new(Letter::const_from_u8(i as u8));
        i += 1;
    }
    unsafe { core::mem::transmute::<_, LetterMapping>(wiring) }
}