Skip to content

Instantly share code, notes, and snippets.

@mboeh
Last active November 14, 2018 03:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mboeh/2c1dacdb10d9ec07b7e5b40b7bebb014 to your computer and use it in GitHub Desktop.
Save mboeh/2c1dacdb10d9ec07b7e5b40b7bebb014 to your computer and use it in GitHub Desktop.
toy implementation of Luhn algorithm and credit card prefix check
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