use super::funejson::Value; fn invalid(reason: &str) -> BicCheck { BicCheck { valid: false, normalised: None, institution: None, country: None, location: None, branch: None, reason: Some(reason.to_string()), } } /// Check the format of a BIC and split it into institution, country, location /// and branch. /// /// Well formed is not registered: only SWIFT's directory knows whether the /// code is assigned. Validators answer rather than panic. pub fn validate_bic(value: &str) -> BicCheck { let bic: Vec = value .chars() .filter(|ch| *ch != ' ') .map(|ch| ch.to_ascii_uppercase()) .collect(); if bic.is_empty() { return invalid("empty"); } if bic.iter().any(|ch| !(ch.is_ascii_uppercase() || ch.is_ascii_digit())) { return invalid("bad-character"); } if bic.len() != 8 && bic.len() != 11 { return invalid("bad-length"); } if !bic[4].is_ascii_uppercase() || !bic[5].is_ascii_uppercase() { return invalid("bad-country"); } let part = |from: usize, to: usize| -> Option { Some(bic[from..to].iter().collect()) }; BicCheck { valid: true, normalised: Some(bic.iter().collect()), institution: part(0, 4), country: part(4, 6), location: part(6, 8), // An 8-character BIC is the primary office, which the 11-character form spells XXX. branch: if bic.len() == 11 { part(8, 11) } else { Some("XXX".to_string()) }, reason: None, } } /// Object keys are camelCase to match the shared vectors. pub fn bic_check_to_value(result: &BicCheck) -> Value { let text = |field: &Option| match field { Some(s) => Value::str(s), None => Value::Null, }; Value::obj(vec![ ("valid", Value::Bool(result.valid)), ("normalised", text(&result.normalised)), ("institution", text(&result.institution)), ("country", text(&result.country)), ("location", text(&result.location)), ("branch", text(&result.branch)), ("reason", text(&result.reason)), ]) } pub fn fune_vector(args: &[Value]) -> Value { // A non-string argument arrives here as an empty string, which is exactly // the answer TypeScript and Python give for a non-string: empty. bic_check_to_value(&validate_bic(args[0].as_str())) }