1use crate::token::{Token, TokenType};
8use regex::Regex;
9
10pub trait ChUtils {
15 fn is_number(&self) -> bool;
17
18 fn is_point(&self) -> bool;
22
23 fn is_plus_or_minus(&self) -> bool;
28
29 fn is_div_or_prod(&self) -> bool;
34
35 fn is_operation_sign(&self) -> bool;
43
44 fn is_parentheses(&self) -> (bool, bool);
49
50 fn is_abs(&self) -> (bool, bool);
55
56 fn is_percentage(&self) -> bool;
58}
59
60impl ChUtils for String {
61 fn is_number(&self) -> bool {
62 Regex::new("[[:digit:]]").unwrap().is_match(self)
63 }
64
65 fn is_point(&self) -> bool {
66 self.trim().eq(".") || self.trim().eq(",")
67 }
68
69 fn is_plus_or_minus(&self) -> bool {
70 self.trim().eq("+") || self.trim().eq("-")
71 }
72
73 fn is_div_or_prod(&self) -> bool {
74 let is_div: bool = self.trim().eq(":") || self.trim().eq("/");
75 let is_prod: bool = self.trim().eq("*") || self.trim().eq("•");
76
77 is_div || is_prod
78 }
79
80 fn is_operation_sign(&self) -> bool {
81 self.is_plus_or_minus() || self.is_div_or_prod()
82 }
83
84 fn is_parentheses(&self) -> (bool, bool) {
85 (self.trim().eq("("), self.trim().eq(")"))
86 }
87
88 fn is_abs(&self) -> (bool, bool) {
89 (self.trim().eq("["), self.trim().eq("]"))
90 }
91
92 fn is_percentage(&self) -> bool {
93 self.trim().eq("%")
94 }
95}
96
97impl ChUtils for Token {
98 fn is_number(&self) -> bool {
99 match self.typ {
100 TokenType::NUMBER => true,
101 _ => false,
102 }
103 }
104
105 fn is_point(&self) -> bool {
106 false }
108
109 fn is_plus_or_minus(&self) -> bool {
110 match self.typ {
111 TokenType::PLUS => true,
112 TokenType::MINUS => true,
113 _ => false,
114 }
115 }
116
117 fn is_div_or_prod(&self) -> bool {
118 match self.typ {
119 TokenType::PRODUCT => true,
120 TokenType::DIVIDE => true,
121 _ => false,
122 }
123 }
124
125 fn is_operation_sign(&self) -> bool {
126 self.is_plus_or_minus() || self.is_div_or_prod()
127 }
128
129 fn is_parentheses(&self) -> (bool, bool) {
130 match self.typ {
131 TokenType::LPAREN => (true, false),
132 TokenType::RPAREN => (false, true),
133 _ => (false, false),
134 }
135 }
136
137 fn is_abs(&self) -> (bool, bool) {
138 match self.typ {
139 TokenType::LABS => (true, false),
140 TokenType::RABS => (false, true),
141 _ => (false, false),
142 }
143 }
144
145 fn is_percentage(&self) -> bool {
146 match self.typ {
147 TokenType::PERCENTAGE => true,
148 _ => false,
149 }
150 }
151}
152
153#[cfg(test)]
155mod tests {
156 use super::*;
157 use std::collections::HashMap;
158
159 #[test]
160 fn is_number() {
161 let test_data: HashMap<String, bool> = HashMap::from([
162 (String::from("42"), true),
163 (String::from("-25"), true),
164 (String::from("+50"), true),
165 (String::from("-"), false),
166 (String::from("+"), false),
167 (String::from("/"), false),
168 ]);
169
170 for (target, expected) in test_data {
171 assert_eq!(target.is_number(), expected);
172 assert_eq!(Token::from(target, (0, 0)).is_number(), expected);
173 }
174 }
175
176 #[test]
177 fn is_point() {
178 let test_data: HashMap<String, bool> = HashMap::from([
179 (String::from("."), true),
180 (String::from(","), true),
181 (String::from("-"), false),
182 (String::from("+"), false),
183 (String::from("/"), false),
184 (String::from("5"), false),
185 ]);
186
187 for (target, expected) in test_data {
188 assert_eq!(target.is_point(), expected);
189 }
190 }
191
192 #[test]
193 fn is_plus_or_minus() {
194 let test_data: HashMap<String, bool> = HashMap::from([
195 (String::from("-"), true),
196 (String::from("+"), true),
197 (String::from("/"), false),
198 (String::from(".5"), false),
199 (String::from("/"), false),
200 (String::from("*"), false),
201 ]);
202
203 for (target, expected) in test_data {
204 assert_eq!(target.is_plus_or_minus(), expected);
205 assert_eq!(Token::from(target, (0, 0)).is_plus_or_minus(), expected);
206 }
207 }
208
209 #[test]
210 fn is_div_or_prod() {
211 let test_data: HashMap<String, bool> = HashMap::from([
212 (String::from("/"), true),
213 (String::from("*"), true),
214 (String::from(":"), true),
215 (String::from("•"), true),
216 (String::from("-"), false),
217 (String::from("+"), false),
218 (String::from(".5"), false),
219 ]);
220
221 for (target, expected) in test_data {
222 assert_eq!(target.is_div_or_prod(), expected);
223 assert_eq!(Token::from(target, (0, 0)).is_div_or_prod(), expected);
224 }
225 }
226
227 #[test]
228 fn is_operation_sign() {
229 let test_data: HashMap<String, bool> = HashMap::from([
230 (String::from("/"), true),
231 (String::from("*"), true),
232 (String::from(":"), true),
233 (String::from("•"), true),
234 (String::from("-"), true),
235 (String::from("+"), true),
236 (String::from("5"), false),
237 (String::from("."), false),
238 (String::from(","), false),
239 ]);
240
241 for (target, expected) in test_data {
242 assert_eq!(target.is_operation_sign(), expected);
243 assert_eq!(Token::from(target, (0, 0)).is_operation_sign(), expected);
244 }
245 }
246
247 #[test]
248 fn is_parentheses() {
249 let test_data: HashMap<String, (bool, bool)> = HashMap::from([
250 (String::from("/"), (false, false)),
251 (String::from("*"), (false, false)),
252 (String::from(":"), (false, false)),
253 (String::from("•"), (false, false)),
254 (String::from("-"), (false, false)),
255 (String::from("+"), (false, false)),
256 (String::from("5"), (false, false)),
257 (String::from(")"), (false, true)),
258 (String::from("("), (true, false)),
259 ]);
260
261 for (target, expected) in test_data {
262 assert_eq!(target.is_parentheses(), expected);
263 assert_eq!(Token::from(target, (0, 0)).is_parentheses(), expected);
264 }
265 }
266
267 #[test]
268 fn is_abs() {
269 let test_data: HashMap<String, (bool, bool)> = HashMap::from([
270 (String::from("/"), (false, false)),
271 (String::from("*"), (false, false)),
272 (String::from(":"), (false, false)),
273 (String::from("•"), (false, false)),
274 (String::from("-"), (false, false)),
275 (String::from("+"), (false, false)),
276 (String::from("5"), (false, false)),
277 (String::from("]"), (false, true)),
278 (String::from("["), (true, false)),
279 ]);
280
281 for (target, expected) in test_data {
282 assert_eq!(target.is_abs(), expected);
283 assert_eq!(Token::from(target, (0, 0)).is_abs(), expected);
284 }
285 }
286
287 #[test]
288 fn is_percentage() {
289 let test_data: HashMap<bool, String> = HashMap::from([
290 (false, String::from("-25")),
291 (false, String::from("-")),
292 (false, String::from("(")),
293 (true, String::from("%")),
294 ]);
295
296 for (expected, data) in test_data {
297 assert_eq!(expected, data.is_percentage());
298 assert_eq!(expected, Token::from(data, (0, 0)).is_percentage());
299 }
300 }
301}