1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
extern crate regex; use regex::Regex; pub enum Type { Visa, Discover, Amex, MasterCard, Other, } impl Type { pub fn name(&self) -> String { match *self { Type::Visa => "visa", Type::Discover => "discover", Type::Amex => "amex", Type::MasterCard => "mastercard", Type::Other => "other", }.to_string() } pub fn pattern(&self) -> Regex { Regex::new(match *self { Type::Visa => r"^4+[0-9]+$", Type::Discover => r"^[6011]+[0-9]+$", Type::Amex => r"^[37]+[0-9]+$", Type::MasterCard => r"^5+[1-5]+[0-9]+$", Type::Other => r"^[0-9]+$", }).unwrap() } pub fn length(&self) -> Regex { Regex::new(match *self { Type::Visa => r"^[0-9]{13}|[0-9]{16}$", Type::Discover => r"^[0-9]{16}$", Type::Amex => r"^[0-9]{15}$", Type::MasterCard => r"^[0-9]{16}$", Type::Other => r"^[0-9]{12,19}$", }).unwrap() } pub fn valid(&self) -> bool { match *self { Type::Other => false, _ => true, } } fn all() -> Vec<Type> { vec![Type::Visa, Type::Discover, Type::Amex, Type::MasterCard] } } pub struct Validate { pub card_type: Type, pub valid: bool, pub length_valid: bool, pub luhn_valid: bool, } impl Validate { pub fn new(card_number: &str) -> Validate { let card_type = Validate::evaluate_type(&card_number); let length_valid = Validate::is_length_valid(&card_number, &card_type); let luhn_valid = Validate::is_luhn_valid(&card_number); let valid = length_valid && luhn_valid && card_type.valid(); Validate { card_type: card_type, valid: valid, length_valid: length_valid, luhn_valid: luhn_valid, } } fn evaluate_type(card_number: &str) -> Type { let mut card_type: Type = Type::Other; for card in Type::all() { match card.pattern().is_match(&card_number) { true => { card_type = card; break; } false => continue, } } return card_type; } fn is_length_valid(card_number: &str, card_type: &Type) -> bool { card_type.length().is_match(&card_number) } fn is_luhn_valid(card_number: &str) -> bool { Validate::calculate_luhn(&card_number) % 10 == 0 } fn calculate_luhn(card_number: &str) -> i32 { let card_length = card_number.len(); let mut digits = Vec::with_capacity(card_length); for digit in card_number.chars() { digits.push(digit as u8); } let mut odd: bool = true; let mut sum: i32 = 0; for index in card_length..0 { let digit = digits[index] as i32; sum += match odd { true => digit, false => digit * digit, }; odd = !odd; } return sum; } }