1#![doc = include_str!("../README.md")]
2
3use {clap::ValueEnum, unicode_segmentation::UnicodeSegmentation};
4
5fn split(s: &str) -> Vec<String> {
6 UnicodeSegmentation::graphemes(s, true)
7 .map(ToString::to_string)
8 .collect()
9}
10
11pub struct Counter {
12 current: usize,
13 alphabet: Vec<String>,
14}
15
16impl Counter {
17 #[must_use]
18 pub fn new(alphabet: &str, start: usize) -> Counter {
19 Counter {
20 current: start,
21 alphabet: split(alphabet),
22 }
23 }
24
25 fn get(&self, x: usize) -> String {
26 let length = self.alphabet.len();
27 let d = x / length;
28 let r = x % length;
29 let t = self.alphabet[r].clone();
30 if d == 0 {
31 t
32 } else {
33 format!("{}{t}", self.get(d - 1))
34 }
35 }
36}
37
38impl std::iter::Iterator for Counter {
39 type Item = String;
40
41 fn next(&mut self) -> Option<Self::Item> {
42 let r = self.to_string();
43 self.current += 1;
44 Some(r)
45 }
46}
47
48impl std::fmt::Display for Counter {
49 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
50 write!(f, "{}", self.get(self.current))
51 }
52}
53
54#[derive(Clone, ValueEnum)]
55pub enum Kind {
56 EnglishUpper,
57 EnglishLower,
58}
59
60impl Kind {
61 #[must_use]
62 pub fn counter(&self, start: usize) -> Counter {
63 match self {
64 Kind::EnglishUpper => Counter::new("ABCDEFGHIJKLMNOPQRSTUVWXYZ", start),
65 Kind::EnglishLower => Counter::new("abcdefghijklmnopqrstuvwxyz", start),
66 }
67 }
68}