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