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