1extern crate num;
43
44use std::{ops, fmt, str, error};
45
46use num::bigint::{BigInt, BigUint, Sign};
47use num::Zero;
48use num::traits::FromPrimitive;
49
50const DECIMAL_PLACES: usize = 2;
51const SECTION_LEN: usize = 3; #[derive(Debug, Clone, Hash, Default, PartialEq, Eq, PartialOrd)]
57pub struct Currency {
58 symbol: Option<char>,
59 coin: BigInt
60}
61
62impl Currency {
63 pub fn new() -> Self {
65 Currency {
66 symbol: None,
67 coin: BigInt::zero()
68 }
69 }
70
71 pub fn from_str(s: &str) -> Result<Currency, ParseCurrencyError> {
84 use std::str::FromStr;
85 use num::bigint::{BigUint, Sign};
86
87 let err = ParseCurrencyError::new(s);
88
89 fn is_symbol(c: char) -> bool {
90 !c.is_digit(10) && c != '-' && c != '.' && c != ','
91 }
92
93 fn is_delimiter(c: char) -> bool {
94 c == '.' || c == ','
95 }
96
97 let mut digits = String::new();
98 let mut symbol = None;
99 let mut sign = Sign::Plus;
100
101 let mut last_delimiter = None;
102 let mut last_streak_len = 0;
103 for c in s.chars() {
104 if c == '-' && digits.len() == 0 {
105 sign = Sign::Minus;
106 } else if is_delimiter(c) {
107 last_streak_len = 0;
108 last_delimiter = Some(c);
109 } else if is_symbol(c) {
110 if symbol.is_none() {
111 symbol = Some(c);
112 }
113 } else {
114 last_streak_len += 1;
115 digits.push(c);
116 }
117 }
118
119 let unsigned_bigint = if digits.len() > 0 {
120 let parse_result = BigUint::from_str(&digits);
121 match parse_result {
122 Ok(int) => int,
123 Err(_) => {
124 println!("{:?}", digits);
125 return Err(err)
126 }
127 }
128 } else {
129 BigUint::zero()
130 };
131 let mut coin = BigInt::from_biguint(sign, unsigned_bigint);
132
133 if last_delimiter.is_none() || last_streak_len == 3 { let big_int_factor = BigInt::from(100);
136 coin = coin * big_int_factor;
137 } else if last_streak_len < 2 { let factor = 10u32.pow(2 - last_streak_len);
139 let big_int_factor = BigInt::from(factor);
140 coin = coin * big_int_factor;
141 } else if last_streak_len > 2 { let divisor = 10u32.pow(last_streak_len - 2);
143 let big_int = BigInt::from(divisor);
144 coin = coin / big_int;
145 } let currency = Currency {
148 symbol: symbol,
149 coin: coin
150 };
151
152 Ok(currency)
153 }
154
155 pub fn sign(&self) -> Sign {
157 self.coin.sign()
158 }
159
160 pub fn value(&self) -> &BigInt {
182 &self.coin
183 }
184
185 pub fn convert(&self, conversion_rate: f64, currency_symbol: char) -> Currency {
199 let mut result = self * conversion_rate;
200 result.symbol = Some(currency_symbol);
201 result
202 }
203
204 }
208
209impl fmt::Display for Currency {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 use num::traits::Signed;
230
231 let mut result = String::new();
232
233 if self.coin.sign() == Sign::Minus {
234 result.push('-');
235 }
236
237 if self.symbol.is_some() {
238 result.push(self.symbol.unwrap());
239 }
240
241 let digit_str = self.coin.abs().to_str_radix(10);
242
243 let n_digits = digit_str.len();
245 if n_digits <= DECIMAL_PLACES { result.push_str("0.");
247 if n_digits == 1 {
248 result.push('0');
249 }
250 result.push_str(&digit_str);
251 } else {
252 let n_before_dec = n_digits - DECIMAL_PLACES;
253 let int_digit_str = &digit_str[0..n_before_dec];
254 let dec_digit_str = &digit_str[n_before_dec..n_digits];
255
256 let first_section_len = n_before_dec % SECTION_LEN;
257 let mut counter = SECTION_LEN - first_section_len;
258 for digit in int_digit_str.chars() {
259 if counter == SECTION_LEN && n_digits > 5{
260 counter = 0;
261 result.push(',');
262 }
263 result.push(digit);
264 counter += 1;
265 }
266 result.push('.');
267 result.push_str(dec_digit_str);
268 }
269
270 write!(f, "{}", result)
271 }
272}
273
274impl str::FromStr for Currency {
275 type Err = ParseCurrencyError;
276
277 fn from_str(s: &str) -> Result<Currency, ParseCurrencyError> {
278 Currency::from_str(s)
279 }
280}
281
282#[derive(Debug, Clone, PartialEq)]
283pub struct ParseCurrencyError {
284 source: String
285}
286
287impl ParseCurrencyError {
288 fn new(s: &str) -> Self {
289 ParseCurrencyError {
290 source: s.to_string()
291 }
292 }
293}
294
295impl fmt::Display for ParseCurrencyError {
296 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297 write!(f, "Could not parse {} into a currency.", self.source)
298 }
299}
300
301impl error::Error for ParseCurrencyError {
302 fn description(&self) -> &str {
303 "Failed to parse currency"
304 }
305}
306
307impl fmt::LowerExp for Currency {
323 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
324 let temp = format!("{}", self).replace(".", "x");
325 let almost = temp.replace(",", ".");
326 let there_we_go = almost.replace("x", ",");
327 write!(f, "{}", there_we_go)
328 }
329}
330
331macro_rules! impl_all_trait_combinations_for_currency {
337 ($module:ident::$imp:ident, $method:ident) => {
338 impl<'a, 'b> $module::$imp<&'b Currency> for &'a Currency {
339 type Output = Currency;
340
341 #[inline]
342 fn $method(self, other: &'b Currency) -> Currency {
343 if self.symbol == other.symbol {
344 Currency {
345 symbol: self.symbol.clone(),
346 coin: self.coin.clone().$method(other.coin.clone())
347 }
348 } else {
349 panic!("Cannot do arithmetic on two different types of currency.");
350 }
351 }
352 }
353
354 impl<'a> $module::$imp<Currency> for &'a Currency {
355 type Output = Currency;
356
357 #[inline]
358 fn $method(self, other: Currency) -> Currency {
359 if self.symbol == other.symbol {
360 Currency {
361 symbol: self.symbol.clone(),
362 coin: self.coin.clone().$method(other.coin)
363 }
364 } else {
365 panic!("Cannot do arithmetic on two different types of currency.");
366 }
367 }
368 }
369
370 impl<'a> $module::$imp<&'a Currency> for Currency {
371 type Output = Currency;
372
373 #[inline]
374 fn $method(self, other: &'a Currency) -> Currency {
375 if self.symbol == other.symbol {
376 Currency {
377 symbol: self.symbol,
378 coin: self.coin.$method(other.coin.clone())
379 }
380 } else {
381 panic!("Cannot do arithmetic on two different types of currency.");
382 }
383 }
384 }
385
386 impl $module::$imp<Currency> for Currency {
387 type Output = Currency;
388
389 #[inline]
390 fn $method(self, other: Currency) -> Currency {
391 if self.symbol == other.symbol {
392 Currency {
393 symbol: self.symbol,
394 coin: self.coin.$method(other.coin)
395 }
396 } else {
397 panic!("Cannot do arithmetic on two different types of currency.");
398 }
399 }
400 }
401 }
402}
403
404impl_all_trait_combinations_for_currency!(ops::Add, add);
405impl_all_trait_combinations_for_currency!(ops::Sub, sub);
406macro_rules! impl_all_trait_combinations_for_currency_into_bigint {
410 ($module:ident::$imp:ident, $method:ident, $other:ty) => {
411 impl<'a, 'b> $module::$imp<&'b $other> for &'a Currency {
412 type Output = Currency;
413
414 #[inline]
415 fn $method(self, other: &'b $other) -> Currency {
416 let big_int: BigInt = other.clone().into();
417 Currency {
418 symbol: self.symbol.clone(),
419 coin: self.coin.clone().$method(big_int)
420 }
421 }
422 }
423
424 impl<'a> $module::$imp<$other> for &'a Currency {
425 type Output = Currency;
426
427 #[inline]
428 fn $method(self, other: $other) -> Currency {
429 let big_int: BigInt = other.into();
430 Currency {
431 symbol: self.symbol.clone(),
432 coin: self.coin.clone().$method(big_int)
433 }
434 }
435 }
436
437 impl<'a> $module::$imp<&'a $other> for Currency {
438 type Output = Currency;
439
440 #[inline]
441 fn $method(self, other: &'a $other) -> Currency {
442 let big_int: BigInt = other.clone().into();
443 Currency {
444 symbol: self.symbol,
445 coin: self.coin.$method(big_int)
446 }
447 }
448 }
449
450 impl $module::$imp<$other> for Currency {
451 type Output = Currency;
452
453 #[inline]
454 fn $method(self, other: $other) -> Currency {
455 let big_int: BigInt = other.into();
456 Currency {
457 symbol: self.symbol,
458 coin: self.coin.$method(big_int)
459 }
460 }
461 }
462
463 impl<'a, 'b> $module::$imp<&'b Currency> for &'a $other {
464 type Output = Currency;
465
466 #[inline]
467 fn $method(self, other: &'b Currency) -> Currency {
468 let big_int: BigInt = self.clone().into();
469 Currency {
470 symbol: other.symbol.clone(),
471 coin: other.coin.clone().$method(big_int)
472 }
473 }
474 }
475
476 impl<'a> $module::$imp<Currency> for &'a $other {
477 type Output = Currency;
478
479 #[inline]
480 fn $method(self, other: Currency) -> Currency {
481 let big_int: BigInt = self.clone().into();
482 Currency {
483 symbol: other.symbol,
484 coin: other.coin.$method(big_int)
485 }
486 }
487 }
488
489 impl<'a> $module::$imp<&'a Currency> for $other {
490 type Output = Currency;
491
492 #[inline]
493 fn $method(self, other: &'a Currency) -> Currency {
494 let big_int: BigInt = self.into();
495 Currency {
496 symbol: other.symbol.clone(),
497 coin: other.coin.clone().$method(big_int)
498 }
499 }
500 }
501
502 impl $module::$imp<Currency> for $other {
503 type Output = Currency;
504
505 #[inline]
506 fn $method(self, other: Currency) -> Currency {
507 let big_int: BigInt = self.into();
508 Currency {
509 symbol: other.symbol,
510 coin: other.coin.$method(big_int)
511 }
512 }
513 }
514 }
515}
516
517impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, BigUint);
518impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, u8);
519impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, u16);
520impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, u32);
521impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, u64);
522impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, usize);
523impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, i8);
524impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, i16);
525impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, i32);
526impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, i64);
527impl_all_trait_combinations_for_currency_into_bigint!(ops::Mul, mul, isize);
528
529impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, BigUint);
530impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, u8);
531impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, u16);
532impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, u32);
533impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, u64);
534impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, usize);
535impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, i8);
536impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, i16);
537impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, i32);
538impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, i64);
539impl_all_trait_combinations_for_currency_into_bigint!(ops::Div, div, isize);
540
541macro_rules! impl_all_trait_combinations_for_currency_conv_bigint {
542 ($module:ident::$imp:ident, $method:ident, $other:ty, $conv_method:ident) => {
543 impl<'a, 'b> $module::$imp<&'b $other> for &'a Currency {
544 type Output = Currency;
545
546 #[inline]
547 fn $method(self, other: &'b $other) -> Currency {
548 let big_int = BigInt::$conv_method(other.clone() * 100.0).unwrap();
549 Currency {
550 symbol: self.symbol.clone(),
551 coin: self.coin.clone().$method(big_int) / BigInt::from(100)
552 }
553 }
554 }
555
556 impl<'a> $module::$imp<$other> for &'a Currency {
557 type Output = Currency;
558
559 #[inline]
560 fn $method(self, other: $other) -> Currency {
561 let big_int = BigInt::$conv_method(other * 100.0).unwrap();
562 Currency {
563 symbol: self.symbol.clone(),
564 coin: self.coin.clone().$method(big_int) / BigInt::from(100)
565 }
566 }
567 }
568
569 impl<'a> $module::$imp<&'a $other> for Currency {
570 type Output = Currency;
571
572 #[inline]
573 fn $method(self, other: &'a $other) -> Currency {
574 let big_int = BigInt::$conv_method(other.clone() * 100.0).unwrap();
575 Currency {
576 symbol: self.symbol,
577 coin: self.coin.$method(big_int) / BigInt::from(100)
578 }
579 }
580 }
581
582 impl $module::$imp<$other> for Currency {
583 type Output = Currency;
584
585 #[inline]
586 fn $method(self, other: $other) -> Currency {
587 let big_int = BigInt::$conv_method(other * 100.0).unwrap();
588 Currency {
589 symbol: self.symbol,
590 coin: self.coin.$method(big_int) / BigInt::from(100)
591 }
592 }
593 }
594
595 impl<'a, 'b> $module::$imp<&'b Currency> for &'a $other {
596 type Output = Currency;
597
598 #[inline]
599 fn $method(self, other: &'b Currency) -> Currency {
600 let big_int = BigInt::$conv_method(self.clone() * 100.0).unwrap();
601 Currency {
602 symbol: other.symbol.clone(),
603 coin: other.coin.clone().$method(big_int) / BigInt::from(100)
604 }
605 }
606 }
607
608 impl<'a> $module::$imp<Currency> for &'a $other {
609 type Output = Currency;
610
611 #[inline]
612 fn $method(self, other: Currency) -> Currency {
613 let big_int = BigInt::$conv_method(self.clone() * 100.0).unwrap();
614 Currency {
615 symbol: other.symbol,
616 coin: other.coin.$method(big_int) / BigInt::from(100)
617 }
618 }
619 }
620
621 impl<'a> $module::$imp<&'a Currency> for $other {
622 type Output = Currency;
623
624 #[inline]
625 fn $method(self, other: &'a Currency) -> Currency {
626 let big_int = BigInt::$conv_method(self * 100.0).unwrap();
627 Currency {
628 symbol: other.symbol.clone(),
629 coin: other.coin.clone().$method(big_int) / BigInt::from(100)
630 }
631 }
632 }
633
634 impl $module::$imp<Currency> for $other {
635 type Output = Currency;
636
637 #[inline]
638 fn $method(self, other: Currency) -> Currency {
639 let big_int = BigInt::$conv_method(self * 100.0).unwrap();
640 Currency {
641 symbol: other.symbol,
642 coin: other.coin.$method(big_int) / BigInt::from(100)
643 }
644 }
645 }
646 }
647}
648
649impl_all_trait_combinations_for_currency_conv_bigint!(ops::Mul, mul, f32, from_f32);
650impl_all_trait_combinations_for_currency_conv_bigint!(ops::Mul, mul, f64, from_f64);
651
652impl_all_trait_combinations_for_currency_conv_bigint!(ops::Div, div, f32, from_f32);
653impl_all_trait_combinations_for_currency_conv_bigint!(ops::Div, div, f64, from_f64);
654
655impl<'a, 'b> ops::Div<&'b Currency> for &'a Currency {
660 type Output = BigInt;
661
662 fn div(self, other: &'b Currency) -> BigInt {
663 if self.symbol == other.symbol {
664 self.coin.clone() / other.coin.clone()
665 } else {
666 panic!("Cannot divide two different types of currency.");
667 }
668 }
669}
670
671impl<'a> ops::Div<Currency> for &'a Currency {
676 type Output = BigInt;
677
678 fn div(self, other: Currency) -> BigInt {
679 if self.symbol == other.symbol {
680 self.coin.clone() / other.coin
681 } else {
682 panic!("Cannot divide two different types of currency.");
683 }
684 }
685}
686
687impl<'a> ops::Div<&'a Currency> for Currency {
692 type Output = BigInt;
693
694 fn div(self, other: &'a Currency) -> BigInt {
695 if self.symbol == other.symbol {
696 self.coin / other.coin.clone()
697 } else {
698 panic!("Cannot divide two different types of currency.");
699 }
700 }
701}
702
703impl ops::Div<Currency> for Currency {
708 type Output = BigInt;
709
710 fn div(self, other: Currency) -> BigInt {
711 if self.symbol == other.symbol {
712 self.coin / other.coin
713 } else {
714 panic!("Cannot divide two different types of currency.");
715 }
716 }
717}
718
719impl ops::Neg for Currency {
720 type Output = Currency;
721
722 fn neg(self) -> Currency {
723 Currency {
724 symbol: self.symbol,
725 coin: -self.coin
726 }
727 }
728}
729
730impl<'a> ops::Neg for &'a Currency {
731 type Output = Currency;
732
733 fn neg(self) -> Currency {
734 Currency {
735 symbol: self.symbol.clone(),
736 coin: -self.coin.clone()
737 }
738 }
739}
740
741#[cfg(test)]
746mod tests {
747 use super::Currency;
748 use num::bigint::BigInt;
749
750 #[test]
751 fn test_from_str() {
752 let expected = Currency { symbol: Some('$'), coin: BigInt::from(1210) };
753 let actual = Currency::from_str("$12.10").unwrap();
754 assert_eq!(expected, actual);
755 let actual = Currency::from_str("$12.100000").unwrap();
756 assert_eq!(expected, actual);
757 let actual = Currency::from_str("$12.1").unwrap();
758 assert_eq!(expected, actual);
759
760 let expected = Currency { symbol: None, coin: BigInt::from(1210) };
761 let actual = Currency::from_str("12.10").unwrap();
762 assert_eq!(expected, actual);
763 let actual = Currency::from_str("12.100000").unwrap();
764 assert_eq!(expected, actual);
765 let actual = Currency::from_str("12.1").unwrap();
766 assert_eq!(expected, actual);
767
768 let expected = Currency { symbol: Some('$'), coin: BigInt::from(121000) };
769 let actual = Currency::from_str("$1210").unwrap();
770 assert_eq!(expected, actual);
771 let actual = Currency::from_str("$1,210").unwrap();
772 assert_eq!(expected, actual);
773 let actual = Currency::from_str("$1,210.00").unwrap();
774 assert_eq!(expected, actual);
775 let actual = Currency::from_str("$1210.").unwrap();
776 assert_eq!(expected, actual);
777 let actual = Currency::from_str("$1,210.0").unwrap();
778 assert_eq!(expected, actual);
779 let actual = Currency::from_str("$1.210,0").unwrap();
780 assert_eq!(expected, actual);
781
782 let expected = Currency { symbol: Some('$'), coin: BigInt::from(1200099) };
783 let actual = Currency::from_str("$12,000.99").unwrap();
784 assert_eq!(expected, actual);
785
786 let expected = Currency { symbol: Some('£'), coin: BigInt::from(1200099) };
787 let actual = Currency::from_str("£12,000.99").unwrap();
788 assert_eq!(expected, actual);
789
790 let expected = Currency { symbol: Some('$'), coin: BigInt::from(-1210) };
791 let actual = Currency::from_str("-$12.10").unwrap();
792 assert_eq!(expected, actual);
793 let actual = Currency::from_str("$-12.10").unwrap();
794 assert_eq!(expected, actual);
795
796 let expected = Currency { symbol: Some('€'), coin: BigInt::from(-12000) };
797 let actual = Currency::from_str("-€120.00").unwrap();
798 assert_eq!(expected, actual);
799 let actual = Currency::from_str("-€120").unwrap();
800 assert_eq!(expected, actual);
801 let actual = Currency::from_str("-€-120.0").unwrap();
802 assert_eq!(expected, actual);
803 let actual = Currency::from_str("-€120").unwrap();
804 assert_eq!(expected, actual);
805
806 let expected = Currency { symbol: Some('€'), coin: BigInt::from(0) };
807 let actual = Currency::from_str("€0").unwrap();
808 assert_eq!(expected, actual);
809 let actual = Currency::from_str("€00.00").unwrap();
810 assert_eq!(expected, actual);
811 let actual = Currency::from_str("€.00000000").unwrap();
812 assert_eq!(expected, actual);
813 let actual = Currency::from_str("€0.0").unwrap();
814 assert_eq!(expected, actual);
815 let actual = Currency::from_str("€000,000.00").unwrap();
816 assert_eq!(expected, actual);
817 let actual = Currency::from_str("€000,000").unwrap();
818 assert_eq!(expected, actual);
819 let actual = Currency::from_str("€").unwrap();
820 assert_eq!(expected, actual);
821
822 let expected = Currency { symbol: Some('$'), coin: BigInt::from(1000) };
823 let actual = Currency::from_str("$10.0001").unwrap();
824 assert_eq!(expected, actual);
825
826 }
831
832 #[test]
833 fn test_eq() {
834 let a = Currency { symbol: Some('$'), coin: BigInt::from(1210) };
835 let b = Currency { symbol: Some('$'), coin: BigInt::from(1210) };
836 let c = Currency { symbol: Some('$'), coin: BigInt::from(1251) };
837
838 assert!(a == b);
839 assert!(b == b);
840 assert!(b == a);
841 assert!(a != c);
842 }
843
844 #[test]
845 fn test_ord() {
846 use std::cmp::Ordering;
847
848 let a = Currency { symbol: Some('$'), coin: BigInt::from(1210) };
849 let b = Currency { symbol: Some('$'), coin: BigInt::from(1211) };
850 let c = Currency { symbol: Some('$'), coin: BigInt::from(1311) };
851 let d = Currency { symbol: Some('$'), coin: BigInt::from(1210) };
852
853 assert_eq!(a.partial_cmp(&b), Some(Ordering::Less));
854 assert_eq!(a.partial_cmp(&c), Some(Ordering::Less));
855 assert_eq!(a.partial_cmp(&d), Some(Ordering::Equal));
856 assert_eq!(c.partial_cmp(&a), Some(Ordering::Greater));
857
858 assert!(a < b);
859 assert!(a < c);
860 assert!(a <= a);
861 assert!(a <= c);
862 assert!(b > a);
863 assert!(c > a);
864 assert!(a >= a);
865 assert!(c >= a);
866 }
867
868 #[test]
869 fn test_add() {
870 let a = Currency { symbol: Some('$'), coin: BigInt::from(1211) };
871 let b = Currency { symbol: Some('$'), coin: BigInt::from(1311) };
872 let expected_sum = Currency { symbol: Some('$'), coin: BigInt::from(2522) };
873 let actual_sum = a + b;
874 assert_eq!(expected_sum, actual_sum);
875 }
876
877 #[test]
878 fn test_add_commutative() {
879 let a = Currency { symbol: Some('$'), coin: BigInt::from(1211) };
880 let b = Currency { symbol: Some('$'), coin: BigInt::from(1311) };
881 assert!(&a + &b == &b + &a);
882 }
883
884 #[test]
885 fn test_sub() {
886 let a = Currency { symbol: Some('$'), coin: BigInt::from(1211) };
887 let b = Currency { symbol: Some('$'), coin: BigInt::from(1311) };
888
889 let expected = Currency { symbol: Some('$'), coin: BigInt::from(-100) };
890 let actual = &a - &b;
891 assert_eq!(expected, actual);
892
893 let expected = Currency { symbol: Some('$'), coin: BigInt::from(100) };
894 let actual = b - a;
895 assert_eq!(expected, actual);
896 }
897
898 #[test]
899 fn test_mul() {
900 let a = Currency { symbol: Some('$'), coin: BigInt::from(1211) };
901 let f = 0.97;
902 let expected = Currency { symbol: Some('$'), coin: BigInt::from(1174) };
903 let actual = a * f;
904 assert_eq!(expected, actual);
905 }
906
907 #[test]
908 fn test_mul_commutative() {
909 let a = Currency { symbol: Some('$'), coin: BigInt::from(1211) };
910 let f = 0.97;
911 assert_eq!(&a * &f, &f * &a);
912 }
913
914 #[test]
915 fn test_div() {
916 let a = Currency { symbol: Some('$'), coin: BigInt::from(2500) };
917 let b = Currency { symbol: Some('$'), coin: BigInt::from(500) };
918 let expected = BigInt::from(5);
919 let actual = a / b;
920 assert_eq!(expected, actual);
921
922 let a = Currency { symbol: Some('$'), coin: BigInt::from(3248) };
923 let b = Currency { symbol: Some('$'), coin: BigInt::from(888) };
924 let expected = BigInt::from(3);
925 let actual = a / b;
926 assert_eq!(expected, actual);
927 }
928
929 #[test]
930 fn test_neg() {
931 let c = Currency { symbol: Some('$'), coin: BigInt::from(3248) };
932 let expected = Currency { symbol: Some('$'), coin: BigInt::from(-3248) };
933 let actual = -c;
934 assert_eq!(expected, actual);
935
936 let c = Currency { symbol: Some('$'), coin: BigInt::from(-3248) };
937 let expected = Currency { symbol: Some('$'), coin: BigInt::from(3248) };
938 let actual = -c;
939 assert_eq!(expected, actual);
940
941 let c = Currency { symbol: Some('$'), coin: BigInt::from(0) };
942 let expected = Currency { symbol: Some('$'), coin: BigInt::from(0) };
943 let actual = -c;
944 assert_eq!(expected, actual);
945 }
946
947 #[test]
948 fn test_convert() {
949 let dollars = Currency::from_str("$12.50").unwrap();
950 let euro_conversion_rate = 0.89;
951 let euros = dollars.convert(euro_conversion_rate, '€');
952 let expected = Currency { symbol: Some('€'), coin: BigInt::from(1112) };
953 assert_eq!(expected, euros);
954 }
955
956 #[test]
957 fn test_display() {
958 use num::traits::Num;
959
960 assert_eq!(
961 Currency { symbol: Some('$'), coin: BigInt::from(0) }.to_string(),
962 "$0.00"
963 );
964
965 assert_eq!(
966 Currency { symbol: Some('$'), coin: BigInt::from(-1) }.to_string(),
967 "-$0.01"
968 );
969
970 assert_eq!(
971 Currency { symbol: None, coin: BigInt::from(11) }.to_string(),
972 "0.11"
973 );
974
975 assert_eq!(
976 Currency { symbol: None, coin: BigInt::from(1210) }.to_string(),
977 "12.10"
978 );
979
980 assert_eq!(
981 Currency { symbol: Some('$'), coin: BigInt::from(1210) }.to_string(),
982 "$12.10"
983 );
984
985 assert_eq!(
986 Currency { symbol: Some('£'), coin: BigInt::from(100010) }.to_string(),
987 "£1,000.10"
988 );
989
990 assert_eq!(
991 Currency {
992 symbol: Some('$'),
993 coin: BigInt::from_str_radix("123456789001", 10).unwrap()
994 }.to_string(),
995 "$1,234,567,890.01"
996 );
997
998 assert_eq!(
999 Currency {
1000 symbol: Some('$'),
1001 coin: BigInt::from_str_radix("-123456789001", 10).unwrap()
1002 }.to_string(),
1003 "-$1,234,567,890.01"
1004 );
1005
1006 let ccy: Currency = "100".parse().unwrap();
1007 assert_eq!(ccy.to_string(), "100.00");
1008
1009 let ccy: Currency = "1200".parse().unwrap();
1010 assert_eq!(ccy.to_string(), "1,200.00");
1011 }
1012
1013 #[test]
1014 fn test_foreign_display() {
1015 assert_eq!(
1016 format!("{:e}", Currency { symbol: Some('£'), coin: BigInt::from(100000) }),
1017 "£1.000,00"
1018 );
1019
1020 assert_eq!(
1021 format!("{:e}", Currency { symbol: Some('£'), coin: BigInt::from(123400101) }),
1022 "£1.234.001,01"
1023 );
1024 }
1025}