ethiopic_numerals/
lib.rs

1const ETHIOPIC_ONE: u16 = '፩' as u16;
2const ETHIOPIC_TEN: u16 = '፲' as u16;
3const ONE: u16 = '1' as u16;
4
5pub fn ethiopic(num: usize) -> String {
6    let mut num = num.to_string();
7    if num.len() % 2 != 0 {
8        num.insert(0, '0')
9    }
10
11    let mut num = num.chars().rev().peekable();
12
13    let mut ethiopic_num = String::new();
14    let mut pos = 0;
15    while let (Some(ascii_one), Some(ascii_ten)) = (num.next(), num.next()) {
16        let mut ethio_one: Option<char> = None;
17        let mut ethio_ten: Option<char> = None;
18
19        if ascii_one != '0' {
20            ethio_one = char::from_u32((ETHIOPIC_ONE + ((ascii_one as u16) - ONE)) as u32);
21        }
22
23        if ascii_ten != '0' {
24            ethio_ten = char::from_u32((ETHIOPIC_TEN + ((ascii_ten as u16) - ONE)) as u32);
25        }
26
27        let sep = if pos > 0 {
28            if pos % 2 == 0 {
29                "፼"
30            } else if ethio_one.is_some() || ethio_ten.is_some() {
31                "፻"
32            } else {
33                ""
34            }
35        } else {
36            ""
37        };
38
39        if ethio_one == Some('፩')
40            && sep != ""
41            && ethio_ten.is_none()
42            && (num.peek().is_none() || sep == "፻")
43        {
44            ethio_one = None;
45        }
46
47        let mut part = String::new();
48
49        if let Some(x) = ethio_ten {
50            part.push(x);
51        }
52        if let Some(x) = ethio_one {
53            part.push(x);
54        }
55
56        part.push_str(sep);
57        ethiopic_num = format!("{part}{ethiopic_num}");
58        pos += 1;
59    }
60
61    ethiopic_num
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::ethiopic;
67
68    #[test]
69    fn test() {
70        let test_data = [
71            (0, ""),
72            (1, "፩"),
73            (2, "፪"),
74            (3, "፫"),
75            (4, "፬"),
76            (5, "፭"),
77            (6, "፮"),
78            (7, "፯"),
79            (8, "፰"),
80            (9, "፱"),
81            (10, "፲"),
82            (20, "፳"),
83            (30, "፴"),
84            (40, "፵"),
85            (50, "፶"),
86            (60, "፷"),
87            (70, "፸"),
88            (80, "፹"),
89            (90, "፺"),
90            (100, "፻"),
91            (500, "፭፻"),
92            (10_000, "፼"),
93            (42, "፵፪"),
94            (78, "፸፰"),
95            (18, "፲፰"),
96            (1000, "፲፻"),
97            (100_000, "፲፼"),
98            (111, "፻፲፩"),
99            (666, "፮፻፷፮"),
100            (1_000_000, "፻፼"),
101            (10_000_000, "፲፻፼"),
102            (123, "፻፳፫"),
103            (1111, "፲፩፻፲፩"),
104            (1234, "፲፪፻፴፬"),
105            (6666, "፷፮፻፷፮"),
106            (1001, "፲፻፩"),
107            (11111, "፼፲፩፻፲፩"),
108            (111111, "፲፩፼፲፩፻፲፩"),
109        ];
110
111        for (n, e) in test_data {
112            assert_eq!(ethiopic(n), e.to_owned());
113        }
114    }
115
116    #[test]
117    fn test_from_website() {
118        let test_data = [
119            (1, "፩"),
120            (10, "፲"),
121            (100, "፻"),
122            (1000, "፲፻"),
123            (10000, "፼"),
124            (100000, "፲፼"),
125            (1000000, "፻፼"),
126            (10000000, "፲፻፼"),
127            (100000000, "፼፼"),
128            (1000000000, "፲፼፼"),
129            (10000000000, "፻፼፼"),
130            (100000000000, "፲፻፼፼"),
131            (1000000000000, "፼፼፼"),
132            (100010000, "፼፩፼"),
133            (100100000, "፼፲፼"),
134            (100200000, "፼፳፼"),
135            (100110000, "፼፲፩፼"),
136            (1, "፩"),
137            (11, "፲፩"),
138            (111, "፻፲፩"),
139            (1111, "፲፩፻፲፩"),
140            (11111, "፼፲፩፻፲፩"),
141            (111111, "፲፩፼፲፩፻፲፩"),
142            (1111111, "፻፲፩፼፲፩፻፲፩"),
143            (11111111, "፲፩፻፲፩፼፲፩፻፲፩"),
144            (111111111, "፼፲፩፻፲፩፼፲፩፻፲፩"),
145            (1111111111, "፲፩፼፲፩፻፲፩፼፲፩፻፲፩"),
146            (11111111111, "፻፲፩፼፲፩፻፲፩፼፲፩፻፲፩"),
147            (111111111111, "፲፩፻፲፩፼፲፩፻፲፩፼፲፩፻፲፩"),
148            (1111111111111, "፼፲፩፻፲፩፼፲፩፻፲፩፼፲፩፻፲፩"),
149            (1, "፩"),
150            (12, "፲፪"),
151            (123, "፻፳፫"),
152            (1234, "፲፪፻፴፬"),
153            (12345, "፼፳፫፻፵፭"),
154            (7654321, "፯፻፷፭፼፵፫፻፳፩"),
155            (17654321, "፲፯፻፷፭፼፵፫፻፳፩"),
156            (51615131, "፶፩፻፷፩፼፶፩፻፴፩"),
157            (15161513, "፲፭፻፲፮፼፲፭፻፲፫"),
158            (10101011, "፲፻፲፼፲፻፲፩"),
159            (101, "፻፩"),
160            (1001, "፲፻፩"),
161            (1010, "፲፻፲"),
162            (1011, "፲፻፲፩"),
163            (1100, "፲፩፻"),
164            (1101, "፲፩፻፩"),
165            (1111, "፲፩፻፲፩"),
166            (10001, "፼፩"),
167            (10010, "፼፲"),
168            (10100, "፼፻"),
169            (10101, "፼፻፩"),
170            (10110, "፼፻፲"),
171            (10111, "፼፻፲፩"),
172            (100001, "፲፼፩"),
173            (100010, "፲፼፲"),
174            (100011, "፲፼፲፩"),
175            (100100, "፲፼፻"),
176            (101010, "፲፼፲፻፲"),
177            (1000001, "፻፼፩"),
178            (1000101, "፻፼፻፩"),
179            (1000100, "፻፼፻"),
180            (1010000, "፻፩፼"),
181            (1010001, "፻፩፼፩"),
182            (1100001, "፻፲፼፩"),
183            (1010101, "፻፩፼፻፩"),
184            (101010101, "፼፻፩፼፻፩"),
185            (100010000, "፼፩፼"),
186            (100010100, "፼፩፼፻"),
187            (101010100, "፼፻፩፼፻"),
188            (3, "፫"),
189            (30, "፴"),
190            (33, "፴፫"),
191            (303, "፫፻፫"),
192            (3003, "፴፻፫"),
193            (3030, "፴፻፴"),
194            (3033, "፴፻፴፫"),
195            (3300, "፴፫፻"),
196            (3303, "፴፫፻፫"),
197            (3333, "፴፫፻፴፫"),
198            (30003, "፫፼፫"),
199            (30303, "፫፼፫፻፫"),
200            (300003, "፴፼፫"),
201            (303030, "፴፼፴፻፴"),
202            (3000003, "፫፻፼፫"),
203            (3000303, "፫፻፼፫፻፫"),
204            (3030003, "፫፻፫፼፫"),
205            (3300003, "፫፻፴፼፫"),
206            (3030303, "፫፻፫፼፫፻፫"),
207            (303030303, "፫፼፫፻፫፼፫፻፫"),
208            (333333333, "፫፼፴፫፻፴፫፼፴፫፻፴፫"),
209        ];
210
211        for (n, e) in test_data {
212            assert_eq!(ethiopic(n), e.to_owned());
213        }
214    }
215}