1use num_bigint::{BigInt, Sign};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Radix {
6 Hexadecimal,
7 Decimal,
8 Octal,
9 Binary,
10}
11
12impl Radix {
13 pub fn as_num(self) -> u32 {
15 match self {
16 Self::Hexadecimal => 16,
17 Self::Decimal => 10,
18 Self::Octal => 8,
19 Self::Binary => 2,
20 }
21 }
22}
23
24#[derive(Debug, Clone)]
26pub struct Literal<'a> {
27 num: &'a str,
29 radix: Radix,
31}
32
33impl<'a> Literal<'a> {
34 pub fn new(src: &'a str) -> Self {
35 debug_assert!(!src.is_empty());
36 debug_assert_ne!(src.chars().next(), Some('-'));
37 let (radix, prefix) = if src.len() < 2 {
38 (Radix::Decimal, None)
39 } else {
40 match &src[0..2] {
41 "0x" | "0X" => (Radix::Hexadecimal, Some(&src[..2])),
42 "0o" | "0O" => (Radix::Octal, Some(&src[..2])),
43 "0b" | "0B" => (Radix::Binary, Some(&src[..2])),
44 _ => (Radix::Decimal, None),
45 }
46 };
47
48 Self {
49 num: &src[prefix.map_or(0, str::len)..],
50 radix,
51 }
52 }
53
54 pub fn parse<T: num_traits::Num>(&self) -> Result<T, T::FromStrRadixErr> {
56 T::from_str_radix(self.num, self.radix.as_num())
57 }
58
59 pub fn radix(&self) -> Radix {
61 self.radix
62 }
63}
64
65pub fn to_hex_str(val: &BigInt) -> String {
67 format!(
68 "0x{}",
69 BigInt::from_bytes_be(Sign::Plus, &val.to_signed_bytes_be()).to_str_radix(16)
70 )
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_radix() {
79 assert_eq!(Literal::new("0XFF").radix(), Radix::Hexadecimal);
80 assert_eq!(Literal::new("0xFF").radix(), Radix::Hexadecimal);
81 assert_eq!(Literal::new("0O77").radix(), Radix::Octal);
82 assert_eq!(Literal::new("0o77").radix(), Radix::Octal);
83 assert_eq!(Literal::new("0B77").radix(), Radix::Binary);
84 assert_eq!(Literal::new("0b77").radix(), Radix::Binary);
85 assert_eq!(Literal::new("1").radix(), Radix::Decimal);
86
87 assert_eq!(Literal::new("0D15").radix(), Radix::Decimal);
89 }
90
91 #[test]
92 fn test_to_hex_str() {
93 assert_eq!(to_hex_str(&BigInt::from(-1i8)), "0xff");
94 assert_eq!(to_hex_str(&BigInt::from(-2i8)), "0xfe");
95 assert_eq!(to_hex_str(&BigInt::from(1i8)), "0x1");
96 assert_eq!(to_hex_str(&BigInt::from(2i8)), "0x2");
97 }
98}