1use indexmap::set::Iter;
2use indexmap::IndexSet;
3use rand::Rng;
4use std::char::ParseCharError;
5use std::fmt;
6use std::iter::FromIterator;
7use std::ops::{Deref, DerefMut};
8use std::str::FromStr;
9
10#[derive(Debug, Clone, Eq, PartialEq)]
12pub struct Pool(IndexSet<char>);
13
14impl Deref for Pool {
15 type Target = IndexSet<char>;
16
17 fn deref(&self) -> &Self::Target {
18 &self.0
19 }
20}
21
22impl DerefMut for Pool {
23 fn deref_mut(&mut self) -> &mut Self::Target {
24 &mut self.0
25 }
26}
27
28impl FromIterator<char> for Pool {
29 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
30 let mut pool = Pool::new();
31 pool.0 = IndexSet::from_iter(iter);
32
33 pool
34 }
35}
36
37impl Extend<char> for Pool {
38 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
39 self.0.extend(iter)
40 }
41}
42
43impl FromStr for Pool {
44 type Err = ParseCharError;
45
46 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 Ok(Pool(s.chars().collect::<IndexSet<char>>()))
48 }
49}
50
51impl fmt::Display for Pool {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "{}", self.0.iter().collect::<String>())
54 }
55}
56
57impl Pool {
58 pub fn new() -> Self {
60 Pool(IndexSet::new())
61 }
62
63 pub fn len(&self) -> usize {
73 self.0.len()
74 }
75
76 pub fn extend_from_string(&mut self, s: &str) -> &mut Self {
78 self.0.extend(s.chars().collect::<IndexSet<char>>());
79
80 self
81 }
82
83 pub fn is_empty(&self) -> bool {
93 self.0.is_empty()
94 }
95
96 pub(crate) fn get(&self, index: usize) -> Option<&char> {
98 self.0.get_index(index)
99 }
100
101 pub fn contains(&self, ch: char) -> bool {
111 self.0.contains(&ch)
112 }
113
114 pub fn contains_all(&self, elements: &str) -> bool {
124 self.0
125 .is_superset(&elements.chars().collect::<IndexSet<char>>())
126 }
127
128 #[allow(dead_code)]
131 pub(crate) fn insert(&mut self, ch: char) {
132 self.0.insert(ch);
133 }
134
135 pub fn iter(&self) -> Iter<'_, char> {
137 self.0.iter()
138 }
139
140 pub fn swap_remove(&mut self, ch: &char) -> bool {
142 self.0.swap_remove(ch)
143 }
144
145 pub fn shift_remove(&mut self, ch: &char) -> bool {
147 self.0.shift_remove(ch)
148 }
149
150 pub fn remove_all(&mut self, elements: &str) {
152 elements.chars().for_each(|ch| {
153 self.swap_remove(&ch);
154 });
155 }
156
157 pub fn sort(&mut self) {
169 self.0.sort()
170 }
171}
172
173pub fn generate_password(pool: &Pool, length: usize) -> String {
187 assert!(!pool.is_empty(), "Pool contains no elements!");
188
189 let mut rng = rand::thread_rng();
190
191 (0..length)
192 .map(|_| {
193 let idx = rng.gen_range(0, pool.len());
194 *pool.get(idx).unwrap()
195 })
196 .collect()
197}
198
199pub fn calculate_entropy(length: usize, pool_size: usize) -> f64 {
208 length as f64 * (pool_size as f64).log2()
209}
210
211pub fn calculate_length(entropy: f64, pool_size: f64) -> f64 {
220 (entropy / pool_size.log2()).ceil()
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn pool_deref_mut() {
229 let mut pool = Pool::from_str("12345").unwrap();
230 *pool = "abcde".chars().collect::<IndexSet<char>>();
231
232 assert_eq!(*pool, "abcde".chars().collect::<IndexSet<char>>())
233 }
234
235 #[test]
236 fn pool_deref() {
237 let pool = Pool::from_str("12345").unwrap();
238
239 assert_eq!(*pool, "12345".chars().collect::<IndexSet<char>>())
240 }
241
242 #[test]
243 fn pool_sort() {
244 let mut pool = Pool::from_str("31524").unwrap();
245 pool.sort();
246
247 assert_eq!(pool, Pool::from_str("12345").unwrap())
248 }
249
250 #[test]
251 fn pool_extend() {
252 let mut pool = Pool::from_str("abc").unwrap();
253 pool.extend(vec!['d', 'e']);
254
255 assert_eq!(pool, Pool::from_str("abcde").unwrap())
256 }
257
258 #[test]
259 fn pool_from_iter() {
260 let iter = vec!['a', 'b', 'c'].into_iter();
261
262 assert_eq!(iter.collect::<Pool>(), Pool::from_str("abc").unwrap());
263 }
264
265 #[test]
266 fn pool_remove_all() {
267 let mut pool: Pool = "abcde".parse().unwrap();
268 pool.remove_all("ace");
269
270 assert_eq!(pool, "bd".parse::<Pool>().unwrap());
271 }
272
273 #[test]
274 fn pool_swap_remove() {
275 let mut pool: Pool = "abcdefz".parse().unwrap();
276
277 assert!(pool.swap_remove(&'b'));
278 assert_eq!(pool.get(1), Some(&'z'));
279 assert_eq!(pool.get(6), None);
280 }
281
282 #[test]
283 fn pool_shift_remove() {
284 let mut pool: Pool = "abcdefz".parse().unwrap();
285
286 assert!(pool.shift_remove(&'b'));
287 assert_eq!(pool.get(1), Some(&'c'));
288 assert_eq!(pool.get(6), None);
289 }
290
291 #[test]
292 fn pool_iter() {
293 let pool: Pool = "abcdefz".parse().unwrap();
294 let mut iter = pool.iter();
295
296 assert_eq!(iter.next(), Some(&'a'));
297 assert_eq!(iter.next(), Some(&'b'));
298 assert_eq!(iter.last(), Some(&'z'));
299 }
300
301 #[test]
302 fn pool_display() {
303 let pool: Pool = "0123456789".parse().unwrap();
304
305 assert_eq!(pool.to_string(), "0123456789".to_owned());
306 }
307
308 #[test]
309 fn pool_contains_all() {
310 let pool: Pool = "0123456789".parse().unwrap();
311
312 assert!(pool.contains_all("2357"));
313 }
314
315 #[test]
316 fn pool_contains_all_assert_false() {
317 let pool: Pool = "0123456789".parse().unwrap();
318
319 assert!(!pool.contains_all("0123F"));
320 }
321
322 #[test]
323 fn pool_contains() {
324 let pool: Pool = "0123456789".parse().unwrap();
325
326 assert!(pool.contains('5'));
327 }
328
329 #[test]
330 fn pool_contains_assert_false() {
331 let pool: Pool = "0123456789".parse().unwrap();
332
333 assert!(!pool.contains('A'));
334 }
335
336 #[test]
337 fn pool_get() {
338 let pool: Pool = "ABCD".parse().unwrap();
339
340 assert_eq!(pool.get(0), Some(&'A'))
341 }
342
343 #[test]
344 fn pool_is_empty() {
345 let pool = Pool::new();
346
347 assert!(pool.is_empty());
348 }
349
350 #[test]
351 fn pool_is_empty_assert_false() {
352 let pool = Pool::from_str("0123456789").unwrap();
353
354 assert!(!pool.is_empty());
355 }
356
357 #[test]
358 fn pool_len() {
359 let pool: Pool = "0123456789".parse().unwrap();
360
361 assert_eq!(pool.len(), 10)
362 }
363
364 #[test]
365 fn pool_insert() {
366 let mut pool = "ABC".parse::<Pool>().unwrap();
367 pool.insert('D');
368
369 assert_eq!(pool, "ABCD".parse::<Pool>().unwrap())
370 }
371
372 #[test]
373 fn pool_extend_from_string() {
374 let mut pool = "ABC".parse::<Pool>().unwrap();
375 let mut other_pool = pool.clone();
376
377 other_pool.insert('D');
378 pool.extend_from_string("D");
379
380 assert_eq!(other_pool, pool)
381 }
382
383 #[test]
384 fn pool_from_string() {
385 let indexset: IndexSet<_> = "0123456789".chars().collect();
386
387 assert_eq!(Pool(indexset), "0123456789".to_owned().parse().unwrap())
388 }
389
390 #[test]
391 fn pool_from_str() {
392 let indexset: IndexSet<_> = "0123456789".chars().collect();
393
394 assert_eq!(Pool(indexset), "0123456789".parse().unwrap())
395 }
396
397 #[test]
398 fn generate_password_assert_len() {
399 let pool = "0123456789".chars().collect::<IndexSet<char>>();
400 let password = generate_password(&Pool(pool), 15);
401
402 assert_eq!(password.chars().count(), 15);
403 }
404
405 #[test]
406 #[should_panic(expected = "Pool contains no elements!")]
407 fn generate_password_passed_empty_pool() {
408 let pool = "".chars().collect::<IndexSet<char>>();
409
410 generate_password(&Pool(pool), 15);
411 }
412
413 #[test]
414 fn calculate_entropy_assert_true() {
415 let entropy = calculate_entropy(12, 64);
416
417 assert_eq!(entropy, 72_f64);
418 }
419
420 #[test]
421 fn calculate_entropy_passed_length_is_0() {
422 let entropy = calculate_entropy(0, 64);
423
424 assert_eq!(entropy, 0_f64)
425 }
426
427 #[test]
428 fn calculate_entropy_passed_pool_size_is_0() {
429 let entropy = calculate_entropy(12, 0);
430
431 assert_eq!(entropy, f64::NEG_INFINITY)
432 }
433
434 #[test]
435 fn calculate_entropy_passed_pool_size_is_1() {
436 let entropy = calculate_entropy(12, 1);
437
438 assert_eq!(entropy, 0_f64)
439 }
440
441 #[test]
442 fn calculate_length_assert_true() {
443 let length = calculate_length(128_f64, 64_f64);
444
445 assert_eq!(length, 22_f64);
446 }
447
448 #[test]
449 fn calculate_length_entropy_is_0() {
450 let length = calculate_length(0_f64, 64_f64);
451
452 assert_eq!(length, 0_f64);
453 }
454
455 #[test]
456 fn calculate_length_pool_size_is_0() {
457 let length = calculate_length(128_f64, 0_f64);
458
459 assert_eq!(length, 0_f64);
460 }
461
462 #[test]
463 fn calculate_length_entropy_and_pool_size_is_0() {
464 let length = calculate_length(0_f64, 0_f64);
465
466 assert_eq!(length, 0_f64);
467 }
468
469 #[test]
470 fn calculate_length_entropy_is_0_and_pool_size_is_1() {
471 let length = calculate_length(0_f64, 1_f64);
472
473 assert!(length.is_nan());
474 }
475
476 #[test]
477 fn calculate_length_entropy_is_1_and_pool_size_is_1() {
478 let length = calculate_length(1_f64, 1_f64);
479
480 assert_eq!(length, f64::INFINITY);
481 }
482}