cl_format/tildes/
reveal_impl.rs

1use radix_fmt::Radix;
2use std::fmt::Write;
3use std::iter::{self, successors};
4
5use super::*;
6
7//========================================
8// TildeKindDigit
9//========================================
10multi_tilde_impl!(
11    TildeKindDigit,
12    [i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, isize],
13    self,
14    buf,
15    {
16        buf.push_str(self.to_string().as_str());
17        Ok(())
18    }
19);
20
21//========================================
22// TildeKindChar
23//========================================
24/// impl, re-define the format method for over writing the default method
25impl TildeKindChar for char {
26    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
27        match tkind {
28            TildeKind::Char(CharKind::At) => {
29                buf.push_str(format!("'{}'", self).as_str());
30                Ok(())
31            }
32            TildeKind::Char(CharKind::Nil) => {
33                buf.push_str(self.to_string().as_str());
34                Ok(())
35            }
36            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to Char").into()),
37        }
38    }
39}
40
41//========================================
42// TildeKindVa
43//========================================
44multi_tilde_impl!(
45    TildeKindVa,
46    [f32, f64, char, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, String],
47    self,
48    buf,
49    {
50        buf.push_str(self.to_string().as_str());
51        Ok(())
52    }
53);
54
55impl TildeKindVa for bool {
56    fn format(&self, _: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
57        if *self {
58            buf.push_str("true");
59        } else {
60            buf.push_str("false");
61        }
62        Ok(())
63    }
64}
65
66impl TildeKindVa for TildeNil {
67    fn format(&self, _: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
68        buf.push_str("nil");
69        Ok(())
70    }
71}
72
73impl TildeKindVa for Vec<&dyn TildeAble> {
74    fn format(&self, _: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
75        buf.push_str(format!("{:?}", self).as_str());
76        Ok(())
77    }
78}
79
80//========================================
81// TildeKindLoop
82//========================================
83impl<'a, 'arg> TildeKindLoop for Args<'a, 'arg> {
84    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
85        match tkind {
86            // self[0] is the Vec<&dyn TildeAble> of loop
87            TildeKind::Loop((_, TildeLoopKind::Nil | TildeLoopKind::NilColon)) => {
88                let a = self
89                    .pop()
90                    .ok_or::<TildeError>(TildeError::new(ErrorKind::FormatError, "run out args"))?;
91                tkind.match_reveal(a, buf)
92            }
93            TildeKind::Loop((vv, TildeLoopKind::At)) => {
94                'a: loop {
95                    for t in vv {
96                        if let TildeKind::LoopEnd = t.value {
97                            if self.left_count() != 0 {
98                                continue;
99                            } else {
100                                break 'a;
101                            }
102                        }
103                        t.reveal(self, buf)?;
104                    }
105                    //dbg!(self);
106                    if self.left_count() == 0 {
107                        break;
108                    }
109                }
110
111                Ok(())
112            }
113            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format Arg to Loop").into()),
114        }
115    }
116}
117
118impl<'a> TildeKindLoop for Vec<&dyn TildeAble> {
119    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
120        match tkind {
121            TildeKind::Loop((_, TildeLoopKind::Nil)) => {
122                let mut new_kind = tkind.clone();
123
124                match &mut new_kind {
125                    TildeKind::Loop((_, k @ TildeLoopKind::Nil)) => {
126                        if self.len() != 0 {
127                            *k = TildeLoopKind::At
128                        } else {
129                            return Ok(());
130                        }
131                    }
132                    _ => unreachable!(),
133                };
134                new_kind.match_reveal(&Args::from(self.as_slice()), buf)
135            }
136            TildeKind::Loop((_, TildeLoopKind::NilColon)) => {
137                let mut new_kind = tkind.clone();
138                match &mut new_kind {
139                    TildeKind::Loop((_, k @ TildeLoopKind::NilColon)) => *k = TildeLoopKind::At,
140                    _ => unreachable!(),
141                };
142                new_kind.match_reveal(&Args::from(self.as_slice()), buf)
143            }
144            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format Vec to Loop").into()),
145        }
146    }
147}
148
149//========================================
150// TildeKindCond
151//========================================
152impl TildeKindCond for usize {
153    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
154        //dbg!(self);
155        match tkind {
156            TildeKind::Cond((vv, TildeCondKind::Nil(true))) => match vv.get(*self) {
157                Some(tt) => {
158                    tt.reveal(&TildeNil, buf)?;
159                    Ok(())
160                }
161                None => {
162                    let last = vv.len() - 1;
163                    match vv.get(last) {
164                        Some(tt) => {
165                            tt.reveal(&TildeNil, buf)?;
166                            Ok(())
167                        }
168                        None => Ok(()),
169                    }
170                }
171            },
172            TildeKind::Cond((vv, TildeCondKind::Nil(false))) => match vv.get(*self) {
173                Some(tt) => {
174                    tt.reveal(&TildeNil, buf)?;
175                    Ok(())
176                }
177                None => Ok(()),
178            },
179            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to Cond").into()),
180        }
181    }
182}
183
184impl TildeKindCond for bool {
185    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
186        match tkind {
187            TildeKind::Cond((vv, TildeCondKind::Colon)) => {
188                if *self {
189                    vv.get(1)
190                        .ok_or::<TildeError>(TildeError::new(
191                            ErrorKind::FormatError,
192                            "cannot get tilde",
193                        ))?
194                        .reveal(&TildeNil, buf)?;
195
196                    Ok(())
197                } else {
198                    vv.get(0)
199                        .ok_or::<TildeError>(TildeError::new(
200                            ErrorKind::FormatError,
201                            "cannot get tilde",
202                        ))?
203                        .reveal(&TildeNil, buf)?;
204
205                    Ok(())
206                }
207            }
208            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to Cond").into()),
209        }
210    }
211}
212
213impl TildeKindCond for Option<&dyn TildeAble> {
214    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
215        match tkind {
216            TildeKind::Cond((vv, TildeCondKind::At)) => match self {
217                Some(a) => {
218                    //println!("here: {:?}", a);
219                    let k = TildeKind::VecTilde(vv.clone());
220                    // VecTilde need the vec
221                    // TildeCondKind::At only accept one arg
222
223                    k.match_reveal(&Args::from([*a]), buf)
224                }
225                None => Ok(()),
226            },
227            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to Cond").into()),
228        }
229    }
230}
231
232impl<'a, 'arg> TildeKindCond for Args<'a, 'arg> {
233    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
234        match tkind {
235            TildeKind::Cond((vv, TildeCondKind::Sharp)) => {
236                let l = self.left_count();
237                if l >= vv.len() {
238                    vv[vv.len() - 1].reveal(self, buf)?;
239                    Ok(())
240                } else {
241                    vv[l].reveal(self, buf)?;
242                    Ok(())
243                }
244            }
245            TildeKind::Cond((_, _)) => {
246                let a = self
247                    .pop()
248                    .ok_or::<TildeError>(TildeError::new(ErrorKind::FormatError, "run out args"))?;
249                tkind.match_reveal(a, buf)
250            }
251            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to Cond").into()),
252        }
253    }
254}
255
256//========================================
257// TildeKindVecTilde
258//========================================
259impl TildeKindVecTilde for TildeNil {
260    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
261        match tkind {
262            TildeKind::VecTilde(vv) => {
263                for v in vv {
264                    v.reveal(self, buf)?;
265                }
266
267                Ok(())
268            }
269            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to VecTilde").into()),
270        }
271    }
272}
273
274impl<'a, 'arg> TildeKindVecTilde for Args<'a, 'arg> {
275    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
276        match tkind {
277            TildeKind::VecTilde(vv) => {
278                for v in vv {
279                    v.reveal(self, buf)?;
280                }
281                Ok(())
282            }
283            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to VecTilde").into()),
284        }
285    }
286}
287
288//========================================
289// TildeKindStar
290//========================================
291impl<'a, 'arg> TildeKindStar for Args<'a, 'arg> {
292    fn format(&self, tkind: &TildeKind, _buf: &mut String) -> Result<(), TildeError> {
293        match tkind {
294            TildeKind::Star(StarKind::Hop) => {
295                self.back(); // back to last one, make it hop
296
297                Ok(())
298            }
299            TildeKind::Star(StarKind::Skip) => {
300                self.pop();
301                Ok(())
302            }
303            _ => Err(TildeError::new(ErrorKind::RevealError, "cannot format to Star").into()),
304        }
305    }
306}
307
308//========================================
309// TildeKindStandard
310//========================================
311impl TildeKindStandard for String {
312    fn format(&self, _: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
313        buf.push_str(format!("\"{}\"", self).as_str());
314        Ok(())
315    }
316}
317
318impl TildeKindStandard for char {
319    fn format(&self, _: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
320        buf.push_str(format!("'{}'", self).as_str());
321        Ok(())
322    }
323}
324
325multi_tilde_impl!(
326    TildeKindStandard,
327    [f32, f64, bool, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, isize],
328    self,
329    buf,
330    {
331        buf.push_str(self.to_string().as_str());
332        Ok(())
333    }
334);
335
336//========================================
337// TildeKindRadix
338//========================================
339const NUMERALS: [(usize, [&'static str; 10]); 4] = [
340    (
341        1000,
342        ["", "M", "MM", "MMM", "--", "-", "--", "---", "----", "--"],
343    ),
344    (
345        100,
346        ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"],
347    ),
348    (
349        10,
350        ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],
351    ),
352    (
353        1,
354        ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"],
355    ),
356];
357
358/// make roman
359fn into_roman(n: usize) -> Result<String, TildeError> {
360    if n > 3999 {
361        return Err(TildeError::new(
362            ErrorKind::FormatError,
363            "number is too big to reveal as roman numerals",
364        ));
365    }
366    Ok(NUMERALS
367        .iter()
368        .map(|&(base, nums)| nums[(n / base) % 10])
369        .collect())
370}
371
372/// make number
373const ONES: [&str; 20] = [
374    "zero",
375    "one",
376    "two",
377    "three",
378    "four",
379    "five",
380    "six",
381    "seven",
382    "eight",
383    "nine",
384    "ten",
385    "eleven",
386    "twelve",
387    "thirteen",
388    "fourteen",
389    "fifteen",
390    "sixteen",
391    "seventeen",
392    "eighteen",
393    "nineteen",
394];
395
396const ORDINAL_ONES: [&str; 20] = [
397    "zeroth",
398    "first",
399    "second",
400    "third",
401    "fourth",
402    "fifth",
403    "sixth",
404    "seventh",
405    "eighth",
406    "ninth",
407    "tenth",
408    "eleventh",
409    "twelfth",
410    "thirteenth",
411    "fourteenth",
412    "fifteenth",
413    "sixteenth",
414    "seventeenth",
415    "eighteenth",
416    "nineteenth",
417];
418
419const TENS: [&str; 10] = [
420    "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety",
421];
422
423const ORDINAL_TENS: [&str; 10] = [
424    "zeroth",
425    "tenth",
426    "twentieth",
427    "thirtieth",
428    "fortieth",
429    "fiftieth",
430    "sixtieth",
431    "seventieth",
432    "eightieth",
433    "ninetieth",
434];
435
436const ORDERS: [&str; 7] = [
437    "zero",
438    "thousand",
439    "million",
440    "billion",
441    "trillion",
442    "quadrillion",
443    "quintillion", // enough for u64::MAX
444];
445
446const ORDINAL_ORDERS: [&str; 7] = [
447    "zeroth",
448    "thousandth",
449    "millionth",
450    "billionth",
451    "trillionth",
452    "quadrillionth",
453    "quintillionth", // enough for u64::MAX
454];
455
456pub fn into_english(num: usize, buf: &mut String) {
457    match num {
458        0..=19 => {
459            buf.push_str(ONES[num as usize]);
460        }
461        20..=99 => {
462            let upper = (num / 10) as usize;
463            match num % 10 {
464                0 => buf.push_str(TENS[upper]),
465                lower => {
466                    buf.push_str(TENS[upper]);
467                    buf.push_str("-");
468                    into_english(lower, buf);
469                }
470            }
471        }
472        100..=999 => format_num(num, 100, "hundred", buf),
473        _ => {
474            let (div, order) = successors(Some(1_usize), |v| v.checked_mul(1000_usize))
475                .zip(ORDERS.iter())
476                .find(|&(e, _)| e > num / 1000)
477                .unwrap();
478
479            format_num(num, div, order, buf)
480        }
481    }
482}
483
484fn format_num(num: usize, div: usize, order: &str, buf: &mut String) {
485    match (num / div, num % div) {
486        (upper, 0) => {
487            into_english(upper, buf);
488            buf.push_str(" ");
489            buf.push_str(order)
490        }
491        (upper, lower) => {
492            into_english(upper, buf);
493            buf.push_str(" ");
494            buf.push_str(order);
495            buf.push_str(" ");
496            into_english(lower, buf);
497        }
498    }
499}
500
501pub fn into_ordinal_english(num: usize, buf: &mut String) {
502    match num {
503        0..=19 => {
504            buf.push_str(ORDINAL_ONES[num as usize]);
505        }
506        20..=99 => {
507            let upper = (num / 10) as usize;
508            match num % 10 {
509                0 => buf.push_str(ORDINAL_TENS[upper]),
510                lower => {
511                    buf.push_str(TENS[upper]);
512                    buf.push_str("-");
513                    into_ordinal_english(lower, buf);
514                }
515            }
516        }
517        100..=999 => format_ordinal_num(num, 100, "hundred", buf),
518        _ => {
519            let (div, order) = successors(Some(1_usize), |v| v.checked_mul(1000_usize))
520                .zip(ORDERS.iter())
521                .find(|&(e, _)| e > num / 1000)
522                .unwrap();
523            //dbg!(&div);
524            //dbg!(&order);
525            format_ordinal_num(num, div, order, buf)
526        }
527    }
528}
529
530fn orders_to_ordinal(order: &str) -> &str {
531    ORDINAL_ORDERS[ORDERS.iter().position(|s| *s == order).unwrap()]
532}
533
534fn format_ordinal_num(num: usize, div: usize, order: &str, buf: &mut String) {
535    //dbg!(&num);
536    //dbg!(&div);
537    match (num / div, num % div) {
538        (upper, 0) => {
539            into_english(upper, buf);
540            buf.push_str(" ");
541            buf.push_str(orders_to_ordinal(order))
542        }
543        (upper, lower) => {
544            into_english(upper, buf);
545            buf.push_str(" ");
546            buf.push_str(order);
547            buf.push_str(" ");
548            into_ordinal_english(lower, buf);
549        }
550    }
551}
552
553fn format_helper(
554    buf: &mut String,
555    orginal: String,
556    mincol: &Option<usize>,
557    padchar: &Option<char>,
558    commachar: &Option<char>,
559    comma_interval: &Option<usize>,
560    flag: &Option<RadixFlag>,
561) -> Result<(), TildeError> {
562    let mut inner_buf = String::with_capacity(orginal.len());
563    if let Some(RadixFlag::Colon) = flag {
564        match comma_interval {
565            Some(n) => {
566                let commachar = match commachar {
567                    Some(c) => *c,
568                    None => ',',
569                };
570
571                if orginal.len() > *n {
572                    let mut edge = orginal.len() % n;
573                    if edge == 0 {
574                        edge = *n;
575                    };
576                    inner_buf.push_str(&orginal[0..edge]);
577                    loop {
578                        if edge >= orginal.len() {
579                            break;
580                        }
581                        inner_buf.push(commachar);
582                        inner_buf.push_str(&orginal[edge..edge + n]);
583                        edge += n;
584                    }
585                } else {
586                    inner_buf.push_str(&orginal);
587                }
588            }
589            None => (),
590        }
591    } else {
592        inner_buf = orginal
593    }
594
595    match mincol {
596        Some(n) => {
597            if *n > inner_buf.len() {
598                buf.push_str(
599                    &iter::repeat(padchar.unwrap_or(' '))
600                        .take(*n - inner_buf.len())
601                        .collect::<String>(),
602                );
603                buf.push_str(&inner_buf);
604            } else {
605                buf.push_str(&inner_buf);
606            }
607        }
608        None => buf.push_str(&inner_buf),
609    }
610
611    Ok(())
612}
613
614impl TildeKindRadix for isize {
615    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
616        match tkind {
617            TildeKind::Radix((ra, mincol, padchar, commachar, comma_interval, flag)) => {
618                match (ra, mincol, padchar, commachar, comma_interval, flag) {
619                    (ra, None, None, None, None, None) => {
620                        if ra.is_none() {
621                            // ~R
622                            if *self < 0 {
623                                buf.push_str("negative ");
624                                into_english(self.abs() as usize, buf)
625                            } else {
626                                into_english(self.abs() as usize, buf)
627                            }
628                        } else {
629                            // ~xR
630                            if *self < 0 {
631                                write!(buf, "-{}", Radix::new(-*self, ra.unwrap())).map_err(
632                                    |e| TildeError::new(ErrorKind::FormatError, e.to_string()),
633                                )?
634                            } else {
635                                write!(buf, "{}", Radix::new(*self, ra.unwrap())).map_err(|e| {
636                                    TildeError::new(ErrorKind::FormatError, e.to_string())
637                                })?
638                            }
639                        }
640                    }
641                    (ra, None, None, None, None, Some(RadixFlag::Colon)) => {
642                        if ra.is_none() {
643                            // ~:R
644                            if *self < 0 {
645                                buf.push_str("negative ");
646                                into_ordinal_english(self.abs() as usize, buf)
647                            } else {
648                                into_ordinal_english(self.abs() as usize, buf)
649                            }
650                        } else {
651                            // ~x:R
652                            // ~x:R == ~x,,,',,3:R
653                            if *self < 0 {
654                                buf.push('-');
655                                let s = Radix::new(-*self, ra.unwrap()).to_string();
656                                format_helper(buf, s, mincol, padchar, &Some(','), &Some(3), flag)?;
657                            } else {
658                                let s = Radix::new(*self, ra.unwrap()).to_string();
659                                format_helper(buf, s, mincol, padchar, &Some(','), &Some(3), flag)?;
660                            }
661                        }
662                    }
663
664                    (None, None, None, None, None, Some(RadixFlag::At)) => {
665                        // ~@R
666                        if *self <= 0 {
667                            return Err(TildeError::new(
668                                ErrorKind::FormatError,
669                                "negative cannot be roman numerals",
670                            ));
671                        } else {
672                            buf.push_str(&into_roman(*self as usize)?);
673                        }
674                    }
675
676                    (None, None, None, None, None, Some(RadixFlag::AtColon)) => {
677                        return Err(TildeError::new(
678                            ErrorKind::FormatError,
679                            "old Roman numeral haven't supported yet",
680                        ));
681                    }
682
683                    (ra, _, _, _, _, _) => {
684                        if *self < 0 {
685                            buf.push('-');
686                            let s = Radix::new(-*self, ra.unwrap()).to_string();
687                            format_helper(
688                                buf,
689                                s,
690                                mincol,
691                                padchar,
692                                commachar,
693                                comma_interval,
694                                flag,
695                            )?;
696                        } else {
697                            let s = Radix::new(*self, ra.unwrap()).to_string();
698                            format_helper(
699                                buf,
700                                s,
701                                mincol,
702                                padchar,
703                                commachar,
704                                comma_interval,
705                                flag,
706                            )?;
707                        }
708                    }
709                }
710            }
711            _ => {
712                return Err(
713                    TildeError::new(ErrorKind::RevealError, "cannot format to Radix").into(),
714                )
715            }
716        }
717        Ok(())
718    }
719}
720
721impl TildeKindRadix for i8 {
722    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
723        TildeKindRadix::format(&Into::<isize>::into(*self), tkind, buf)
724    }
725}
726
727impl TildeKindRadix for i16 {
728    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
729        TildeKindRadix::format(&Into::<isize>::into(*self), tkind, buf)
730    }
731}
732
733impl TildeKindRadix for i32 {
734    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
735        TildeKindRadix::format(&(*self as isize), tkind, buf)
736    }
737}
738
739impl TildeKindRadix for i64 {
740    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
741        TildeKindRadix::format(&(*self as isize), tkind, buf)
742    }
743}
744
745impl TildeKindRadix for i128 {
746    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
747        TildeKindRadix::format(&(*self as isize), tkind, buf)
748    }
749}
750
751impl TildeKindRadix for usize {
752    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
753        match tkind {
754            TildeKind::Radix((ra, mincol, padchar, commachar, comma_interval, flag)) => {
755                match (ra, mincol, padchar, commachar, comma_interval, flag) {
756                    (ra, None, None, None, None, None) => {
757                        if ra.is_none() {
758                            // ~R
759                            into_english(*self, buf)
760                        } else {
761                            // ~xR
762                            write!(buf, "{}", Radix::new(*self, ra.unwrap())).map_err(|e| {
763                                TildeError::new(ErrorKind::FormatError, e.to_string())
764                            })?
765                        }
766                    }
767                    (ra, None, None, None, None, Some(RadixFlag::Colon)) => {
768                        if ra.is_none() {
769                            // ~:R
770                            into_ordinal_english(*self, buf)
771                        } else {
772                            // ~x:R
773                            // ~x:R == ~x,,,',,3:R
774                            let s = Radix::new(*self, ra.unwrap()).to_string();
775                            format_helper(buf, s, mincol, padchar, &Some(','), &Some(3), flag)?;
776                        }
777                    }
778
779                    (None, None, None, None, None, Some(RadixFlag::At)) => {
780                        // ~@R
781                        buf.push_str(&into_roman(*self as usize)?);
782                    }
783
784                    (None, None, None, None, None, Some(RadixFlag::AtColon)) => {
785                        return Err(TildeError::new(
786                            ErrorKind::FormatError,
787                            "old Roman numeral haven't supported yet",
788                        ));
789                    }
790
791                    (ra, _, _, _, _, _) => {
792                        let s = Radix::new(*self, ra.unwrap()).to_string();
793                        format_helper(buf, s, mincol, padchar, commachar, comma_interval, flag)?;
794                    }
795                }
796            }
797            _ => {
798                return Err(
799                    TildeError::new(ErrorKind::RevealError, "cannot format to Radix").into(),
800                )
801            }
802        }
803        Ok(())
804    }
805}
806
807impl TildeKindRadix for u8 {
808    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
809        TildeKindRadix::format(&(*self as usize), tkind, buf)
810    }
811}
812impl TildeKindRadix for u16 {
813    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
814        TildeKindRadix::format(&(*self as usize), tkind, buf)
815    }
816}
817impl TildeKindRadix for u32 {
818    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
819        TildeKindRadix::format(&(*self as usize), tkind, buf)
820    }
821}
822
823impl TildeKindRadix for u64 {
824    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
825        TildeKindRadix::format(&(*self as usize), tkind, buf)
826    }
827}
828
829impl TildeKindRadix for u128 {
830    fn format(&self, tkind: &TildeKind, buf: &mut String) -> Result<(), TildeError> {
831        TildeKindRadix::format(&(*self as usize), tkind, buf)
832    }
833}
834
835#[cfg(test)]
836mod tests {
837    use super::*;
838
839    #[test]
840    fn test_into_english() {
841        let mut buf = String::new();
842        into_english(12345, &mut buf);
843        assert_eq!(
844            buf,
845            String::from("twelve thousand three hundred forty-five")
846        );
847
848        let mut buf = String::new();
849        into_english(0, &mut buf);
850        assert_eq!(buf, String::from("zero"));
851
852        let mut buf = String::new();
853        into_english(1000000000000000001, &mut buf);
854        assert_eq!(buf, String::from("one quintillion one"));
855
856        let mut buf = String::new();
857        into_english(2132314453234, &mut buf);
858        assert_eq!(buf, String::from("two trillion one hundred thirty-two billion three hundred fourteen million four hundred fifty-three thousand two hundred thirty-four"));
859    }
860
861    #[test]
862    fn test_into_ordinal_english() {
863        let mut buf = String::new();
864        into_ordinal_english(55, &mut buf);
865
866        assert_eq!(buf, String::from("fifty-fifth"));
867
868        let mut buf = String::new();
869        into_ordinal_english(345, &mut buf);
870
871        assert_eq!(buf, String::from("three hundred forty-fifth"));
872
873        let mut buf = String::new();
874        into_ordinal_english(12345, &mut buf);
875
876        assert_eq!(
877            buf,
878            String::from("twelve thousand three hundred forty-fifth")
879        );
880
881        let mut buf = String::new();
882        into_ordinal_english(1000000000000000, &mut buf);
883        assert_eq!(buf, String::from("one quadrillionth"));
884
885        let mut buf = String::new();
886        into_ordinal_english(1000000000000000001, &mut buf);
887        assert_eq!(buf, String::from("one quintillion first"));
888
889        let mut buf = String::new();
890        into_ordinal_english(2132314453234, &mut buf);
891        assert_eq!(buf, String::from("two trillion one hundred thirty-two billion three hundred fourteen million four hundred fifty-three thousand two hundred thirty-fourth"));
892    }
893
894    #[test]
895    fn test_radix_format() {
896        let mut buf = String::new();
897        assert!(write!(buf, "{}", Radix::new(17, 3)).is_ok());
898        assert_eq!(buf, String::from("122"));
899
900        let mut buf = String::new();
901        assert!(write!(buf, "{}", Radix::new(345, 2)).is_ok());
902        assert_eq!(buf, String::from("101011001"));
903    }
904
905    #[test]
906    fn test_format_helper() {
907        let mut buf = String::new();
908        assert!(format_helper(
909            &mut buf,
910            Radix::new(345, 2).to_string(),
911            &None,
912            &None,
913            &Some(','),
914            &Some(3),
915            &Some(RadixFlag::Colon),
916        )
917        .is_ok());
918        assert_eq!(buf, String::from("101,011,001"));
919
920        let mut buf = String::new();
921        assert!(format_helper(
922            &mut buf,
923            Radix::new(345, 2).to_string(),
924            &None,
925            &None,
926            &Some(','),
927            &Some(3),
928            &None,
929        )
930        .is_ok());
931        assert_eq!(buf, String::from("101011001"));
932
933        let mut buf = String::new();
934        assert!(format_helper(
935            &mut buf,
936            Radix::new(345, 3).to_string(),
937            &None,
938            &None,
939            &Some(','),
940            &Some(3),
941            &Some(RadixFlag::Colon),
942        )
943        .is_ok());
944        assert_eq!(buf, String::from("110,210"));
945
946        let mut buf = String::new();
947        assert!(format_helper(
948            &mut buf,
949            Radix::new(17, 3).to_string(),
950            &None,
951            &None,
952            &Some(','),
953            &Some(2),
954            &Some(RadixFlag::Colon),
955        )
956        .is_ok());
957        assert_eq!(buf, String::from("1,22"));
958
959        let mut buf = String::new();
960        assert!(format_helper(
961            &mut buf,
962            Radix::new(17, 10).to_string(),
963            &None,
964            &None,
965            &Some(','),
966            &Some(2),
967            &Some(RadixFlag::Colon),
968        )
969        .is_ok());
970        assert_eq!(buf, String::from("17"));
971
972        let mut buf = String::new();
973        assert!(format_helper(
974            &mut buf,
975            Radix::new(17, 10).to_string(),
976            &Some(5),
977            &Some('a'),
978            &Some(','),
979            &Some(2),
980            &Some(RadixFlag::Colon),
981        )
982        .is_ok());
983        assert_eq!(buf, String::from("aaa17"));
984    }
985}