1use std::cmp;
13
14pub fn checked_add(lhs: impl Into<String>, rhs: impl Into<String>) -> Result<String, &'static str> {
29 let lhs: String = lhs.into();
31 let rhs: String = rhs.into();
32 let lhs: &str = lhs.as_str();
33 let rhs: &str = rhs.as_str();
34 let res = check_str(lhs);
35 let res2 = check_str(rhs);
36 if res.is_err() { return Err("LHS is invalid decimal. Please check."); }
37 if res2.is_err() { return Err("RHS is invalid decimal. Please check."); }
38
39 let (lhs_i128, rhs_i128, max_decimal) = convert_to_i128(lhs, rhs);
40
41 let value = lhs_i128.checked_add(rhs_i128);
42 if value.is_none() { return Err("Sorry, i128 add encounters overflow. Please find other methods to add."); }
43
44 let mut value_str: String = value.unwrap().to_string();
46 let insert_loc = value_str.len().checked_sub(max_decimal);
47 if max_decimal != 0 && insert_loc.is_some() {
48 let insert_loc = insert_loc.unwrap();
49 value_str.insert(insert_loc, '.');
50 if insert_loc == 0 { value_str.insert(insert_loc, '0'); }
51 value_str = value_str.trim_end_matches('0').to_owned();
52 };
53 value_str = value_str.trim_end_matches(".").to_owned();
54
55 return Ok(value_str);
56}
57
58
59pub fn checked_sub(lhs: impl Into<String>, rhs: impl Into<String>) -> Result<String, &'static str> {
74 let lhs: String = lhs.into();
75 let rhs: String = rhs.into();
76 let lhs: &str = lhs.as_str();
77 let rhs: &str = rhs.as_str();
78
79 let res = check_str(lhs);
80 let res2 = check_str(rhs);
81 if res.is_err() { return Err("LHS is invalid decimal. Please check."); }
82 if res2.is_err() { return Err("RHS is invalid decimal. Please check."); }
83
84 let (lhs_i128, rhs_i128, max_decimal) = convert_to_i128(lhs, rhs);
85
86 let value = lhs_i128.checked_sub(rhs_i128);
87 if value.is_none() { return Err("Sorry, i128 add encounters overflow. Please find other methods to add."); }
88
89 let mut value_str: String = value.unwrap().to_string();
91 let insert_loc = value_str.len().checked_sub(max_decimal);
92 if max_decimal != 0 && insert_loc.is_some() {
93 let insert_loc = insert_loc.unwrap();
94 value_str.insert(insert_loc, '.');
95 if insert_loc == 0 { value_str.insert(insert_loc, '0'); }
96 value_str = value_str.trim_end_matches('0').to_owned();
97 };
98 value_str = value_str.trim_end_matches(".").to_owned();
99
100 return Ok(value_str);
101}
102
103pub fn checked_mul(lhs: impl Into<String>, rhs: impl Into<String>) -> Result<String, &'static str> {
118 let lhs: String = lhs.into();
119 let rhs: String = rhs.into();
120 let lhs: &str = lhs.as_str();
121 let rhs: &str = rhs.as_str();
122
123 let res = check_str(lhs);
124 let res2 = check_str(rhs);
125 if res.is_err() { return Err("LHS is invalid decimal. Please check."); }
126 if res2.is_err() { return Err("RHS is invalid decimal. Please check."); }
127
128 let (lhs_i128, rhs_i128, max_decimal) = convert_to_i128(lhs, rhs);
129 let total_decimal = max_decimal.checked_mul(2);
130 if total_decimal.is_none() { return Err("Please report Bug: Failed to multiply total_decimal. "); }
131 let total_decimal = total_decimal.unwrap();
132
133 let value = lhs_i128.checked_mul(rhs_i128);
134 if value.is_none() { return Err("Sorry, i128 add encounters overflow. Please find other methods to add."); }
135
136 let mut value_str: String = value.unwrap().to_string();
138 let insert_loc = value_str.len().checked_sub(total_decimal);
139 if total_decimal != 0 && insert_loc.is_some() {
140 let insert_loc = insert_loc.unwrap();
141 value_str.insert(insert_loc, '.');
142 if insert_loc == 0 { value_str.insert(insert_loc, '0'); }
143 value_str = value_str.trim_end_matches("0").to_owned();
144 };
145 value_str = value_str.trim_end_matches(".").to_owned(); return Ok(value_str)
148}
149
150pub fn compare(lhs: impl Into<String>, rhs: impl Into<String>,
169 comparator: &str
170) -> Result<bool, &'static str> {
171 let lhs: String = lhs.into();
172 let rhs: String = rhs.into();
173 let lhs: &str = lhs.as_str();
174 let rhs: &str = rhs.as_str();
175
176 let res = check_str(lhs);
177 let res2 = check_str(rhs);
178 if res.is_err() { return Err("LHS is invalid decimal. Please check."); }
179 if res2.is_err() { return Err("RHS is invalid decimal. Please check."); }
180
181 let (lhs_i128, rhs_i128, _) = convert_to_i128(lhs, rhs);
182 match comparator {
183 "le" => return Ok(lhs_i128 <= rhs_i128),
184 "ge" => return Ok(lhs_i128 >= rhs_i128),
185 "lt" => return Ok(lhs_i128 < rhs_i128),
186 "gt" => return Ok(lhs_i128 > rhs_i128),
187 "eq" => return Ok(lhs_i128 == rhs_i128),
188 _ => return Err("Invalid comparator. Choose between le, ge, lt, gt, and eq.")
189 };
190}
191
192
193pub fn sum(values: Vec<impl Into<String> + Clone>) -> Result<String, &'static str> {
207 let mut _temp_vals: Vec<String> = Vec::new();
208 for i in 0..values.len() {
210 let g: String = values[i].clone().into();
211 _temp_vals.push(g);
212 }
213 let new_values: Vec<&str> = _temp_vals.iter().map(|c| c.as_str()).collect();
215
216 if new_values.iter().any(|c| check_str(*c).is_err()) {
217 return Err("There are values which didn't pass check_str. Please inspect and fix.");
219 }
220
221 let (new_vec, max_decimal) = convert_all_to_i128(new_values);
222
223 let sum_val: i128 = new_vec.iter().sum();
224
225 let mut value_str: String = sum_val.to_string();
227 let insert_loc = value_str.len().checked_sub(max_decimal);
228 if max_decimal != 0 && insert_loc.is_some() {
229 let insert_loc = insert_loc.unwrap();
230 value_str.insert(insert_loc, '.');
231 if insert_loc == 0 { value_str.insert(insert_loc, '0'); }
232 value_str = value_str.trim_end_matches('0').to_owned();
233 };
234 value_str = value_str.trim_end_matches(".").to_owned();
235
236 return Ok(value_str);
237}
238
239
240
241
242fn check_str(str: &str) -> Result<(), &'static str> {
244 let mut dot_count = 0;
245 for c in str.chars() {
246 if !['0', '1', '2', '3', '4', '5', '6',
247 '7', '8', '9', '.', '-'].contains(&c)
248 {
249 return Err("Invalid String. Must be numbers and decimal point only.");
250 }
251
252 if c == '.' { dot_count += 1; }
253 if dot_count > 1 { return Err("Invalid String. Cannot have more than one decimal."); }
254 }
255 return Ok(());
256}
257
258fn get_decimal_points(num: &str) -> usize {
262 let num_len = num.len();
263 let num_di = num.find(".").unwrap_or(num_len - 1);
264 return num_len - (num_di + 1);
265}
266
267fn preprocess_value(num: &str, curr_d: usize, max_d: usize) -> String {
274 let mut num_str = num.to_owned();
275 let num_di = num.find(".");
276 if num_di.is_some() { num_str.remove(num_di.unwrap()); }
277
278 let repeat_no = max_d - curr_d;
280 if repeat_no >= 1 {
281 for _ in 0..repeat_no {
282 num_str.push('0');
283 }
284 }
285
286 return num_str;
287}
288
289fn convert_to_i128(lhs: &str, rhs: &str) -> (i128, i128, usize) {
291 let lhs_decimals = get_decimal_points(lhs);
292 let rhs_decimals = get_decimal_points(rhs);
293 let max_decimal = cmp::max(lhs_decimals, rhs_decimals);
294
295 let lhs_int = preprocess_value(lhs, lhs_decimals, max_decimal);
297 let rhs_int = preprocess_value(rhs, rhs_decimals, max_decimal);
298
299 let lhs_i128: i128 = lhs_int.parse().unwrap();
300 let rhs_i128: i128 = rhs_int.parse().unwrap();
301
302 return (lhs_i128, rhs_i128, max_decimal);
303}
304
305fn convert_all_to_i128(our_vec: Vec<&str>) -> (Vec<i128>, usize) {
309 let decimals: Vec<usize> = our_vec.iter()
310 .map(|c| get_decimal_points(*c))
311 .collect();
312 let max_decimal: usize = *decimals.iter().max().unwrap();
313
314 let ret_val: Vec<i128> = our_vec.iter().enumerate().map(|(i, c)| {
315 let value = preprocess_value(c, decimals[i], max_decimal);
316 let value_i128 = value.parse().unwrap();
317 value_i128
318 }).collect();
319
320 return (ret_val, max_decimal);
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326
327 #[test]
328 fn test_alphabets_wont_work() {
329 let result = check_str("123str");
330 assert!(result.is_err());
331 }
332
333 #[test]
334 fn test_char_wont_work() {
335 let result = check_str("我爱你");
336 assert!(result.is_err());
337 }
338
339 #[test]
340 fn test_floats_work() {
341 let result = check_str("12.376");
342 assert!(result.is_ok());
343 }
344
345 #[test]
346 fn test_ip_addr_not_work() {
347 let result = check_str("192.168.10.1");
348 assert!(result.is_err());
349 }
350
351 #[test]
352 fn correct_decimal() {
353 let decimal = get_decimal_points("12.376");
354 assert_eq!(decimal, 3);
355 }
356
357 #[test]
358 fn correct_integer() {
359 let decimal = get_decimal_points("123");
360 assert_eq!(decimal, 0);
361 }
362
363 #[test]
364 fn preprocess_value_case_1() {
365 let value = preprocess_value("12.237", 3, 3);
366 assert_eq!(value, "12237");
367 }
368
369 #[test]
370 fn preprocess_value_case_2() {
371 let value = preprocess_value("12.237", 3, 5);
372 assert_eq!(value, "1223700");
373 }
374
375 #[test]
376 fn preprocess_value_case_3() {
377 let value = preprocess_value("12", 0, 3);
378 assert_eq!(value, "12000");
379 }
380
381 #[test]
382 fn preprocess_value_case_4() {
383 let value = preprocess_value("12", 0, 0);
384 assert_eq!(value, "12");
385 }
386
387 #[test]
388 fn checked_add_case_1() {
389 let value = checked_add("12.32", "15.6");
390 assert_eq!(value.unwrap(), "27.92".to_owned());
391 }
392
393 #[test]
394 fn checked_add_case_2() {
395 let value = checked_add("12.3", "17");
396 assert_eq!(value.unwrap(), "29.3".to_owned());
397 }
398
399 #[test]
400 fn checked_add_case_3() {
401 let value = checked_add("12", "15");
402 assert_eq!(value.unwrap(), "27".to_owned());
403 }
404
405 #[test]
406 fn checked_add_case_4() {
407 let value = checked_add("meh", "12");
408 assert!(value.is_err());
409 }
410
411 #[test]
412 fn checked_add_case_5() {
413 let value = checked_add("12", "meh");
414 assert!(value.is_err());
415 }
416
417 #[test]
421 fn checked_sub_case_1() {
422 let value = checked_sub("12.367", "9.3");
423 assert_eq!(value.unwrap(), "3.067".to_owned());
424 }
425
426 #[test]
427 fn checked_sub_case_2() {
428 let value = checked_sub("12", "6.3");
429 assert_eq!(value.unwrap(), "5.7".to_owned());
430 }
431
432 #[test]
433 fn checked_sub_case_3() {
434 let value = checked_sub("12", "6");
435 assert_eq!(value.unwrap(), "6".to_owned());
436 }
437
438 #[test]
439 fn checked_sub_case_4() {
440 let value = checked_sub("meh", "6");
441 assert!(value.is_err());
442 }
443
444 #[test]
445 fn checked_sub_case_5() {
446 let value = checked_sub("6", "meh");
447 assert!(value.is_err());
448 }
449
450 #[test]
451 fn checked_mul_case_1() {
452 let value = checked_mul("19.87", "13.625");
453 assert_eq!(value.unwrap(), "270.72875".to_owned());
454 }
455
456 #[test]
457 fn checked_mul_case_2() {
458 let value = checked_mul("12.3", "6");
459 let value2 = checked_mul("6", "12.3");
460 assert_eq!(value.clone().unwrap(), "73.8".to_owned());
461 assert_eq!(value.unwrap(), value2.unwrap());
462 }
463
464 #[test]
465 fn checked_mul_case_3() {
466 let value = checked_mul("12.5", "6");
467 assert_eq!(value.unwrap(), "75".to_owned());
468 }
469
470 #[test]
471 fn checked_mul_case_4() {
472 let value = checked_mul("meh", "6");
473 assert!(value.is_err());
474 }
475
476 #[test]
477 fn checked_mul_case_5() {
478 let value = checked_mul("6", "meh");
479 assert!(value.is_err());
480 }
481
482 #[test]
483 fn check_comparator_le() {
484 assert!(compare("12.5", "17.6", "le").unwrap());
485 assert!(!compare("17.6", "12.5", "le").unwrap());
486 assert!(compare("12.5", "12.5", "le").unwrap());
487 }
488
489 #[test]
490 fn check_comparator_lt() {
491 assert!(compare("12.5", "17.6", "lt").unwrap());
492 assert!(!compare("17.6", "12.5", "lt").unwrap());
493 assert!(!compare("12.5", "12.5", "lt").unwrap());
494 }
495
496 #[test]
497 fn check_comparator_ge() {
498 assert!(!compare("12.5", "17.6", "ge").unwrap());
499 assert!(compare("17.6", "12.5", "ge").unwrap());
500 assert!(compare("12.5", "12.5", "ge").unwrap());
501 }
502
503 #[test]
504 fn check_comparator_gt() {
505 assert!(!compare("12.5", "17.6", "gt").unwrap());
506 assert!(compare("17.6", "12.5", "gt").unwrap());
507 assert!(!compare("12.5", "12.5", "gt").unwrap());
508 }
509
510 #[test]
511 fn check_comparator_eq() {
512 assert!(!compare("12.5", "17.6", "eq").unwrap());
513 assert!(!compare("17.6", "12.5", "eq").unwrap());
514 assert!(compare("12.5", "12.5", "eq").unwrap());
515 }
516
517 #[test]
518 fn check_comparator_wrong() {
519 assert!(compare("12.5", "17.6", "meh").is_err());
520 }
521
522 #[test]
523 fn check_after_minus_no_decimal_no_cause_error() {
524 assert!(checked_sub("12.70", "12.7").is_ok());
525 assert_eq!(checked_sub("25.400", "12.8").unwrap(), "12.6".to_owned());
526 assert_eq!(checked_sub("12.8", "11.8".to_owned()).unwrap(), "1".to_owned());
527 assert_eq!(checked_sub("12.8", "12.0000").unwrap(), "0.8".to_owned());
528 assert!(checked_mul("12.52", "0").is_ok());
529 }
530
531 #[test]
532 fn check_string_works_not_only_str() {
533 assert_eq!(checked_add("12.5".to_owned(), "13.70".to_owned()).unwrap(), "26.2".to_owned());
534 assert_eq!(checked_sub("12.5".to_owned(), "9.62".to_owned()).unwrap(), "2.88".to_owned());
535 assert_eq!(checked_mul("12.5".to_owned(), "7.2".to_owned()).unwrap(), "90".to_owned());
536 }
537
538 #[test]
539 fn checked_can_run_negative_numbers() {
540 assert_eq!(checked_sub("12.8", "17.5").unwrap(), "-4.7".to_owned());
541 }
542
543 #[test]
544 fn check_special_case_negative_numbers() {
545 assert_eq!(checked_add("-12.800", "12.8").unwrap(), "0".to_owned());
546 assert_eq!(checked_sub("-12.8", "-12.80").unwrap(), "0".to_owned());
547 assert_eq!(checked_sub("-12.8", "-11.0").unwrap(), "-1.8".to_owned());
548 assert_eq!(checked_add("12.8", "-12.0000").unwrap(), "0.8".to_owned());
549 }
550
551 #[test]
552 fn check_convert_all_to_i128_works() {
553 let vec: Vec<&str> = vec!["12.368", "1.14", "28"];
554 let (new_vec, max_decimal) = convert_all_to_i128(vec);
555 assert_eq!(new_vec, vec![12368, 1140, 28000]);
556 assert_eq!(max_decimal, 3);
557 }
558
559 #[test]
560 fn check_sum_all_with_negative_numbers() {
561 let vec = vec!["-12.42", "3.87", "2.323"];
562 assert_eq!(sum(vec).unwrap(), "-6.227".to_owned());
563 }
564}