trivet/numbers/
radix.rs

1// Trivet
2// Copyright (c) 2025 by Stacy Prowell.  All rights reserved.
3// https://gitlab.com/binary-tools/trivet
4
5//! Provide the different radices for numbers.
6
7use std::fmt::{self, Debug, Display};
8
9/// Number radices that are supported.
10#[derive(Clone, Copy, Default, PartialEq, Eq)]
11pub enum Radix {
12    /// Binary is base two.
13    Binary,
14    /// Octal is base eight.
15    Octal,
16    /// Decimal is base 10.
17    #[default]
18    Decimal,
19    /// Hexadecimal is base 16.
20    Hexadecimal,
21}
22
23impl Radix {
24    /// Get the value of each radix.
25    pub fn value(&self) -> u32 {
26        match self {
27            Radix::Binary => 2,
28            Radix::Octal => 8,
29            Radix::Decimal => 10,
30            Radix::Hexadecimal => 16,
31        }
32    }
33
34    /// Get the radix prefix.
35    pub fn as_prefix(&self) -> String {
36        match self {
37            Radix::Binary => String::from("0b"),
38            Radix::Octal => String::from("0o"),
39            Radix::Decimal => String::from(""),
40            Radix::Hexadecimal => String::from("0x"),
41        }
42    }
43
44    /// Return a closure that can be used to determine if a given character is a legal
45    /// digit in the chosen radix.
46    pub fn digit_test(&self) -> Box<dyn Fn(char) -> bool> {
47        match self {
48            Radix::Binary => Box::new(|ch| ch == '0' || ch == '1'),
49            Radix::Octal => Box::new(|ch| ('0'..='7').contains(&ch)),
50            Radix::Decimal => Box::new(|ch| char::is_ascii_digit(&ch)),
51            Radix::Hexadecimal => Box::new(|ch| char::is_ascii_hexdigit(&ch)),
52        }
53    }
54}
55
56impl Debug for Radix {
57    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
58        write!(
59            formatter,
60            "Radix::{}",
61            match self {
62                Radix::Binary => "Binary",
63                Radix::Octal => "Octal",
64                Radix::Decimal => "Decimal",
65                Radix::Hexadecimal => "Hexadecimal",
66            }
67        )
68    }
69}
70
71impl Display for Radix {
72    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
73        write!(
74            formatter,
75            "{}",
76            match self {
77                Radix::Binary => "Binary",
78                Radix::Octal => "Octal",
79                Radix::Decimal => "Decimal",
80                Radix::Hexadecimal => "Hexadecimal",
81            }
82        )
83    }
84}
85
86#[cfg(test)]
87mod test {
88    use crate::numbers::Radix;
89
90    #[test]
91    fn value_test() {
92        let mut radix = Radix::Binary;
93        assert_eq!(radix.value(), 2);
94        assert_eq!(radix.as_prefix(), "0b".to_string());
95        assert!(!(radix.digit_test())('/'));
96        assert!((radix.digit_test())('0'));
97        assert!((radix.digit_test())('1'));
98        assert!(!(radix.digit_test())('2'));
99        assert!(!(radix.digit_test())('A'));
100        assert!(!(radix.digit_test())('a'));
101
102        radix = Radix::Octal;
103        assert_eq!(radix.value(), 8);
104        assert_eq!(radix.as_prefix(), "0o".to_string());
105        assert!(!(radix.digit_test())('/'));
106        assert!((radix.digit_test())('0'));
107        assert!((radix.digit_test())('1'));
108        assert!((radix.digit_test())('2'));
109        assert!((radix.digit_test())('3'));
110        assert!((radix.digit_test())('4'));
111        assert!((radix.digit_test())('5'));
112        assert!((radix.digit_test())('6'));
113        assert!((radix.digit_test())('7'));
114        assert!(!(radix.digit_test())('8'));
115        assert!(!(radix.digit_test())('A'));
116        assert!(!(radix.digit_test())('a'));
117
118        radix = Radix::Decimal;
119        assert_eq!(radix.value(), 10);
120        assert_eq!(radix.as_prefix(), "".to_string());
121        assert!(!(radix.digit_test())('/'));
122        assert!((radix.digit_test())('0'));
123        assert!((radix.digit_test())('1'));
124        assert!((radix.digit_test())('2'));
125        assert!((radix.digit_test())('3'));
126        assert!((radix.digit_test())('4'));
127        assert!((radix.digit_test())('5'));
128        assert!((radix.digit_test())('6'));
129        assert!((radix.digit_test())('7'));
130        assert!((radix.digit_test())('8'));
131        assert!((radix.digit_test())('9'));
132        assert!(!(radix.digit_test())(':'));
133        assert!(!(radix.digit_test())('A'));
134        assert!(!(radix.digit_test())('a'));
135
136        radix = Radix::Hexadecimal;
137        assert_eq!(radix.value(), 16);
138        assert_eq!(radix.as_prefix(), "0x".to_string());
139        assert!(!(radix.digit_test())('/'));
140        assert!((radix.digit_test())('0'));
141        assert!((radix.digit_test())('1'));
142        assert!((radix.digit_test())('2'));
143        assert!((radix.digit_test())('3'));
144        assert!((radix.digit_test())('4'));
145        assert!((radix.digit_test())('5'));
146        assert!((radix.digit_test())('6'));
147        assert!((radix.digit_test())('7'));
148        assert!((radix.digit_test())('8'));
149        assert!((radix.digit_test())('9'));
150        assert!(!(radix.digit_test())(':'));
151        assert!(!(radix.digit_test())('@'));
152        assert!(!(radix.digit_test())('`'));
153        assert!((radix.digit_test())('A'));
154        assert!((radix.digit_test())('a'));
155        assert!((radix.digit_test())('B'));
156        assert!((radix.digit_test())('b'));
157        assert!((radix.digit_test())('C'));
158        assert!((radix.digit_test())('c'));
159        assert!((radix.digit_test())('D'));
160        assert!((radix.digit_test())('d'));
161        assert!((radix.digit_test())('E'));
162        assert!((radix.digit_test())('e'));
163        assert!((radix.digit_test())('F'));
164        assert!((radix.digit_test())('f'));
165        assert!(!(radix.digit_test())('G'));
166        assert!(!(radix.digit_test())('g'));
167    }
168}