mini_enigma/utils/
letter.rs1use super::{ConversionError, ROTOR_SIZE_U8};
2
3const ASCII_OFFSET: u8 = 65;
4
5#[repr(u8)]
6#[allow(missing_docs)]
7#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
8pub enum Letter {
10 #[default]
11 A = 0,
12 B = 1,
13 C = 2,
14 D = 3,
15 E = 4,
16 F = 5,
17 G = 6,
18 H = 7,
19 I = 8,
20 J = 9,
21 K = 10,
22 L = 11,
23 M = 12,
24 N = 13,
25 O = 14,
26 P = 15,
27 Q = 16,
28 R = 17,
29 S = 18,
30 T = 19,
31 U = 20,
32 V = 21,
33 W = 22,
34 X = 23,
35 Y = 24,
36 Z = 25,
37}
38
39impl core::ops::Add for Letter {
40 type Output = Letter;
41 fn add(self, rhs: Self) -> Self::Output {
42 unsafe { core::mem::transmute::<u8, Letter>((self as u8 + rhs as u8) % ROTOR_SIZE_U8) }
43 }
44}
45impl core::ops::Add<u8> for Letter {
46 type Output = Letter;
47
48 fn add(self, rhs: u8) -> Self::Output {
49 unsafe { core::mem::transmute::<u8, Letter>((self as u8 + rhs) % ROTOR_SIZE_U8) }
50 }
51}
52impl core::ops::Sub for Letter {
53 type Output = Letter;
54
55 fn sub(self, rhs: Self) -> Self::Output {
56 unsafe {
57 core::mem::transmute::<u8, Letter>(
58 (self as u8 + (ROTOR_SIZE_U8 - rhs as u8 % ROTOR_SIZE_U8)) % ROTOR_SIZE_U8,
59 )
60 }
61 }
62}
63impl core::ops::Sub<u8> for Letter {
64 type Output = Letter;
65
66 fn sub(self, rhs: u8) -> Self::Output {
67 unsafe {
68 core::mem::transmute::<u8, Letter>(
69 (self as u8 + (ROTOR_SIZE_U8 - rhs % ROTOR_SIZE_U8)) % ROTOR_SIZE_U8,
70 )
71 }
72 }
73}
74impl core::ops::AddAssign<u8> for Letter {
75 fn add_assign(&mut self, rhs: u8) {
76 *self = *self + rhs;
77 }
78}
79
80impl From<Letter> for char {
81 fn from(value: Letter) -> Self {
82 (value as u8 + ASCII_OFFSET) as char
83 }
84}
85
86impl TryFrom<char> for Letter {
87 type Error = ConversionError;
88
89 fn try_from(value: char) -> Result<Self, Self::Error> {
90 if value > 64 as char && value <= 90 as char {
91 Ok(unsafe { core::mem::transmute::<u8, Letter>(value as u8 - ASCII_OFFSET) })
92 } else {
93 Err(ConversionError)
94 }
95 }
96}
97
98impl From<u8> for Letter {
99 fn from(value: u8) -> Self {
100 unsafe { core::mem::transmute::<u8, Letter>(value % ROTOR_SIZE_U8) }
101 }
102}
103
104impl Letter {
105 #[must_use]
111 pub const fn const_from_char(value: char) -> Letter {
112 unsafe { core::mem::transmute::<u8, Letter>((value as u8 - ASCII_OFFSET) % ROTOR_SIZE_U8) }
113 }
114
115 #[must_use]
117 pub const fn const_from_u8(value: u8) -> Letter {
118 unsafe { core::mem::transmute::<u8, Letter>(value % ROTOR_SIZE_U8) }
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_add() {
128 assert_eq!(Letter::A + Letter::B, Letter::B);
129 assert_eq!(Letter::Z + Letter::B, Letter::A);
130 assert_eq!(Letter::Y + Letter::B, Letter::Z);
131 assert_eq!(Letter::Y + Letter::E, Letter::C);
132 }
133
134 #[test]
135 fn test_sub() {
136 assert_eq!(Letter::B - Letter::B, Letter::A);
137 assert_eq!(Letter::B - Letter::D, Letter::Y);
138 }
139
140 #[test]
141 fn test_idx() {
142 let arr = [Letter::C, Letter::B, Letter::A];
143 assert_eq!(arr[Letter::B], Letter::B);
144 assert_eq!(arr[Letter::A], Letter::C);
145 }
146}