1use std::ops::RangeBounds;
2
3#[derive(PartialEq, Eq, Hash, Clone, Debug)]
4pub struct Alphabet {
5 characters: Vec<char>,
6 cased: bool,
7}
8
9impl Default for Alphabet {
10 fn default() -> Self {
11 Self::caseless("ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap()
12 }
13}
14
15impl Alphabet {
16 pub fn cased(alphabet: &str) -> anyhow::Result<Self> {
17 let mut chars = alphabet.chars().collect::<Vec<_>>();
18 chars.dedup();
19 if chars.len() != alphabet.len() {
20 anyhow::bail!("Duplicate letter in alphabet: {alphabet}");
21 }
22
23 if alphabet.len() != 26 {
24 anyhow::bail!("Invalid alphabet length: {alphabet}");
25 }
26
27 if alphabet.chars().any(|letter| !letter.is_alphabetic()) {
28 anyhow::bail!("Invalid character found in alphabet: {alphabet}");
29 }
30
31 Ok(Self { characters: chars, cased: true })
32 }
33
34 pub fn caseless(alphabet: &str) -> anyhow::Result<Self> {
35 let alphabet = alphabet.to_uppercase();
36 let mut chars = alphabet.chars().collect::<Vec<_>>();
37 chars.dedup();
38 if chars.len() != alphabet.len() {
39 anyhow::bail!("Duplicate letter in alphabet: {alphabet}");
40 }
41
42 if alphabet.len() != 26 {
43 anyhow::bail!("Invalid alphabet length: {alphabet}");
44 }
45
46 if alphabet.chars().any(|letter| !letter.is_alphabetic()) {
47 anyhow::bail!("Invalid character found in alphabet: {alphabet}");
48 }
49
50 Ok(Self { characters: chars, cased: false })
51 }
52
53 pub fn of_cased(text: &str) -> Self {
67 let mut characters = Vec::new();
68 for character in text.chars() {
69 if !characters.contains(&character) {
70 characters.push(character);
71 }
72 }
73 Self { characters, cased: true }
74 }
75
76 pub fn from_ascii_range<R: RangeBounds<u8> + IntoIterator<Item = u8>>(range: R) -> anyhow::Result<Self> {
77 if range.end_bound() != std::ops::Bound::Included(&127) && range.end_bound() != std::ops::Bound::Excluded(&128) {
78 anyhow::bail!("Error creating alphabet from ASCII range: Upper bound must be at most 127.");
79 }
80
81 let mut characters = Vec::new();
82 for code in range {
83 characters.push(code as char);
84 }
85
86 Ok(Self { characters, cased: true })
87 }
88
89 pub fn random_index_of_coincidence(&self) -> f64 {
95 1f64 / self.characters.len() as f64
96 }
97
98 pub fn characters(&self) -> &[char] {
99 &self.characters
100 }
101
102 pub fn index_of(&self, mut character: char) -> Option<AlphabetIndex> {
103 if !self.cased {
104 character = character.to_ascii_uppercase();
105 }
106 self.characters.iter().position(|char| char == &character).map(|index| AlphabetIndex(index as u8 + 1))
107 }
108
109 pub fn letter_at(&self, index: AlphabetIndex) -> &char {
110 self.characters.get(*(index - 1) as usize).unwrap()
111 }
112
113 pub fn union(&self, other: &Self) -> Self {
114 Alphabet::of_cased(&self.characters.iter().chain(other.characters.iter()).collect::<String>())
115 }
116
117 pub fn shift(&self, shift: u8) -> Self {
118 let mut characters = String::new();
119 for index in 1..=26 {
120 let alphabet_index = AlphabetIndex::new(index).unwrap();
121 characters.push(*self.letter_at(alphabet_index + shift));
122 }
123 Alphabet::caseless(&characters).unwrap()
124 }
125}
126
127lazy_static::lazy_static! {
128 pub static ref LOWERCASE_LETTERS: Alphabet = Alphabet::of_cased("abcdefghijklmnopqrstuvwxyz");
129 pub static ref CAPITAL_LETTERS: Alphabet = Alphabet::of_cased("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
130 pub static ref LETTERS: Alphabet = CAPITAL_LETTERS.union(&LOWERCASE_LETTERS);
131 pub static ref NUMBERS: Alphabet = Alphabet::of_cased("1234567890");
132 pub static ref LETTERS_AND_NUMBERS: Alphabet = LETTERS.union(&NUMBERS);
133 pub static ref BASE_64: Alphabet = LETTERS_AND_NUMBERS.union(&Alphabet::of_cased("+/"));
134 pub static ref ASCII: Alphabet = Alphabet::from_ascii_range(0..128).unwrap();
135}
136
137#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
141pub struct AlphabetIndex(u8);
142
143impl AlphabetIndex {
144 pub fn new(index: u8) -> anyhow::Result<Self> {
145 if !(1..=26).contains(&index) {
146 anyhow::bail!("Alphabet index out of range: {index}")
147 }
148
149 Ok(Self(index))
150 }
151}
152
153impl std::ops::Deref for AlphabetIndex {
154 type Target = u8;
155
156 fn deref(&self) -> &Self::Target {
157 &self.0
158 }
159}
160
161impl std::ops::AddAssign<i32> for AlphabetIndex {
162 fn add_assign(&mut self, rhs: i32) {
163 *self = AlphabetIndex((self.0 + rhs as u8) % 26)
164 }
165}
166
167impl std::ops::Add<AlphabetIndex> for AlphabetIndex {
168 type Output = AlphabetIndex;
169
170 fn add(self, rhs: AlphabetIndex) -> Self::Output {
171 AlphabetIndex((self.0 + rhs.0) % 26)
172 }
173}
174
175impl std::ops::Add<u32> for AlphabetIndex {
176 type Output = AlphabetIndex;
177
178 fn add(self, rhs: u32) -> Self::Output {
179 AlphabetIndex((self.0 + rhs as u8) % 26)
180 }
181}
182
183impl std::ops::Add<u8> for AlphabetIndex {
184 type Output = AlphabetIndex;
185
186 fn add(self, rhs: u8) -> Self::Output {
187 AlphabetIndex((self.0 + rhs) % 26)
188 }
189}
190
191impl std::ops::Add<i32> for AlphabetIndex {
192 type Output = AlphabetIndex;
193
194 fn add(self, rhs: i32) -> Self::Output {
195 AlphabetIndex((self.0 + rhs as u8) % 26)
196 }
197}
198
199impl std::ops::Sub<AlphabetIndex> for AlphabetIndex {
200 type Output = AlphabetIndex;
201
202 fn sub(self, rhs: AlphabetIndex) -> Self::Output {
203 AlphabetIndex(((self.0 as i32 - rhs.0 as i32 + 26) % 26) as u8)
204 }
205}
206
207impl std::ops::Sub<u32> for AlphabetIndex {
208 type Output = AlphabetIndex;
209
210 fn sub(self, rhs: u32) -> Self::Output {
211 AlphabetIndex(((self.0 as i32 - rhs as i32 + 26) % 26) as u8)
212 }
213}