mandos/value_interpreter/
parse_num.rs1use super::prefixes::*;
2use num_bigint::{BigInt, BigUint, Sign};
3use num_traits::identities::Zero;
4
5pub fn try_parse_fixed_width(s: &str) -> Option<Vec<u8>> {
6 if let Some(stripped) = s.strip_prefix(U64_PREFIX) {
7 return Some(parse_fixed_width_unsigned(stripped, 8));
8 }
9
10 if let Some(stripped) = s.strip_prefix(U32_PREFIX) {
11 return Some(parse_fixed_width_unsigned(stripped, 4));
12 }
13
14 if let Some(stripped) = s.strip_prefix(U16_PREFIX) {
15 return Some(parse_fixed_width_unsigned(stripped, 2));
16 }
17
18 if let Some(stripped) = s.strip_prefix(U8_PREFIX) {
19 return Some(parse_fixed_width_unsigned(stripped, 1));
20 }
21
22 if let Some(stripped) = s.strip_prefix(I64_PREFIX) {
23 return Some(parse_fixed_width_signed(stripped, 8));
24 }
25
26 if let Some(stripped) = s.strip_prefix(I32_PREFIX) {
27 return Some(parse_fixed_width_signed(stripped, 4));
28 }
29
30 if let Some(stripped) = s.strip_prefix(I16_PREFIX) {
31 return Some(parse_fixed_width_signed(stripped, 2));
32 }
33
34 if let Some(stripped) = s.strip_prefix(I8_PREFIX) {
35 return Some(parse_fixed_width_signed(stripped, 1));
36 }
37
38 if let Some(stripped) = s.strip_prefix(BIGUINT_PREFIX) {
39 return Some(parse_biguint(stripped));
40 }
41
42 None
43}
44
45pub fn parse_num(s: &str) -> Vec<u8> {
46 if let Some(stripped) = s.strip_prefix('+') {
47 let bi = BigInt::from_bytes_be(Sign::Plus, parse_unsigned(stripped).as_slice());
48 return big_int_to_bytes_be(&bi);
49 }
50
51 if let Some(stripped) = s.strip_prefix('-') {
52 let bi = BigInt::from_bytes_be(Sign::Minus, parse_unsigned(stripped).as_slice());
53 return big_int_to_bytes_be(&bi);
54 }
55
56 parse_unsigned(s)
57}
58
59fn parse_fixed_width_signed(s: &str, length: usize) -> Vec<u8> {
60 if let Some(stripped) = s.strip_prefix('-') {
61 let mut result = vec![0xffu8; length];
62 let bi = BigInt::from_bytes_be(Sign::Minus, parse_unsigned(stripped).as_slice());
63 let bytes = bi.to_signed_bytes_be();
64 assert!(
65 bytes.len() <= length,
66 "representation of {s} does not fit in {length} bytes"
67 );
68 let offset = length - bytes.len();
69 if !bytes.is_empty() {
70 result[offset..].clone_from_slice(&bytes[..]);
71 }
72 result
73 } else {
74 let s = if let Some(stripped) = s.strip_prefix('+') {
75 stripped
76 } else {
77 s
78 };
79 let result = parse_fixed_width_unsigned(s, length);
80 assert!(
81 result.is_empty() || result[0] >> 7 != 1,
82 "representation of {s} does not fit in {length} bytes"
83 );
84 result
85 }
86}
87
88fn parse_fixed_width_unsigned(s: &str, length: usize) -> Vec<u8> {
89 let parsed = parse_unsigned(s);
90 assert!(
91 parsed.len() <= length,
92 "representation of {s} does not fit in {length} bytes"
93 );
94
95 let mut result = vec![0u8; length];
96 let offset = length - parsed.len();
97 if !parsed.is_empty() {
98 result[offset..].clone_from_slice(&parsed[..]);
99 }
100 result
101}
102
103fn parse_biguint(s: &str) -> Vec<u8> {
104 let parsed = parse_unsigned(s);
105 let encoded_length = (parsed.len() as u32).to_be_bytes();
106 [&encoded_length[..], &parsed[..]].concat()
107}
108
109fn parse_unsigned(s: &str) -> Vec<u8> {
110 let clean = s.replace(&['_', ','][..], "");
111 if clean.starts_with("0x") || clean.starts_with("0X") {
112 let clean = &clean[2..];
113 return if clean.len() % 2 == 0 {
114 hex::decode(clean).unwrap()
115 } else {
116 let even_bytes = format!("0{clean}");
117 hex::decode(&even_bytes[..]).unwrap()
118 };
119 }
120
121 if clean.starts_with("0b") || clean.starts_with("0B") {
122 let clean = &clean[2..];
123 if clean.is_empty() {
124 return Vec::new();
125 }
126 let bu = BigUint::parse_bytes(clean.as_bytes(), 2).unwrap();
127 return big_uint_to_bytes_be(&bu);
128 }
129
130 if let Some(bu) = BigUint::parse_bytes(clean.as_bytes(), 10) {
131 big_uint_to_bytes_be(&bu)
132 } else {
133 panic!("Could not parse base 10 number: {clean}")
134 }
135}
136
137fn big_uint_to_bytes_be(bu: &BigUint) -> Vec<u8> {
138 if bu.is_zero() {
139 Vec::new()
140 } else {
141 bu.to_bytes_be()
142 }
143}
144
145fn big_int_to_bytes_be(bi: &BigInt) -> Vec<u8> {
146 if bi.is_zero() {
147 Vec::new()
148 } else {
149 bi.to_signed_bytes_be()
150 }
151}