taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

commit e43225e2e68bc9b5d32755e77165d1ec2502bbc8
parent 4ed98dc57ed48957f9a44fba1b4f40e480d43b05
Author: Antoine A <>
Date:   Fri, 21 Feb 2025 18:28:56 +0100

common: improve iban registry codegen

Diffstat:
Mcommon/taler-common/src/types/iban.rs | 12++++++------
Mcommon/taler-common/src/types/iban/registry.rs | 1056++++++++++++++++++++++---------------------------------------------------------
2 files changed, 302 insertions(+), 766 deletions(-)

diff --git a/common/taler-common/src/types/iban.rs b/common/taler-common/src/types/iban.rs @@ -21,7 +21,7 @@ use std::{ }; pub use registry::Country; -use registry::{IbanC, PatternErr, rng_pattern}; +use registry::{IbanC, PatternErr, check_pattern, rng_pattern}; use super::utils::InlineStr; @@ -62,11 +62,12 @@ impl IBAN { } fn from_raw_parts(country: Country, bban: &[u8]) -> Self { - // Create a iban with an empty digit check + // Create an iban with an empty digit check let mut encoded = InlineStr::try_from_iter( country .as_bytes() - .into_iter() + .iter() + .copied() .chain([b'0', b'0']) .chain(bban.iter().copied()), ) @@ -86,8 +87,7 @@ impl IBAN { } pub fn from_parts(country: Country, bban: &str) -> Self { - assert_eq!(bban.len(), country.bban_len()); // TODO return Result ? - country.bban_check(bban.as_bytes()).unwrap(); // TODO return Result + check_pattern(bban.as_bytes(), country.bban_pattern()).unwrap(); // TODO return Result Self::from_raw_parts(country, bban.as_bytes()) } @@ -166,7 +166,7 @@ impl FromStr for IBAN { } else if !IbanC::A.check(&encoded[0..2]) || !IbanC::N.check(&encoded[2..4]) { Err(IbanErrorKind::Malformed) } else if let Some(country) = Country::from_str(&encoded.as_ref()[..2]) { - if let Err(e) = country.bban_check(&encoded[4..]) { + if let Err(e) = check_pattern(&encoded[4..], country.bban_pattern()) { Err(match e { PatternErr::Len(expected, got) => IbanErrorKind::Size(expected, got), PatternErr::Malformed => IbanErrorKind::Malformed, diff --git a/common/taler-common/src/types/iban/registry.rs b/common/taler-common/src/types/iban/registry.rs @@ -344,97 +344,97 @@ impl Country { } } - pub const fn as_bytes(self) -> [u8; 2] { + pub const fn as_bytes(self) -> &'static [u8; 2] { match self { - AD => [b'A', b'D'], - AE => [b'A', b'E'], - AL => [b'A', b'L'], - AT => [b'A', b'T'], - AZ => [b'A', b'Z'], - BA => [b'B', b'A'], - BE => [b'B', b'E'], - BG => [b'B', b'G'], - BH => [b'B', b'H'], - BI => [b'B', b'I'], - BR => [b'B', b'R'], - BY => [b'B', b'Y'], - CH => [b'C', b'H'], - CR => [b'C', b'R'], - CY => [b'C', b'Y'], - CZ => [b'C', b'Z'], - DE => [b'D', b'E'], - DJ => [b'D', b'J'], - DK => [b'D', b'K'], - DO => [b'D', b'O'], - EE => [b'E', b'E'], - EG => [b'E', b'G'], - ES => [b'E', b'S'], - FI => [b'F', b'I'], - FK => [b'F', b'K'], - FO => [b'F', b'O'], - FR => [b'F', b'R'], - GB => [b'G', b'B'], - GE => [b'G', b'E'], - GI => [b'G', b'I'], - GL => [b'G', b'L'], - GR => [b'G', b'R'], - GT => [b'G', b'T'], - HN => [b'H', b'N'], - HR => [b'H', b'R'], - HU => [b'H', b'U'], - IE => [b'I', b'E'], - IL => [b'I', b'L'], - IQ => [b'I', b'Q'], - IS => [b'I', b'S'], - IT => [b'I', b'T'], - JO => [b'J', b'O'], - KW => [b'K', b'W'], - KZ => [b'K', b'Z'], - LB => [b'L', b'B'], - LC => [b'L', b'C'], - LI => [b'L', b'I'], - LT => [b'L', b'T'], - LU => [b'L', b'U'], - LV => [b'L', b'V'], - LY => [b'L', b'Y'], - MC => [b'M', b'C'], - MD => [b'M', b'D'], - ME => [b'M', b'E'], - MK => [b'M', b'K'], - MN => [b'M', b'N'], - MR => [b'M', b'R'], - MT => [b'M', b'T'], - MU => [b'M', b'U'], - NI => [b'N', b'I'], - NL => [b'N', b'L'], - NO => [b'N', b'O'], - OM => [b'O', b'M'], - PK => [b'P', b'K'], - PL => [b'P', b'L'], - PS => [b'P', b'S'], - PT => [b'P', b'T'], - QA => [b'Q', b'A'], - RO => [b'R', b'O'], - RS => [b'R', b'S'], - RU => [b'R', b'U'], - SA => [b'S', b'A'], - SC => [b'S', b'C'], - SD => [b'S', b'D'], - SE => [b'S', b'E'], - SI => [b'S', b'I'], - SK => [b'S', b'K'], - SM => [b'S', b'M'], - SO => [b'S', b'O'], - ST => [b'S', b'T'], - SV => [b'S', b'V'], - TL => [b'T', b'L'], - TN => [b'T', b'N'], - TR => [b'T', b'R'], - UA => [b'U', b'A'], - VA => [b'V', b'A'], - VG => [b'V', b'G'], - XK => [b'X', b'K'], - YE => [b'Y', b'E'], + AD => b"AD", + AE => b"AE", + AL => b"AL", + AT => b"AT", + AZ => b"AZ", + BA => b"BA", + BE => b"BE", + BG => b"BG", + BH => b"BH", + BI => b"BI", + BR => b"BR", + BY => b"BY", + CH => b"CH", + CR => b"CR", + CY => b"CY", + CZ => b"CZ", + DE => b"DE", + DJ => b"DJ", + DK => b"DK", + DO => b"DO", + EE => b"EE", + EG => b"EG", + ES => b"ES", + FI => b"FI", + FK => b"FK", + FO => b"FO", + FR => b"FR", + GB => b"GB", + GE => b"GE", + GI => b"GI", + GL => b"GL", + GR => b"GR", + GT => b"GT", + HN => b"HN", + HR => b"HR", + HU => b"HU", + IE => b"IE", + IL => b"IL", + IQ => b"IQ", + IS => b"IS", + IT => b"IT", + JO => b"JO", + KW => b"KW", + KZ => b"KZ", + LB => b"LB", + LC => b"LC", + LI => b"LI", + LT => b"LT", + LU => b"LU", + LV => b"LV", + LY => b"LY", + MC => b"MC", + MD => b"MD", + ME => b"ME", + MK => b"MK", + MN => b"MN", + MR => b"MR", + MT => b"MT", + MU => b"MU", + NI => b"NI", + NL => b"NL", + NO => b"NO", + OM => b"OM", + PK => b"PK", + PL => b"PL", + PS => b"PS", + PT => b"PT", + QA => b"QA", + RO => b"RO", + RS => b"RS", + RU => b"RU", + SA => b"SA", + SC => b"SC", + SD => b"SD", + SE => b"SE", + SI => b"SI", + SK => b"SK", + SM => b"SM", + SO => b"SO", + ST => b"ST", + SV => b"SV", + TL => b"TL", + TN => b"TN", + TR => b"TR", + UA => b"UA", + VA => b"VA", + VG => b"VG", + XK => b"XK", + YE => b"YE", } } @@ -818,678 +818,192 @@ impl Country { } } - pub fn bban_check(self, iban_ascii: &[u8]) -> Result<(), PatternErr> { - // IBAN are made of ASCII digits and uppercase - debug_assert!( - iban_ascii - .iter() - .all(|b| b.is_ascii_uppercase() || b.is_ascii_digit()) - ); + pub const fn bank_pattern(self) -> Pattern { + match self { + AD => &[(4, N)], + AE => &[(3, N)], + AL => &[(3, N)], + AT => &[(5, N)], + AZ => &[(4, A)], + BA => &[(3, N)], + BE => &[(3, N)], + BG => &[(4, A)], + BH => &[(4, A)], + BI => &[(5, N)], + BR => &[(8, N)], + BY => &[(4, C)], + CH => &[(5, N)], + CR => &[(4, N)], + CY => &[(3, N)], + CZ => &[(4, N)], + DE => &[(8, N)], + DJ => &[(5, N)], + DK => &[(4, N)], + DO => &[(4, C)], + EE => &[(2, N)], + EG => &[(4, N)], + ES => &[(4, N)], + FI => &[(3, N)], + FK => &[(2, A)], + FO => &[(4, N)], + FR => &[(5, N)], + GB => &[(4, A)], + GE => &[(2, A)], + GI => &[(4, A)], + GL => &[(4, N)], + GR => &[(3, N)], + GT => &[(4, C)], + HN => &[(4, A)], + HR => &[(7, N)], + HU => &[(3, N)], + IE => &[(4, A)], + IL => &[(3, N)], + IQ => &[(4, A)], + IS => &[(2, N)], + IT => &[(5, N)], + JO => &[(4, N)], + KW => &[(4, A)], + KZ => &[(3, N)], + LB => &[(4, A)], + LC => &[(4, A)], + LI => &[(5, N)], + LT => &[(5, N)], + LU => &[(3, N)], + LV => &[(4, A)], + LY => &[(3, N)], + MC => &[(5, N)], + MD => &[(2, C)], + ME => &[(3, N)], + MK => &[(3, N)], + MN => &[(4, N)], + MR => &[(5, N)], + MT => &[(4, A)], + MU => &[(6, C)], + NI => &[(4, A)], + NL => &[(4, A)], + NO => &[(4, N)], + OM => &[(3, N)], + PK => &[(4, A)], + PL => &[], + PS => &[(4, A)], + PT => &[(4, N)], + QA => &[(4, A)], + RO => &[(4, A)], + RS => &[(3, N)], + RU => &[(9, N)], + SA => &[(2, N)], + SC => &[(4, A), (2, N)], + SD => &[(2, N)], + SE => &[(3, N)], + SI => &[(5, N)], + SK => &[(4, N)], + SM => &[(5, N)], + SO => &[(4, N)], + ST => &[(4, N)], + SV => &[(4, A)], + TL => &[(3, N)], + TN => &[(2, N)], + TR => &[(5, N)], + UA => &[(6, N)], + VA => &[(3, N)], + VG => &[(4, A)], + XK => &[(2, N)], + YE => &[(4, A)], + } + } + + pub const fn branch_pattern(self) -> Pattern { match self { - AD => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..8]) || !C.check(&iban_ascii[8..20]) { - return Err(PatternErr::Malformed); - } - } - AE => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..19]) { - return Err(PatternErr::Malformed); - } - } - AL => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..8]) || !C.check(&iban_ascii[8..24]) { - return Err(PatternErr::Malformed); - } - } - AT => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..16]) { - return Err(PatternErr::Malformed); - } - } - AZ => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..24]) { - return Err(PatternErr::Malformed); - } - } - BA => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..16]) { - return Err(PatternErr::Malformed); - } - } - BE => { - if iban_ascii.len() != 12 { - return Err(PatternErr::Len(12, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..12]) { - return Err(PatternErr::Malformed); - } - } - BG => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..10]) - || !C.check(&iban_ascii[10..18]) - { - return Err(PatternErr::Malformed); - } - } - BH => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..18]) { - return Err(PatternErr::Malformed); - } - } - BI => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..23]) { - return Err(PatternErr::Malformed); - } - } - BR => { - if iban_ascii.len() != 25 { - return Err(PatternErr::Len(25, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..23]) - || !A.check(&iban_ascii[23..24]) - || !C.check(&iban_ascii[24..25]) - { - return Err(PatternErr::Malformed); - } - } - BY => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !C.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..8]) - || !C.check(&iban_ascii[8..24]) - { - return Err(PatternErr::Malformed); - } - } - CH => { - if iban_ascii.len() != 17 { - return Err(PatternErr::Len(17, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..5]) || !C.check(&iban_ascii[5..17]) { - return Err(PatternErr::Malformed); - } - } - CR => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..18]) { - return Err(PatternErr::Malformed); - } - } - CY => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..8]) || !C.check(&iban_ascii[8..24]) { - return Err(PatternErr::Malformed); - } - } - CZ => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..20]) { - return Err(PatternErr::Malformed); - } - } - DE => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..18]) { - return Err(PatternErr::Malformed); - } - } - DJ => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..23]) { - return Err(PatternErr::Malformed); - } - } - DK => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..14]) { - return Err(PatternErr::Malformed); - } - } - DO => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !C.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..24]) { - return Err(PatternErr::Malformed); - } - } - EE => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..16]) { - return Err(PatternErr::Malformed); - } - } - EG => { - if iban_ascii.len() != 25 { - return Err(PatternErr::Len(25, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..25]) { - return Err(PatternErr::Malformed); - } - } - ES => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..20]) { - return Err(PatternErr::Malformed); - } - } - FI => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..14]) { - return Err(PatternErr::Malformed); - } - } - FK => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..2]) || !N.check(&iban_ascii[2..14]) { - return Err(PatternErr::Malformed); - } - } - FO => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..14]) { - return Err(PatternErr::Malformed); - } - } - FR => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..10]) - || !C.check(&iban_ascii[10..21]) - || !N.check(&iban_ascii[21..23]) - { - return Err(PatternErr::Malformed); - } - } - GB => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..18]) { - return Err(PatternErr::Malformed); - } - } - GE => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..2]) || !N.check(&iban_ascii[2..18]) { - return Err(PatternErr::Malformed); - } - } - GI => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..19]) { - return Err(PatternErr::Malformed); - } - } - GL => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..14]) { - return Err(PatternErr::Malformed); - } - } - GR => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..7]) || !C.check(&iban_ascii[7..23]) { - return Err(PatternErr::Malformed); - } - } - GT => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !C.check(&iban_ascii[0..24]) { - return Err(PatternErr::Malformed); - } - } - HN => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..24]) { - return Err(PatternErr::Malformed); - } - } - HR => { - if iban_ascii.len() != 17 { - return Err(PatternErr::Len(17, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..17]) { - return Err(PatternErr::Malformed); - } - } - HU => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..24]) { - return Err(PatternErr::Malformed); - } - } - IE => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..18]) { - return Err(PatternErr::Malformed); - } - } - IL => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..19]) { - return Err(PatternErr::Malformed); - } - } - IQ => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..19]) { - return Err(PatternErr::Malformed); - } - } - IS => { - if iban_ascii.len() != 22 { - return Err(PatternErr::Len(22, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..22]) { - return Err(PatternErr::Malformed); - } - } - IT => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..1]) - || !N.check(&iban_ascii[1..11]) - || !C.check(&iban_ascii[11..23]) - { - return Err(PatternErr::Malformed); - } - } - JO => { - if iban_ascii.len() != 26 { - return Err(PatternErr::Len(26, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..8]) - || !C.check(&iban_ascii[8..26]) - { - return Err(PatternErr::Malformed); - } - } - KW => { - if iban_ascii.len() != 26 { - return Err(PatternErr::Len(26, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..26]) { - return Err(PatternErr::Malformed); - } - } - KZ => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..3]) || !C.check(&iban_ascii[3..16]) { - return Err(PatternErr::Malformed); - } - } - LB => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..24]) { - return Err(PatternErr::Malformed); - } - } - LC => { - if iban_ascii.len() != 28 { - return Err(PatternErr::Len(28, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..28]) { - return Err(PatternErr::Malformed); - } - } - LI => { - if iban_ascii.len() != 17 { - return Err(PatternErr::Len(17, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..5]) || !C.check(&iban_ascii[5..17]) { - return Err(PatternErr::Malformed); - } - } - LT => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..16]) { - return Err(PatternErr::Malformed); - } - } - LU => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..3]) || !C.check(&iban_ascii[3..16]) { - return Err(PatternErr::Malformed); - } - } - LV => { - if iban_ascii.len() != 17 { - return Err(PatternErr::Len(17, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..17]) { - return Err(PatternErr::Malformed); - } - } - LY => { - if iban_ascii.len() != 21 { - return Err(PatternErr::Len(21, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..21]) { - return Err(PatternErr::Malformed); - } - } - MC => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..10]) - || !C.check(&iban_ascii[10..21]) - || !N.check(&iban_ascii[21..23]) - { - return Err(PatternErr::Malformed); - } - } - MD => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !C.check(&iban_ascii[0..20]) { - return Err(PatternErr::Malformed); - } - } - ME => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..18]) { - return Err(PatternErr::Malformed); - } - } - MK => { - if iban_ascii.len() != 15 { - return Err(PatternErr::Len(15, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..3]) - || !C.check(&iban_ascii[3..13]) - || !N.check(&iban_ascii[13..15]) - { - return Err(PatternErr::Malformed); - } - } - MN => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..16]) { - return Err(PatternErr::Malformed); - } - } - MR => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..23]) { - return Err(PatternErr::Malformed); - } - } - MT => { - if iban_ascii.len() != 27 { - return Err(PatternErr::Len(27, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..9]) - || !C.check(&iban_ascii[9..27]) - { - return Err(PatternErr::Malformed); - } - } - MU => { - if iban_ascii.len() != 26 { - return Err(PatternErr::Len(26, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..23]) - || !A.check(&iban_ascii[23..26]) - { - return Err(PatternErr::Malformed); - } - } - NI => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..24]) { - return Err(PatternErr::Malformed); - } - } - NL => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..14]) { - return Err(PatternErr::Malformed); - } - } - NO => { - if iban_ascii.len() != 11 { - return Err(PatternErr::Len(11, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..11]) { - return Err(PatternErr::Malformed); - } - } - OM => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..3]) || !C.check(&iban_ascii[3..19]) { - return Err(PatternErr::Malformed); - } - } - PK => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..20]) { - return Err(PatternErr::Malformed); - } - } - PL => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..24]) { - return Err(PatternErr::Malformed); - } - } - PS => { - if iban_ascii.len() != 25 { - return Err(PatternErr::Len(25, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..25]) { - return Err(PatternErr::Malformed); - } - } - PT => { - if iban_ascii.len() != 21 { - return Err(PatternErr::Len(21, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..21]) { - return Err(PatternErr::Malformed); - } - } - QA => { - if iban_ascii.len() != 25 { - return Err(PatternErr::Len(25, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..25]) { - return Err(PatternErr::Malformed); - } - } - RO => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !C.check(&iban_ascii[4..20]) { - return Err(PatternErr::Malformed); - } - } - RS => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..18]) { - return Err(PatternErr::Malformed); - } - } - RU => { - if iban_ascii.len() != 29 { - return Err(PatternErr::Len(29, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..14]) || !C.check(&iban_ascii[14..29]) { - return Err(PatternErr::Malformed); - } - } - SA => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..2]) || !C.check(&iban_ascii[2..20]) { - return Err(PatternErr::Malformed); - } - } - SC => { - if iban_ascii.len() != 27 { - return Err(PatternErr::Len(27, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..24]) - || !A.check(&iban_ascii[24..27]) - { - return Err(PatternErr::Malformed); - } - } - SD => { - if iban_ascii.len() != 14 { - return Err(PatternErr::Len(14, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..14]) { - return Err(PatternErr::Malformed); - } - } - SE => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..20]) { - return Err(PatternErr::Malformed); - } - } - SI => { - if iban_ascii.len() != 15 { - return Err(PatternErr::Len(15, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..15]) { - return Err(PatternErr::Malformed); - } - } - SK => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..20]) { - return Err(PatternErr::Malformed); - } - } - SM => { - if iban_ascii.len() != 23 { - return Err(PatternErr::Len(23, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..1]) - || !N.check(&iban_ascii[1..11]) - || !C.check(&iban_ascii[11..23]) - { - return Err(PatternErr::Malformed); - } - } - SO => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..19]) { - return Err(PatternErr::Malformed); - } - } - ST => { - if iban_ascii.len() != 21 { - return Err(PatternErr::Len(21, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..21]) { - return Err(PatternErr::Malformed); - } - } - SV => { - if iban_ascii.len() != 24 { - return Err(PatternErr::Len(24, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..24]) { - return Err(PatternErr::Malformed); - } - } - TL => { - if iban_ascii.len() != 19 { - return Err(PatternErr::Len(19, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..19]) { - return Err(PatternErr::Malformed); - } - } - TN => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..20]) { - return Err(PatternErr::Malformed); - } - } - TR => { - if iban_ascii.len() != 22 { - return Err(PatternErr::Len(22, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..6]) || !C.check(&iban_ascii[6..22]) { - return Err(PatternErr::Malformed); - } - } - UA => { - if iban_ascii.len() != 25 { - return Err(PatternErr::Len(25, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..6]) || !C.check(&iban_ascii[6..25]) { - return Err(PatternErr::Malformed); - } - } - VA => { - if iban_ascii.len() != 18 { - return Err(PatternErr::Len(18, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..18]) { - return Err(PatternErr::Malformed); - } - } - VG => { - if iban_ascii.len() != 20 { - return Err(PatternErr::Len(20, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) || !N.check(&iban_ascii[4..20]) { - return Err(PatternErr::Malformed); - } - } - XK => { - if iban_ascii.len() != 16 { - return Err(PatternErr::Len(16, iban_ascii.len())); - } else if !N.check(&iban_ascii[0..16]) { - return Err(PatternErr::Malformed); - } - } - YE => { - if iban_ascii.len() != 26 { - return Err(PatternErr::Len(26, iban_ascii.len())); - } else if !A.check(&iban_ascii[0..4]) - || !N.check(&iban_ascii[4..8]) - || !C.check(&iban_ascii[8..26]) - { - return Err(PatternErr::Malformed); - } - } + AD => &[(4, N)], + AE => &[], + AL => &[(5, N)], + AT => &[], + AZ => &[], + BA => &[(3, N)], + BE => &[], + BG => &[(4, N)], + BH => &[], + BI => &[(5, N)], + BR => &[(5, N)], + BY => &[], + CH => &[], + CR => &[], + CY => &[(5, N)], + CZ => &[], + DE => &[], + DJ => &[(5, N)], + DK => &[], + DO => &[], + EE => &[], + EG => &[(4, N)], + ES => &[(4, N)], + FI => &[], + FK => &[], + FO => &[], + FR => &[], + GB => &[(6, N)], + GE => &[], + GI => &[], + GL => &[], + GR => &[(4, N)], + GT => &[], + HN => &[], + HR => &[], + HU => &[(4, N)], + IE => &[(6, N)], + IL => &[(3, N)], + IQ => &[(3, N)], + IS => &[(2, N)], + IT => &[(5, N)], + JO => &[(4, N)], + KW => &[], + KZ => &[], + LB => &[], + LC => &[], + LI => &[], + LT => &[], + LU => &[], + LV => &[], + LY => &[(3, N)], + MC => &[(5, N)], + MD => &[], + ME => &[], + MK => &[], + MN => &[], + MR => &[(5, N)], + MT => &[(5, N)], + MU => &[(2, N)], + NI => &[], + NL => &[], + NO => &[], + OM => &[], + PK => &[], + PL => &[(8, N)], + PS => &[], + PT => &[(4, N)], + QA => &[], + RO => &[], + RS => &[], + RU => &[(5, N)], + SA => &[], + SC => &[(2, N)], + SD => &[], + SE => &[], + SI => &[], + SK => &[], + SM => &[(5, N)], + SO => &[(3, N)], + ST => &[(4, N)], + SV => &[], + TL => &[], + TN => &[(3, N)], + TR => &[], + UA => &[], + VA => &[], + VG => &[], + XK => &[(2, N)], + YE => &[(4, N)], } - Ok(()) } } @@ -1515,6 +1029,28 @@ pub fn rng_pattern(out: &mut [u8], pattern: Pattern) { } } +/// Valid an IBAN slice against a pattern +pub fn check_pattern(iban_ascii: &[u8], pattern: Pattern) -> Result<(), PatternErr> { + // IBAN are made of ASCII digits and uppercase + debug_assert!( + iban_ascii + .iter() + .all(|b| b.is_ascii_uppercase() || b.is_ascii_digit()) + ); + let pattern_len: u8 = pattern.iter().map(|(len, _)| *len).sum(); + if iban_ascii.len() != pattern_len as usize { + return Err(PatternErr::Len(pattern_len, iban_ascii.len())); + } + let mut cursor = 0; + for (repetition, char) in pattern { + if !char.check(&iban_ascii[cursor..cursor + *repetition as usize]) { + return Err(PatternErr::Malformed); + } + cursor += *repetition as usize; + } + Ok(()) +} + #[cfg(test)] pub const VALID_IBAN: [(&str, Option<&str>); 89] = [ ("AD1200012030200359100100", Some("00012030200359100100")),