Last active
November 14, 2018 03:38
-
-
Save mboeh/2c1dacdb10d9ec07b7e5b40b7bebb014 to your computer and use it in GitHub Desktop.
toy implementation of Luhn algorithm and credit card prefix check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::io; | |
use std::io::BufRead; | |
mod luhn { | |
pub fn luhn(cardn: &str) -> bool { | |
let chars : Vec<char> = cardn.chars().collect(); | |
let mut sum = 0; | |
let len = chars.len(); | |
for ridx in 1..=len { | |
match chars[len - ridx].to_digit(10) { | |
Some(digit) => { | |
if ridx % 2 == 1 { | |
sum += digit; | |
} else { | |
let product = digit * 2; | |
sum += product % 10; | |
if product > 9 { | |
sum += product / 10; | |
} | |
} | |
}, | |
None => { return false; } | |
} | |
} | |
sum % 10 == 0 | |
} | |
} | |
mod cards { | |
use std::fmt; | |
use super::luhn::luhn; | |
#[derive(Clone)] | |
pub enum CardType { | |
INVALID, | |
VISA, | |
MASTERCARD, | |
AMEX, | |
UNKNOWN | |
} | |
use CardType::*; | |
impl fmt::Display for CardType { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
match self { | |
INVALID => write!(f, "INVALID"), | |
VISA => write!(f, "VISA"), | |
MASTERCARD => write!(f, "MASTERCARD"), | |
AMEX => write!(f, "AMEX"), | |
UNKNOWN => write!(f, "UNKNOWN"), | |
} | |
} | |
} | |
struct CardPrefix { | |
card: CardType, | |
len: usize, | |
start: i32, | |
end: i32 | |
} | |
impl CardPrefix { | |
fn matches(&self, cardn: &str) -> bool { | |
let pslice = &cardn[0..self.len]; | |
let prefix = pslice.parse::<i32>().unwrap_or(0); | |
prefix >= self.start && prefix <= self.end | |
} | |
} | |
static PREFIXES : [CardPrefix; 4] = [ | |
CardPrefix { card: VISA, len: 1, start: 4, end: 4 }, | |
CardPrefix { card: MASTERCARD, len: 2, start: 50, end: 55 }, | |
CardPrefix { card: AMEX, len: 2, start: 34, end: 34 }, | |
CardPrefix { card: AMEX, len: 2, start: 37, end: 37 } | |
]; | |
pub fn card_type(cardn: &str) -> CardType { | |
if !luhn(&cardn) { | |
return INVALID; | |
} | |
for prefix in &PREFIXES { | |
if prefix.matches(&cardn) { | |
return prefix.card.clone(); | |
} | |
} | |
return UNKNOWN; | |
} | |
} | |
use self::cards::*; | |
fn main() -> Result<(), Box<std::error::Error>> { | |
let stdin = io::stdin(); | |
for cardn in stdin.lock().lines() { | |
let cardn = cardn?; | |
let cardtype = card_type(&cardn); | |
println!("{}: {}", cardn, cardtype); | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment