use super::{ConversionError, ROTOR_SIZE_U8};
const ASCII_OFFSET: u8 = 65;
#[repr(u8)]
#[allow(missing_docs)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub enum Letter {
#[default]
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
I = 8,
J = 9,
K = 10,
L = 11,
M = 12,
N = 13,
O = 14,
P = 15,
Q = 16,
R = 17,
S = 18,
T = 19,
U = 20,
V = 21,
W = 22,
X = 23,
Y = 24,
Z = 25,
}
impl core::ops::Add for Letter {
type Output = Letter;
fn add(self, rhs: Self) -> Self::Output {
unsafe { core::mem::transmute::<u8, Letter>((self as u8 + rhs as u8) % ROTOR_SIZE_U8) }
}
}
impl core::ops::Add<u8> for Letter {
type Output = Letter;
fn add(self, rhs: u8) -> Self::Output {
unsafe { core::mem::transmute::<u8, Letter>((self as u8 + rhs) % ROTOR_SIZE_U8) }
}
}
impl core::ops::Sub for Letter {
type Output = Letter;
fn sub(self, rhs: Self) -> Self::Output {
unsafe {
core::mem::transmute::<u8, Letter>(
(self as u8 + (ROTOR_SIZE_U8 - rhs as u8 % ROTOR_SIZE_U8)) % ROTOR_SIZE_U8,
)
}
}
}
impl core::ops::Sub<u8> for Letter {
type Output = Letter;
fn sub(self, rhs: u8) -> Self::Output {
unsafe {
core::mem::transmute::<u8, Letter>(
(self as u8 + (ROTOR_SIZE_U8 - rhs % ROTOR_SIZE_U8)) % ROTOR_SIZE_U8,
)
}
}
}
impl core::ops::AddAssign<u8> for Letter {
fn add_assign(&mut self, rhs: u8) {
*self = *self + rhs;
}
}
impl From<Letter> for char {
fn from(value: Letter) -> Self {
(value as u8 + ASCII_OFFSET) as char
}
}
impl TryFrom<char> for Letter {
type Error = ConversionError;
fn try_from(value: char) -> Result<Self, Self::Error> {
if value > 64 as char && value <= 90 as char {
Ok(unsafe { core::mem::transmute::<u8, Letter>(value as u8 - ASCII_OFFSET) })
} else {
Err(ConversionError)
}
}
}
impl From<u8> for Letter {
fn from(value: u8) -> Self {
unsafe { core::mem::transmute::<u8, Letter>(value % ROTOR_SIZE_U8) }
}
}
impl Letter {
#[must_use]
pub const fn const_from_char(value: char) -> Letter {
unsafe { core::mem::transmute::<u8, Letter>((value as u8 - ASCII_OFFSET) % ROTOR_SIZE_U8) }
}
#[must_use]
pub const fn const_from_u8(value: u8) -> Letter {
unsafe { core::mem::transmute::<u8, Letter>(value % ROTOR_SIZE_U8) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(Letter::A + Letter::B, Letter::B);
assert_eq!(Letter::Z + Letter::B, Letter::A);
assert_eq!(Letter::Y + Letter::B, Letter::Z);
assert_eq!(Letter::Y + Letter::E, Letter::C);
}
#[test]
fn test_sub() {
assert_eq!(Letter::B - Letter::B, Letter::A);
assert_eq!(Letter::B - Letter::D, Letter::Y);
}
#[test]
fn test_idx() {
let arr = [Letter::C, Letter::B, Letter::A];
assert_eq!(arr[Letter::B], Letter::B);
assert_eq!(arr[Letter::A], Letter::C);
}
}