///|
fn unit_at(s : String, i : Int) -> String {
s[i:i + 1].to_owned()
}
///|
fn mrz_value(c : UInt16) -> Int {
if c == '<' {
return 0
}
if c >= '0' && c <= '9' {
let digits = "0123456789"
let mut k = 0
while k < 10 {
if digits[k] == c {
return k
}
k += 1
}
}
if c >= 'A' && c <= 'Z' {
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let mut k = 0
while k < 26 {
if letters[k] == c {
return 10 + k
}
k += 1
}
}
-1
}
///|
fn is_mrz_char(c : UInt16) -> Bool {
mrz_value(c) >= 0
}
///|
fn weight_at(i : Int) -> Int {
let r = i % 3
if r == 0 {
7
} else if r == 1 {
3
} else {
1
}
}
///|
fn digit_string(n : Int) -> String {
"0123456789"[n:n + 1].to_owned()
}
///|
/// ICAO 9303 7-3-1 check digit for a field that already uses MRZ characters.
pub fn check_digit(field : String) -> Int? {
let mut sum = 0
let mut i = 0
while i < field.length() {
let v = mrz_value(field[i])
if v < 0 {
return None
}
sum = sum + v * weight_at(i)
i += 1
}
Some(sum % 10)
}
///|
pub fn check_digit_char(field : String) -> String? {
match check_digit(field) {
None => None
Some(n) => Some(digit_string(n))
}
}
///|
fn field_matches_check(field : String, actual : String) -> Bool {
match check_digit_char(field) {
None => false
Some(expected) => expected == actual
}
}