use crate::{
common::{
ascii_alphanum_to_u8, calculate_mod, is_ascii_alpha_upper, is_ascii_alphanumeric_upper,
is_ascii_numeric, string_to_numeric_string,
},
Calculator,
};
use std::fmt::Display;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum IsoVariant {
Mod_11_2,
Mod_11_10,
Mod_27_26,
Mod_37_2,
Mod_37_36,
Mod_97_10,
Mod_661_26,
Mod_1271_36,
}
#[derive(Clone, Copy, Debug)]
pub struct CheckDigitAlgorithm {
variant: IsoVariant,
}
pub const fn get_algorithm_instance(variant: IsoVariant) -> CheckDigitAlgorithm {
CheckDigitAlgorithm::new(variant)
}
impl Display for IsoVariant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
impl IsoVariant {
const fn check_digits(&self) -> usize {
match self {
Self::Mod_11_2 => 1,
Self::Mod_11_10 => 1,
Self::Mod_27_26 => 1,
Self::Mod_37_2 => 1,
Self::Mod_37_36 => 1,
Self::Mod_97_10 => 2,
Self::Mod_661_26 => 2,
Self::Mod_1271_36 => 2,
}
}
const fn name(&self) -> &'static str {
match self {
Self::Mod_11_2 => "ISO 7064 - MOD 11-2",
Self::Mod_11_10 => "ISO 7064 - MOD 11,10",
Self::Mod_27_26 => "ISO 7064 - MOD 27,26",
Self::Mod_37_2 => "ISO 7064 - MOD 37-2",
Self::Mod_37_36 => "ISO 7064 - MOD 37,36",
Self::Mod_97_10 => "ISO 7064 - MOD 97-10",
Self::Mod_661_26 => "ISO 7064 - MOD 661-26",
Self::Mod_1271_36 => "ISO 7064 - MOD 1271-36",
}
}
}
impl CheckDigitAlgorithm {
pub const fn new(variant: IsoVariant) -> Self {
Self { variant }
}
}
impl Calculator<u8> for CheckDigitAlgorithm {
fn name(&self) -> &'static str {
self.variant.name()
}
fn number_of_check_digit_chars(&self) -> usize {
self.variant.check_digits()
}
fn calculate(&self, s: &str) -> Result<u8, crate::error::CheckDigitError> {
match self.variant {
IsoVariant::Mod_11_2 => is_ascii_numeric(s)?,
IsoVariant::Mod_27_26 => is_ascii_alpha_upper(s)?,
IsoVariant::Mod_97_10 => {
is_ascii_alphanumeric_upper(s)?;
let s = format!("{}00", string_to_numeric_string(s, ascii_alphanum_to_u8));
return Ok(98 - calculate_mod(&s, 97) as u8);
}
IsoVariant::Mod_661_26 => is_ascii_alpha_upper(s)?,
_ => is_ascii_alphanumeric_upper(s)?,
}
todo!()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_to_string_a36() {
assert_eq!(
&string_to_numeric_string("10BX939C5543TQA1144M999143X", ascii_alphanum_to_u8),
"10113393912554329261011442299914333"
);
}
}