1const LETTERS: &[char] = &[
18 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
19 't', 'u', 'v', 'w', 'x', 'y', 'z',
20];
21const UP_LETTERS: &[char] = &[
22 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
23 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
24];
25const GREEK: &[char] = &[
26 '\u{03B1}', '\u{03B2}', '\u{03B3}', '\u{03B4}', '\u{03B5}', '\u{03B6}', '\u{03B7}', '\u{03B8}',
27 '\u{03B9}', '\u{03BA}', '\u{03BB}', '\u{03BC}', '\u{03BD}', '\u{03BE}', '\u{03BF}', '\u{03C0}',
28 '\u{03C1}', '\u{03C3}', '\u{03C4}', '\u{03C5}', '\u{03C6}', '\u{03C7}', '\u{03C8}', '\u{03C9}',
29];
30const UP_GREEK: &[char] = &[
31 '\u{0391}', '\u{0392}', '\u{0393}', '\u{0394}', '\u{0395}', '\u{0396}', '\u{0397}', '\u{0398}',
32 '\u{0399}', '\u{039A}', '\u{039B}', '\u{039C}', '\u{039D}', '\u{039E}', '\u{039F}', '\u{03A0}',
33 '\u{03A1}', '\u{03A3}', '\u{03A4}', '\u{03A5}', '\u{03A6}', '\u{03A7}', '\u{03A8}', '\u{03A9}',
34];
35
36pub fn radix_format(mut number: i64, symbols: &[char]) -> String {
38 let mut chars: Vec<char> = Vec::new();
39 let max = symbols.len() as i64;
40 while number > 0 {
41 let index = (number - 1) % max;
42 chars.push(symbols[index as usize]);
43 number = (number - 1) / max;
44 }
45 chars.into_iter().rev().collect()
46}
47pub fn radix_format_str(mut number: i64, symbols: &[&str]) -> String {
49 let mut parts: Vec<&str> = Vec::new();
50 let max = symbols.len() as i64;
51 while number > 0 {
52 let index = (number - 1) % max;
53 parts.push(symbols[index as usize]);
54 number = (number - 1) / max;
55 }
56 parts.into_iter().rev().collect()
57}
58
59pub fn radix_alpha(n: i64) -> String { radix_format(n, LETTERS) }
61pub fn radix_up_alpha(n: i64) -> String { radix_format(n, UP_LETTERS) }
63pub fn radix_greek(n: i64) -> String { radix_format(n, GREEK) }
65
66pub fn radix_up_greek(n: i64) -> String { radix_format(n, UP_GREEK) }
68
69const RMLETTERS: &[char] = &['i', 'v', 'x', 'l', 'c', 'd', 'm']; pub fn radix_roman(mut n: i64) -> String {
78 if n <= 0 {
79 return String::new();
80 }
81 let mut s = String::new();
82 let mut div = 1000;
83 if n >= div {
84 s = (0..(n / div)).map(|_| 'm').collect::<String>();
85 }
86
87 let mut p = 4;
88 loop {
89 n %= div;
90 if n == 0 {
91 break;
92 }
93 div /= 10;
94 let mut d: i64 = n / div;
95 if d % 5 == 4 {
96 s.push(RMLETTERS[p]);
97 d += 1;
98 }
99 if d > 4 {
100 let index: usize = p + (d / 5) as usize;
101 s.push(RMLETTERS[index]);
102 d %= 5;
103 }
104 if d != 0 {
105 let ps = (0..d).map(|_| RMLETTERS[p]).collect::<String>();
106 s.push_str(&ps);
107 }
108 if p > 1 {
109 p -= 2;
110 } else {
111 p = 0;
112 }
113 }
114 s
115}
116
117pub fn radix_up_roman(n: i64) -> String { radix_roman(n).to_uppercase() }
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn roman_non_positive_empty() {
126 assert_eq!(radix_roman(0), "");
127 assert_eq!(radix_roman(-1), "");
128 assert_eq!(radix_roman(i64::MIN), "");
129 }
130
131 #[test]
132 fn roman_basic_cases() {
133 assert_eq!(radix_roman(1), "i");
134 assert_eq!(radix_roman(4), "iv");
135 assert_eq!(radix_roman(9), "ix");
136 assert_eq!(radix_roman(1000), "m");
137 assert_eq!(radix_roman(1999), "mcmxcix");
138 }
139
140 #[test]
141 fn alpha_edge_cases() {
142 assert_eq!(radix_alpha(0), "");
143 assert_eq!(radix_alpha(-5), "");
144 assert_eq!(radix_alpha(1), "a");
145 assert_eq!(radix_alpha(26), "z");
146 assert_eq!(radix_alpha(27), "aa");
147 }
148
149 #[test]
150 fn alpha_alphabet_progression() {
151 assert_eq!(radix_alpha(28), "ab");
152 assert_eq!(radix_alpha(52), "az");
153 assert_eq!(radix_alpha(53), "ba");
154 assert_eq!(radix_alpha(26 * 26 + 26), "zz");
156 assert_eq!(radix_alpha(26 * 26 + 26 + 1), "aaa");
157 }
158
159 #[test]
160 fn up_alpha_basic() {
161 assert_eq!(radix_up_alpha(0), "");
162 assert_eq!(radix_up_alpha(1), "A");
163 assert_eq!(radix_up_alpha(26), "Z");
164 assert_eq!(radix_up_alpha(27), "AA");
165 }
166
167 #[test]
168 fn up_alpha_vs_alpha_case_only() {
169 for n in 0..60 {
171 assert_eq!(
172 radix_up_alpha(n),
173 radix_alpha(n).to_uppercase(),
174 "divergence at {n}"
175 );
176 }
177 }
178
179 #[test]
180 fn greek_basic() {
181 assert_eq!(radix_greek(0), "");
182 assert_eq!(radix_greek(1), "α");
183 assert_eq!(radix_greek(24), "ω"); assert_eq!(radix_greek(25), "αα");
185 }
186
187 #[test]
188 fn up_greek_basic() {
189 assert_eq!(radix_up_greek(0), "");
190 assert_eq!(radix_up_greek(1), "Α");
191 assert_eq!(radix_up_greek(24), "Ω");
192 }
193
194 #[test]
195 fn up_roman_cases() {
196 assert_eq!(radix_up_roman(0), "");
197 assert_eq!(radix_up_roman(1), "I");
198 assert_eq!(radix_up_roman(4), "IV");
199 assert_eq!(radix_up_roman(1000), "M");
200 assert_eq!(radix_up_roman(1999), "MCMXCIX");
201 }
202
203 #[test]
204 fn radix_format_str_multi_char_symbols() {
205 let syms = &["one", "two", "three"];
207 assert_eq!(radix_format_str(0, syms), "");
208 assert_eq!(radix_format_str(1, syms), "one");
209 assert_eq!(radix_format_str(3, syms), "three");
210 assert_eq!(radix_format_str(4, syms), "oneone");
212 }
213
214 #[test]
215 fn radix_format_custom_symbols() {
216 let syms = &['A', 'B'];
219 assert_eq!(radix_format(1, syms), "A");
220 assert_eq!(radix_format(2, syms), "B");
221 assert_eq!(radix_format(3, syms), "AA");
223 assert_eq!(radix_format(4, syms), "AB");
224 }
225}