#![forbid(unsafe_code)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
pub use crate::country::Country;
pub use crate::error::ValidationError;
use std::str::FromStr;
pub mod country;
pub(crate) mod country_specific;
pub mod error;
#[allow(clippy::all)]
pub(crate) mod u256 {
uint::construct_uint! {
pub(crate) struct U256(4);
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct Iban {
pub country: Country,
pub(crate) raw: String,
}
impl Iban {
pub fn account_number(&self) -> String {
self.country.account_number(&self.raw)
}
pub fn bank_code(&self) -> String {
self.country.bank_code(&self.raw)
}
pub fn country_code(&self) -> String {
self.country.to_string()
}
pub fn raw(&self) -> &str {
&self.raw
}
}
pub fn validate<I: AsRef<str>>(input: I) -> Result<Iban, ValidationError> {
let input = input.as_ref();
let input: String = input.split_whitespace().collect();
if input.len() > 34 {
return Err(ValidationError::TooLong);
};
if !input.chars().all(|ch| ch.is_alphanumeric()) {
return Err(ValidationError::InvalidChar);
};
if input.len() < 2 {
return Err(ValidationError::InvalidCountryCode);
};
let country_code = &input[0..2];
let country = match Country::from_str(country_code) {
Ok(c) => c,
Err(_) => return Err(ValidationError::InvalidCountryCode),
};
if input.len() != country.length() {
return Err(ValidationError::InvalidLength);
}
if !country.format().is_match(&input) {
return Err(ValidationError::InvalidFormat);
}
if !country.custom_validation(&input) {
return Err(ValidationError::CountryCheckFailed);
}
let (start, rest) = input.split_at(4);
let mut rearranged = String::with_capacity(34);
rearranged.push_str(rest);
rearranged.push_str(start);
let mut integer_string = String::with_capacity(34);
for ch in rearranged.chars() {
if ch.is_numeric() {
integer_string.push(ch);
} else {
let x = ch.to_digit(36).unwrap().to_string();
integer_string.push_str(&x)
}
}
let integer = u256::U256::from_dec_str(&integer_string).unwrap();
if integer % 97 != 1.into() {
return Err(ValidationError::InvalidIban);
}
Ok(Iban {
country,
raw: input,
})
}