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


pub struct Details {
  sort_code: String,
  account_number: String,
  weights: Vec<i16>,
  exceptions: Vec<i8>
}

fn standard (modulo: i16, details: Details) -> bool {
  let joined = format!("{}{}", details.sort_code, details.account_number);
  let result = joined.chars().enumerate().fold(0, |acc, (i, x) | { acc + ((x.to_digit(10).unwrap() as i16) * details.weights[i]) });
  let rem = result % modulo;
  rem == 0
}

fn double (modulo: i16, details: Details) -> bool {
  let joined = format!("{}{}", details.sort_code, details.account_number);
  let mut result = joined.chars().enumerate().fold(0, |mut acc, (i, x) | {
    let num = (x.to_digit(10).unwrap() as i16) * details.weights[i];
    num.to_string().chars().for_each(|d| { acc = acc + d.to_digit(10).unwrap() as i16 });
    acc
  });
  if details.exceptions.contains(&1) {
    result = result + 27;
  }
  println!("dbl {:?}", result);
  let rem = result % modulo;
  rem == 0
}

pub fn modulus_check(algorithm: &str, details: Details) -> bool {
  match algorithm {
    "mod10" => standard(10, details),
    "mod11" => standard(11, details),
    "dbl" => double(10, details),
    _ => {
      println!("no algorithm");
      false
    }
  } 
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mod10() {
        assert_eq!(modulus_check("mod10", Details { sort_code: String::from("233142"), account_number: String::from("28937089"), weights: vec![ 2, 1, 2, 1, 2, 1, 30, 36, 24, 20, 16, 12, 8, 4 ], exceptions: vec![] }), true);
    }
    #[test]
    fn dbl() {
        assert_eq!(modulus_check("dbl", Details { sort_code: String::from("041314"), account_number: String::from("89917189"), weights: vec![ 1, 3, 4, 3, 9, 3, 1, 7, 5, 5, 4, 5, 2, 4 ], exceptions: vec![] }), true);
    }
}