taler-rust

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

registry.rs (33198B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::{fmt::Display, str::FromStr};
     18 
     19 use Country::*;
     20 use IbanC::*;
     21 use rand::seq::IndexedRandom;
     22 
     23 /// IBAN ASCII characters rules
     24 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
     25 pub enum IbanC {
     26     /// Digits (0-9)
     27     N,
     28     /// Uppercase (A-Z)
     29     A,
     30     /// Digits or uppercase (0-9 & A-Z)
     31     C,
     32 }
     33 
     34 impl IbanC {
     35     /// Check if a valid IBAN slice follow a specific characters rules
     36     pub fn check(self, iban_ascii: &[u8]) -> bool {
     37         // IBAN are made of ASCII digits and uppercase
     38         debug_assert!(
     39             iban_ascii
     40                 .iter()
     41                 .all(|b| b.is_ascii_uppercase() || b.is_ascii_digit())
     42         );
     43         // As all characters are ASCII digits or uppercase
     44         // we can use simple masks to check the character kind
     45         const MASK_IS_UPPERCASE: u8 = 0b0100_0000;
     46         const MASK_IS_DIGIT: u8 = 0b0010_0000;
     47 
     48         let mask = match self {
     49             Self::N => MASK_IS_UPPERCASE,
     50             Self::A => MASK_IS_DIGIT,
     51             Self::C => return true,
     52         };
     53         iban_ascii.iter().all(|b| (*b & mask) == 0)
     54     }
     55 }
     56 
     57 /// An IBAN pattern, an array of characters rules over a number of character
     58 pub type Pattern = &'static [(u8, IbanC)];
     59 
     60 #[derive(Debug)]
     61 pub enum PatternErr {
     62     Len(u8, usize),
     63     Malformed,
     64 }
     65 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     66 pub enum Country {
     67     AD,
     68     AE,
     69     AL,
     70     AT,
     71     AZ,
     72     BA,
     73     BE,
     74     BG,
     75     BH,
     76     BI,
     77     BR,
     78     BY,
     79     CH,
     80     CR,
     81     CY,
     82     CZ,
     83     DE,
     84     DJ,
     85     DK,
     86     DO,
     87     EE,
     88     EG,
     89     ES,
     90     FI,
     91     FK,
     92     FO,
     93     FR,
     94     GB,
     95     GE,
     96     GI,
     97     GL,
     98     GR,
     99     GT,
    100     HN,
    101     HR,
    102     HU,
    103     IE,
    104     IL,
    105     IQ,
    106     IS,
    107     IT,
    108     JO,
    109     KW,
    110     KZ,
    111     LB,
    112     LC,
    113     LI,
    114     LT,
    115     LU,
    116     LV,
    117     LY,
    118     MC,
    119     MD,
    120     ME,
    121     MK,
    122     MN,
    123     MR,
    124     MT,
    125     MU,
    126     NI,
    127     NL,
    128     NO,
    129     OM,
    130     PK,
    131     PL,
    132     PS,
    133     PT,
    134     QA,
    135     RO,
    136     RS,
    137     RU,
    138     SA,
    139     SC,
    140     SD,
    141     SE,
    142     SI,
    143     SK,
    144     SM,
    145     SO,
    146     ST,
    147     SV,
    148     TL,
    149     TN,
    150     TR,
    151     UA,
    152     VA,
    153     VG,
    154     XK,
    155     YE,
    156 }
    157 
    158 impl Country {
    159     pub fn from_iso(country: &str) -> Option<Self> {
    160         match country {
    161             "AD" => Some(AD),
    162             "AE" => Some(AE),
    163             "AL" => Some(AL),
    164             "AT" => Some(AT),
    165             "AZ" => Some(AZ),
    166             "BA" => Some(BA),
    167             "BE" => Some(BE),
    168             "BG" => Some(BG),
    169             "BH" => Some(BH),
    170             "BI" => Some(BI),
    171             "BR" => Some(BR),
    172             "BY" => Some(BY),
    173             "CH" => Some(CH),
    174             "CR" => Some(CR),
    175             "CY" => Some(CY),
    176             "CZ" => Some(CZ),
    177             "DE" => Some(DE),
    178             "DJ" => Some(DJ),
    179             "DK" => Some(DK),
    180             "DO" => Some(DO),
    181             "EE" => Some(EE),
    182             "EG" => Some(EG),
    183             "ES" => Some(ES),
    184             "FI" => Some(FI),
    185             "FK" => Some(FK),
    186             "FO" => Some(FO),
    187             "FR" => Some(FR),
    188             "GB" => Some(GB),
    189             "GE" => Some(GE),
    190             "GI" => Some(GI),
    191             "GL" => Some(GL),
    192             "GR" => Some(GR),
    193             "GT" => Some(GT),
    194             "HN" => Some(HN),
    195             "HR" => Some(HR),
    196             "HU" => Some(HU),
    197             "IE" => Some(IE),
    198             "IL" => Some(IL),
    199             "IQ" => Some(IQ),
    200             "IS" => Some(IS),
    201             "IT" => Some(IT),
    202             "JO" => Some(JO),
    203             "KW" => Some(KW),
    204             "KZ" => Some(KZ),
    205             "LB" => Some(LB),
    206             "LC" => Some(LC),
    207             "LI" => Some(LI),
    208             "LT" => Some(LT),
    209             "LU" => Some(LU),
    210             "LV" => Some(LV),
    211             "LY" => Some(LY),
    212             "MC" => Some(MC),
    213             "MD" => Some(MD),
    214             "ME" => Some(ME),
    215             "MK" => Some(MK),
    216             "MN" => Some(MN),
    217             "MR" => Some(MR),
    218             "MT" => Some(MT),
    219             "MU" => Some(MU),
    220             "NI" => Some(NI),
    221             "NL" => Some(NL),
    222             "NO" => Some(NO),
    223             "OM" => Some(OM),
    224             "PK" => Some(PK),
    225             "PL" => Some(PL),
    226             "PS" => Some(PS),
    227             "PT" => Some(PT),
    228             "QA" => Some(QA),
    229             "RO" => Some(RO),
    230             "RS" => Some(RS),
    231             "RU" => Some(RU),
    232             "SA" => Some(SA),
    233             "SC" => Some(SC),
    234             "SD" => Some(SD),
    235             "SE" => Some(SE),
    236             "SI" => Some(SI),
    237             "SK" => Some(SK),
    238             "SM" => Some(SM),
    239             "SO" => Some(SO),
    240             "ST" => Some(ST),
    241             "SV" => Some(SV),
    242             "TL" => Some(TL),
    243             "TN" => Some(TN),
    244             "TR" => Some(TR),
    245             "UA" => Some(UA),
    246             "VA" => Some(VA),
    247             "VG" => Some(VG),
    248             "XK" => Some(XK),
    249             "YE" => Some(YE),
    250             _ => None,
    251         }
    252     }
    253 
    254     pub const fn iso(self) -> &'static str {
    255         match self {
    256             AD => "AD",
    257             AE => "AE",
    258             AL => "AL",
    259             AT => "AT",
    260             AZ => "AZ",
    261             BA => "BA",
    262             BE => "BE",
    263             BG => "BG",
    264             BH => "BH",
    265             BI => "BI",
    266             BR => "BR",
    267             BY => "BY",
    268             CH => "CH",
    269             CR => "CR",
    270             CY => "CY",
    271             CZ => "CZ",
    272             DE => "DE",
    273             DJ => "DJ",
    274             DK => "DK",
    275             DO => "DO",
    276             EE => "EE",
    277             EG => "EG",
    278             ES => "ES",
    279             FI => "FI",
    280             FK => "FK",
    281             FO => "FO",
    282             FR => "FR",
    283             GB => "GB",
    284             GE => "GE",
    285             GI => "GI",
    286             GL => "GL",
    287             GR => "GR",
    288             GT => "GT",
    289             HN => "HN",
    290             HR => "HR",
    291             HU => "HU",
    292             IE => "IE",
    293             IL => "IL",
    294             IQ => "IQ",
    295             IS => "IS",
    296             IT => "IT",
    297             JO => "JO",
    298             KW => "KW",
    299             KZ => "KZ",
    300             LB => "LB",
    301             LC => "LC",
    302             LI => "LI",
    303             LT => "LT",
    304             LU => "LU",
    305             LV => "LV",
    306             LY => "LY",
    307             MC => "MC",
    308             MD => "MD",
    309             ME => "ME",
    310             MK => "MK",
    311             MN => "MN",
    312             MR => "MR",
    313             MT => "MT",
    314             MU => "MU",
    315             NI => "NI",
    316             NL => "NL",
    317             NO => "NO",
    318             OM => "OM",
    319             PK => "PK",
    320             PL => "PL",
    321             PS => "PS",
    322             PT => "PT",
    323             QA => "QA",
    324             RO => "RO",
    325             RS => "RS",
    326             RU => "RU",
    327             SA => "SA",
    328             SC => "SC",
    329             SD => "SD",
    330             SE => "SE",
    331             SI => "SI",
    332             SK => "SK",
    333             SM => "SM",
    334             SO => "SO",
    335             ST => "ST",
    336             SV => "SV",
    337             TL => "TL",
    338             TN => "TN",
    339             TR => "TR",
    340             UA => "UA",
    341             VA => "VA",
    342             VG => "VG",
    343             XK => "XK",
    344             YE => "YE",
    345         }
    346     }
    347 
    348     pub const fn iso_bytes(self) -> &'static [u8; 2] {
    349         match self {
    350             AD => b"AD",
    351             AE => b"AE",
    352             AL => b"AL",
    353             AT => b"AT",
    354             AZ => b"AZ",
    355             BA => b"BA",
    356             BE => b"BE",
    357             BG => b"BG",
    358             BH => b"BH",
    359             BI => b"BI",
    360             BR => b"BR",
    361             BY => b"BY",
    362             CH => b"CH",
    363             CR => b"CR",
    364             CY => b"CY",
    365             CZ => b"CZ",
    366             DE => b"DE",
    367             DJ => b"DJ",
    368             DK => b"DK",
    369             DO => b"DO",
    370             EE => b"EE",
    371             EG => b"EG",
    372             ES => b"ES",
    373             FI => b"FI",
    374             FK => b"FK",
    375             FO => b"FO",
    376             FR => b"FR",
    377             GB => b"GB",
    378             GE => b"GE",
    379             GI => b"GI",
    380             GL => b"GL",
    381             GR => b"GR",
    382             GT => b"GT",
    383             HN => b"HN",
    384             HR => b"HR",
    385             HU => b"HU",
    386             IE => b"IE",
    387             IL => b"IL",
    388             IQ => b"IQ",
    389             IS => b"IS",
    390             IT => b"IT",
    391             JO => b"JO",
    392             KW => b"KW",
    393             KZ => b"KZ",
    394             LB => b"LB",
    395             LC => b"LC",
    396             LI => b"LI",
    397             LT => b"LT",
    398             LU => b"LU",
    399             LV => b"LV",
    400             LY => b"LY",
    401             MC => b"MC",
    402             MD => b"MD",
    403             ME => b"ME",
    404             MK => b"MK",
    405             MN => b"MN",
    406             MR => b"MR",
    407             MT => b"MT",
    408             MU => b"MU",
    409             NI => b"NI",
    410             NL => b"NL",
    411             NO => b"NO",
    412             OM => b"OM",
    413             PK => b"PK",
    414             PL => b"PL",
    415             PS => b"PS",
    416             PT => b"PT",
    417             QA => b"QA",
    418             RO => b"RO",
    419             RS => b"RS",
    420             RU => b"RU",
    421             SA => b"SA",
    422             SC => b"SC",
    423             SD => b"SD",
    424             SE => b"SE",
    425             SI => b"SI",
    426             SK => b"SK",
    427             SM => b"SM",
    428             SO => b"SO",
    429             ST => b"ST",
    430             SV => b"SV",
    431             TL => b"TL",
    432             TN => b"TN",
    433             TR => b"TR",
    434             UA => b"UA",
    435             VA => b"VA",
    436             VG => b"VG",
    437             XK => b"XK",
    438             YE => b"YE",
    439         }
    440     }
    441 
    442     pub const fn iban_len(self) -> usize {
    443         match self {
    444             AD => 24,
    445             AE => 23,
    446             AL => 28,
    447             AT => 20,
    448             AZ => 28,
    449             BA => 20,
    450             BE => 16,
    451             BG => 22,
    452             BH => 22,
    453             BI => 27,
    454             BR => 29,
    455             BY => 28,
    456             CH => 21,
    457             CR => 22,
    458             CY => 28,
    459             CZ => 24,
    460             DE => 22,
    461             DJ => 27,
    462             DK => 18,
    463             DO => 28,
    464             EE => 20,
    465             EG => 29,
    466             ES => 24,
    467             FI => 18,
    468             FK => 18,
    469             FO => 18,
    470             FR => 27,
    471             GB => 22,
    472             GE => 22,
    473             GI => 23,
    474             GL => 18,
    475             GR => 27,
    476             GT => 28,
    477             HN => 28,
    478             HR => 21,
    479             HU => 28,
    480             IE => 22,
    481             IL => 23,
    482             IQ => 23,
    483             IS => 26,
    484             IT => 27,
    485             JO => 30,
    486             KW => 30,
    487             KZ => 20,
    488             LB => 28,
    489             LC => 32,
    490             LI => 21,
    491             LT => 20,
    492             LU => 20,
    493             LV => 21,
    494             LY => 25,
    495             MC => 27,
    496             MD => 24,
    497             ME => 22,
    498             MK => 19,
    499             MN => 20,
    500             MR => 27,
    501             MT => 31,
    502             MU => 30,
    503             NI => 28,
    504             NL => 18,
    505             NO => 15,
    506             OM => 23,
    507             PK => 24,
    508             PL => 28,
    509             PS => 29,
    510             PT => 25,
    511             QA => 29,
    512             RO => 24,
    513             RS => 22,
    514             RU => 33,
    515             SA => 24,
    516             SC => 31,
    517             SD => 18,
    518             SE => 24,
    519             SI => 19,
    520             SK => 24,
    521             SM => 27,
    522             SO => 23,
    523             ST => 25,
    524             SV => 28,
    525             TL => 23,
    526             TN => 24,
    527             TR => 26,
    528             UA => 29,
    529             VA => 22,
    530             VG => 24,
    531             XK => 20,
    532             YE => 30,
    533         }
    534     }
    535 
    536     pub const fn bban_len(self) -> usize {
    537         self.iban_len() - 4
    538     }
    539 
    540     pub const fn bank_id(self) -> core::ops::Range<usize> {
    541         match self {
    542             AD => 0..4,
    543             AE => 0..3,
    544             AL => 0..3,
    545             AT => 0..5,
    546             AZ => 0..4,
    547             BA => 0..3,
    548             BE => 0..3,
    549             BG => 0..4,
    550             BH => 0..4,
    551             BI => 0..5,
    552             BR => 0..8,
    553             BY => 0..4,
    554             CH => 0..5,
    555             CR => 0..4,
    556             CY => 0..3,
    557             CZ => 0..4,
    558             DE => 0..8,
    559             DJ => 0..5,
    560             DK => 0..4,
    561             DO => 0..4,
    562             EE => 0..2,
    563             EG => 0..4,
    564             ES => 0..4,
    565             FI => 0..3,
    566             FK => 0..2,
    567             FO => 0..4,
    568             FR => 0..5,
    569             GB => 0..4,
    570             GE => 0..2,
    571             GI => 0..4,
    572             GL => 0..4,
    573             GR => 0..3,
    574             GT => 0..4,
    575             HN => 0..4,
    576             HR => 0..7,
    577             HU => 0..3,
    578             IE => 0..4,
    579             IL => 0..3,
    580             IQ => 0..4,
    581             IS => 0..2,
    582             IT => 1..6,
    583             JO => 4..8,
    584             KW => 0..4,
    585             KZ => 0..3,
    586             LB => 0..4,
    587             LC => 0..4,
    588             LI => 0..5,
    589             LT => 0..5,
    590             LU => 0..3,
    591             LV => 0..4,
    592             LY => 0..3,
    593             MC => 0..5,
    594             MD => 0..2,
    595             ME => 0..3,
    596             MK => 0..3,
    597             MN => 0..4,
    598             MR => 0..5,
    599             MT => 0..4,
    600             MU => 0..6,
    601             NI => 0..4,
    602             NL => 0..4,
    603             NO => 0..4,
    604             OM => 0..3,
    605             PK => 0..4,
    606             PL => 0..0,
    607             PS => 0..4,
    608             PT => 0..4,
    609             QA => 0..4,
    610             RO => 0..4,
    611             RS => 0..3,
    612             RU => 0..9,
    613             SA => 0..2,
    614             SC => 0..6,
    615             SD => 0..2,
    616             SE => 0..3,
    617             SI => 0..5,
    618             SK => 0..4,
    619             SM => 1..6,
    620             SO => 0..4,
    621             ST => 0..4,
    622             SV => 0..4,
    623             TL => 0..3,
    624             TN => 0..2,
    625             TR => 0..5,
    626             UA => 0..6,
    627             VA => 0..3,
    628             VG => 0..4,
    629             XK => 0..2,
    630             YE => 0..4,
    631         }
    632     }
    633 
    634     pub const fn branch_id(self) -> core::ops::Range<usize> {
    635         match self {
    636             AD => 4..8,
    637             AE => 0..0,
    638             AL => 3..8,
    639             AT => 0..0,
    640             AZ => 0..0,
    641             BA => 3..6,
    642             BE => 0..0,
    643             BG => 4..8,
    644             BH => 0..0,
    645             BI => 5..10,
    646             BR => 8..13,
    647             BY => 0..0,
    648             CH => 0..0,
    649             CR => 0..0,
    650             CY => 3..8,
    651             CZ => 0..0,
    652             DE => 0..0,
    653             DJ => 5..10,
    654             DK => 0..0,
    655             DO => 0..0,
    656             EE => 0..0,
    657             EG => 4..8,
    658             ES => 4..8,
    659             FI => 0..0,
    660             FK => 0..0,
    661             FO => 0..0,
    662             FR => 0..0,
    663             GB => 4..10,
    664             GE => 0..0,
    665             GI => 0..0,
    666             GL => 0..0,
    667             GR => 3..7,
    668             GT => 0..0,
    669             HN => 0..0,
    670             HR => 0..0,
    671             HU => 3..7,
    672             IE => 4..10,
    673             IL => 3..6,
    674             IQ => 4..7,
    675             IS => 2..4,
    676             IT => 6..11,
    677             JO => 4..8,
    678             KW => 0..0,
    679             KZ => 0..0,
    680             LB => 0..0,
    681             LC => 0..0,
    682             LI => 0..0,
    683             LT => 0..0,
    684             LU => 0..0,
    685             LV => 0..0,
    686             LY => 3..6,
    687             MC => 5..10,
    688             MD => 0..0,
    689             ME => 0..0,
    690             MK => 0..0,
    691             MN => 0..0,
    692             MR => 5..10,
    693             MT => 4..9,
    694             MU => 6..8,
    695             NI => 0..0,
    696             NL => 0..0,
    697             NO => 0..0,
    698             OM => 0..0,
    699             PK => 0..0,
    700             PL => 0..8,
    701             PS => 0..0,
    702             PT => 4..8,
    703             QA => 0..0,
    704             RO => 0..0,
    705             RS => 0..0,
    706             RU => 9..14,
    707             SA => 0..0,
    708             SC => 6..8,
    709             SD => 0..0,
    710             SE => 0..0,
    711             SI => 0..0,
    712             SK => 0..0,
    713             SM => 6..11,
    714             SO => 4..7,
    715             ST => 4..8,
    716             SV => 0..0,
    717             TL => 0..0,
    718             TN => 2..5,
    719             TR => 0..0,
    720             UA => 0..0,
    721             VA => 0..0,
    722             VG => 0..0,
    723             XK => 2..4,
    724             YE => 4..8,
    725         }
    726     }
    727 
    728     pub const fn bban_pattern(self) -> Pattern {
    729         match self {
    730             AD => &[(8, N), (12, C)],
    731             AE => &[(19, N)],
    732             AL => &[(8, N), (16, C)],
    733             AT => &[(16, N)],
    734             AZ => &[(4, A), (20, C)],
    735             BA => &[(16, N)],
    736             BE => &[(12, N)],
    737             BG => &[(4, A), (6, N), (8, C)],
    738             BH => &[(4, A), (14, C)],
    739             BI => &[(23, N)],
    740             BR => &[(23, N), (1, A), (1, C)],
    741             BY => &[(4, C), (4, N), (16, C)],
    742             CH => &[(5, N), (12, C)],
    743             CR => &[(18, N)],
    744             CY => &[(8, N), (16, C)],
    745             CZ => &[(20, N)],
    746             DE => &[(18, N)],
    747             DJ => &[(23, N)],
    748             DK => &[(14, N)],
    749             DO => &[(4, C), (20, N)],
    750             EE => &[(16, N)],
    751             EG => &[(25, N)],
    752             ES => &[(20, N)],
    753             FI => &[(14, N)],
    754             FK => &[(2, A), (12, N)],
    755             FO => &[(14, N)],
    756             FR => &[(10, N), (11, C), (2, N)],
    757             GB => &[(4, A), (14, N)],
    758             GE => &[(2, A), (16, N)],
    759             GI => &[(4, A), (15, C)],
    760             GL => &[(14, N)],
    761             GR => &[(7, N), (16, C)],
    762             GT => &[(24, C)],
    763             HN => &[(4, A), (20, N)],
    764             HR => &[(17, N)],
    765             HU => &[(24, N)],
    766             IE => &[(4, A), (14, N)],
    767             IL => &[(19, N)],
    768             IQ => &[(4, A), (15, N)],
    769             IS => &[(22, N)],
    770             IT => &[(1, A), (10, N), (12, C)],
    771             JO => &[(4, A), (4, N), (18, C)],
    772             KW => &[(4, A), (22, C)],
    773             KZ => &[(3, N), (13, C)],
    774             LB => &[(4, N), (20, C)],
    775             LC => &[(4, A), (24, C)],
    776             LI => &[(5, N), (12, C)],
    777             LT => &[(16, N)],
    778             LU => &[(3, N), (13, C)],
    779             LV => &[(4, A), (13, C)],
    780             LY => &[(21, N)],
    781             MC => &[(10, N), (11, C), (2, N)],
    782             MD => &[(20, C)],
    783             ME => &[(18, N)],
    784             MK => &[(3, N), (10, C), (2, N)],
    785             MN => &[(16, N)],
    786             MR => &[(23, N)],
    787             MT => &[(4, A), (5, N), (18, C)],
    788             MU => &[(4, A), (19, N), (3, A)],
    789             NI => &[(4, A), (20, N)],
    790             NL => &[(4, A), (10, N)],
    791             NO => &[(11, N)],
    792             OM => &[(3, N), (16, C)],
    793             PK => &[(4, A), (16, C)],
    794             PL => &[(24, N)],
    795             PS => &[(4, A), (21, C)],
    796             PT => &[(21, N)],
    797             QA => &[(4, A), (21, C)],
    798             RO => &[(4, A), (16, C)],
    799             RS => &[(18, N)],
    800             RU => &[(14, N), (15, C)],
    801             SA => &[(2, N), (18, C)],
    802             SC => &[(4, A), (20, N), (3, A)],
    803             SD => &[(14, N)],
    804             SE => &[(20, N)],
    805             SI => &[(15, N)],
    806             SK => &[(20, N)],
    807             SM => &[(1, A), (10, N), (12, C)],
    808             SO => &[(19, N)],
    809             ST => &[(21, N)],
    810             SV => &[(4, A), (20, N)],
    811             TL => &[(19, N)],
    812             TN => &[(20, N)],
    813             TR => &[(6, N), (16, C)],
    814             UA => &[(6, N), (19, C)],
    815             VA => &[(18, N)],
    816             VG => &[(4, A), (16, N)],
    817             XK => &[(16, N)],
    818             YE => &[(4, A), (4, N), (18, C)],
    819         }
    820     }
    821 
    822     pub const fn bank_pattern(self) -> Pattern {
    823         match self {
    824             AD => &[(4, N)],
    825             AE => &[(3, N)],
    826             AL => &[(3, N)],
    827             AT => &[(5, N)],
    828             AZ => &[(4, A)],
    829             BA => &[(3, N)],
    830             BE => &[(3, N)],
    831             BG => &[(4, A)],
    832             BH => &[(4, A)],
    833             BI => &[(5, N)],
    834             BR => &[(8, N)],
    835             BY => &[(4, C)],
    836             CH => &[(5, N)],
    837             CR => &[(4, N)],
    838             CY => &[(3, N)],
    839             CZ => &[(4, N)],
    840             DE => &[(8, N)],
    841             DJ => &[(5, N)],
    842             DK => &[(4, N)],
    843             DO => &[(4, C)],
    844             EE => &[(2, N)],
    845             EG => &[(4, N)],
    846             ES => &[(4, N)],
    847             FI => &[(3, N)],
    848             FK => &[(2, A)],
    849             FO => &[(4, N)],
    850             FR => &[(5, N)],
    851             GB => &[(4, A)],
    852             GE => &[(2, A)],
    853             GI => &[(4, A)],
    854             GL => &[(4, N)],
    855             GR => &[(3, N)],
    856             GT => &[(4, C)],
    857             HN => &[(4, A)],
    858             HR => &[(7, N)],
    859             HU => &[(3, N)],
    860             IE => &[(4, A)],
    861             IL => &[(3, N)],
    862             IQ => &[(4, A)],
    863             IS => &[(2, N)],
    864             IT => &[(5, N)],
    865             JO => &[(4, N)],
    866             KW => &[(4, A)],
    867             KZ => &[(3, N)],
    868             LB => &[(4, A)],
    869             LC => &[(4, A)],
    870             LI => &[(5, N)],
    871             LT => &[(5, N)],
    872             LU => &[(3, N)],
    873             LV => &[(4, A)],
    874             LY => &[(3, N)],
    875             MC => &[(5, N)],
    876             MD => &[(2, C)],
    877             ME => &[(3, N)],
    878             MK => &[(3, N)],
    879             MN => &[(4, N)],
    880             MR => &[(5, N)],
    881             MT => &[(4, A)],
    882             MU => &[(6, C)],
    883             NI => &[(4, A)],
    884             NL => &[(4, A)],
    885             NO => &[(4, N)],
    886             OM => &[(3, N)],
    887             PK => &[(4, A)],
    888             PL => &[],
    889             PS => &[(4, A)],
    890             PT => &[(4, N)],
    891             QA => &[(4, A)],
    892             RO => &[(4, A)],
    893             RS => &[(3, N)],
    894             RU => &[(9, N)],
    895             SA => &[(2, N)],
    896             SC => &[(4, A), (2, N)],
    897             SD => &[(2, N)],
    898             SE => &[(3, N)],
    899             SI => &[(5, N)],
    900             SK => &[(4, N)],
    901             SM => &[(5, N)],
    902             SO => &[(4, N)],
    903             ST => &[(4, N)],
    904             SV => &[(4, A)],
    905             TL => &[(3, N)],
    906             TN => &[(2, N)],
    907             TR => &[(5, N)],
    908             UA => &[(6, N)],
    909             VA => &[(3, N)],
    910             VG => &[(4, A)],
    911             XK => &[(2, N)],
    912             YE => &[(4, A)],
    913         }
    914     }
    915 
    916     pub const fn branch_pattern(self) -> Pattern {
    917         match self {
    918             AD => &[(4, N)],
    919             AE => &[],
    920             AL => &[(5, N)],
    921             AT => &[],
    922             AZ => &[],
    923             BA => &[(3, N)],
    924             BE => &[],
    925             BG => &[(4, N)],
    926             BH => &[],
    927             BI => &[(5, N)],
    928             BR => &[(5, N)],
    929             BY => &[],
    930             CH => &[],
    931             CR => &[],
    932             CY => &[(5, N)],
    933             CZ => &[],
    934             DE => &[],
    935             DJ => &[(5, N)],
    936             DK => &[],
    937             DO => &[],
    938             EE => &[],
    939             EG => &[(4, N)],
    940             ES => &[(4, N)],
    941             FI => &[],
    942             FK => &[],
    943             FO => &[],
    944             FR => &[],
    945             GB => &[(6, N)],
    946             GE => &[],
    947             GI => &[],
    948             GL => &[],
    949             GR => &[(4, N)],
    950             GT => &[],
    951             HN => &[],
    952             HR => &[],
    953             HU => &[(4, N)],
    954             IE => &[(6, N)],
    955             IL => &[(3, N)],
    956             IQ => &[(3, N)],
    957             IS => &[(2, N)],
    958             IT => &[(5, N)],
    959             JO => &[(4, N)],
    960             KW => &[],
    961             KZ => &[],
    962             LB => &[],
    963             LC => &[],
    964             LI => &[],
    965             LT => &[],
    966             LU => &[],
    967             LV => &[],
    968             LY => &[(3, N)],
    969             MC => &[(5, N)],
    970             MD => &[],
    971             ME => &[],
    972             MK => &[],
    973             MN => &[],
    974             MR => &[(5, N)],
    975             MT => &[(5, N)],
    976             MU => &[(2, N)],
    977             NI => &[],
    978             NL => &[],
    979             NO => &[],
    980             OM => &[],
    981             PK => &[],
    982             PL => &[(8, N)],
    983             PS => &[],
    984             PT => &[(4, N)],
    985             QA => &[],
    986             RO => &[],
    987             RS => &[],
    988             RU => &[(5, N)],
    989             SA => &[],
    990             SC => &[(2, N)],
    991             SD => &[],
    992             SE => &[],
    993             SI => &[],
    994             SK => &[],
    995             SM => &[(5, N)],
    996             SO => &[(3, N)],
    997             ST => &[(4, N)],
    998             SV => &[],
    999             TL => &[],
   1000             TN => &[(3, N)],
   1001             TR => &[],
   1002             UA => &[],
   1003             VA => &[],
   1004             VG => &[],
   1005             XK => &[(2, N)],
   1006             YE => &[(4, N)],
   1007         }
   1008     }
   1009 }
   1010 
   1011 impl FromStr for Country {
   1012     type Err = String;
   1013 
   1014     fn from_str(s: &str) -> Result<Self, Self::Err> {
   1015         Self::from_iso(s).ok_or_else(|| format!("Unknown country '{s}'"))
   1016     }
   1017 }
   1018 
   1019 impl Display for Country {
   1020     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
   1021         f.write_str(self.iso())
   1022     }
   1023 }
   1024 
   1025 /// Generate random ASCII string following an IBAN pattern rules
   1026 pub fn rng_pattern(out: &mut [u8], pattern: Pattern) {
   1027     let mut cursor = 0;
   1028     let mut rng = rand::rng();
   1029     for (len, rule) in pattern {
   1030         let alphabet = match rule {
   1031             IbanC::C => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
   1032             IbanC::N => "0123456789",
   1033             IbanC::A => "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
   1034         };
   1035         for b in &mut out[cursor..cursor + *len as usize] {
   1036             *b = *alphabet.as_bytes().choose(&mut rng).unwrap();
   1037         }
   1038         cursor += *len as usize
   1039     }
   1040 }
   1041 
   1042 /// Valid an IBAN slice against a pattern
   1043 pub fn check_pattern(iban_ascii: &[u8], pattern: Pattern) -> Result<(), PatternErr> {
   1044     // IBAN are made of ASCII digits and uppercase
   1045     debug_assert!(
   1046         iban_ascii
   1047             .iter()
   1048             .all(|b| b.is_ascii_uppercase() || b.is_ascii_digit())
   1049     );
   1050     let pattern_len: u8 = pattern.iter().map(|(len, _)| *len).sum();
   1051     if iban_ascii.len() != pattern_len as usize {
   1052         return Err(PatternErr::Len(pattern_len, iban_ascii.len()));
   1053     }
   1054     let mut cursor = 0;
   1055     for (repetition, char) in pattern {
   1056         if !char.check(&iban_ascii[cursor..cursor + *repetition as usize]) {
   1057             return Err(PatternErr::Malformed);
   1058         }
   1059         cursor += *repetition as usize;
   1060     }
   1061     Ok(())
   1062 }
   1063 
   1064 #[cfg(test)]
   1065 pub const VALID_IBAN: [(&str, Option<&str>); 89] = [
   1066     ("AD1200012030200359100100", Some("00012030200359100100")),
   1067     ("AE070331234567890123456", Some("0331234567890123456")),
   1068     (
   1069         "AL47212110090000000235698741",
   1070         Some("212110090000000235698741"),
   1071     ),
   1072     ("AT611904300234573201", Some("1904300234573201")),
   1073     (
   1074         "AZ21NABZ00000000137010001944",
   1075         Some("NABZ00000000137010001944"),
   1076     ),
   1077     ("BA391290079401028494", Some("1290079401028494")),
   1078     ("BE68539007547034", Some("539007547034")),
   1079     ("BG80BNBG96611020345678", Some("BNBG96611020345678")),
   1080     ("BH67BMAG00001299123456", Some("BMAG00001299123456")),
   1081     (
   1082         "BI4210000100010000332045181",
   1083         Some("10000100010000332045181"),
   1084     ),
   1085     (
   1086         "BR1800360305000010009795493C1",
   1087         Some("00360305000010009795493C1"),
   1088     ),
   1089     (
   1090         "BY13NBRB3600900000002Z00AB00",
   1091         Some("NBRB3600900000002Z00AB00"),
   1092     ),
   1093     ("CH9300762011623852957", Some("00762011623852957")),
   1094     ("CR05015202001026284066", Some("015202001026284066")),
   1095     (
   1096         "CY17002001280000001200527600",
   1097         Some("002001280000001200527600"),
   1098     ),
   1099     ("CZ6508000000192000145399", Some("08000000192000145399")),
   1100     ("DE89370400440532013000", Some("370400440532013000")),
   1101     (
   1102         "DJ2100010000000154000100186",
   1103         Some("00010000000154000100186"),
   1104     ),
   1105     ("DK5000400440116243", Some("00400440116243")),
   1106     (
   1107         "DO28BAGR00000001212453611324",
   1108         Some("BAGR00000001212453611324"),
   1109     ),
   1110     ("EE382200221020145685", Some("2200221020145685")),
   1111     (
   1112         "EG380019000500000000263180002",
   1113         Some("0019000500000000263180002"),
   1114     ),
   1115     ("ES9121000418450200051332", Some("21000418450200051332")),
   1116     ("FI2112345600000785", None),
   1117     ("FK88SC123456789012", Some("SC123456789012")),
   1118     ("FO6264600001631634", Some("64600001631634")),
   1119     (
   1120         "FR1420041010050500013M02606",
   1121         Some("20041010050500013M02606"),
   1122     ),
   1123     ("GB29NWBK60161331926819", Some("NWBK60161331926819")),
   1124     ("GE29NB0000000101904917", Some("NB0000000101904917")),
   1125     ("GI75NWBK000000007099453", Some("NWBK000000007099453")),
   1126     ("GL8964710001000206", Some("64710001000206")),
   1127     (
   1128         "GR1601101250000000012300695",
   1129         Some("01101250000000012300695"),
   1130     ),
   1131     (
   1132         "GT82TRAJ01020000001210029690",
   1133         Some("TRAJ01020000001210029690"),
   1134     ),
   1135     (
   1136         "HN88CABF00000000000250005469",
   1137         Some("CABF00000000000250005469"),
   1138     ),
   1139     ("HR1210010051863000160", Some("10010051863000160")),
   1140     (
   1141         "HU42117730161111101800000000",
   1142         Some("117730161111101800000000"),
   1143     ),
   1144     ("IE29AIBK93115212345678", Some("AIBK93115212345678")),
   1145     ("IL620108000000099999999", Some("0108000000099999999")),
   1146     ("IQ98NBIQ850123456789012", Some("NBIQ850123456789012")),
   1147     ("IS140159260076545510730339", Some("0159260076545510730339")),
   1148     (
   1149         "IT60X0542811101000000123456",
   1150         Some("X0542811101000000123456"),
   1151     ),
   1152     (
   1153         "JO94CBJO0010000000000131000302",
   1154         Some("CBJO0010000000000131000302"),
   1155     ),
   1156     (
   1157         "KW81CBKU0000000000001234560101",
   1158         Some("CBKU0000000000001234560101"),
   1159     ),
   1160     ("KZ86125KZT5004100100", Some("125KZT5004100100")),
   1161     (
   1162         "LB62099900000001001901229114",
   1163         Some("099900000001001901229114"),
   1164     ),
   1165     (
   1166         "LC55HEMM000100010012001200023015",
   1167         Some("HEMM000100010012001200023015"),
   1168     ),
   1169     ("LI21088100002324013AA", Some("088100002324013AA")),
   1170     ("LT121000011101001000", Some("1000011101001000")),
   1171     ("LU280019400644750000", Some("0019400644750000")),
   1172     ("LV80BANK0000435195001", Some("BANK0000435195001")),
   1173     ("LY83002048000020100120361", Some("002048000020100120361")),
   1174     (
   1175         "MC5811222000010123456789030",
   1176         Some("11222000010123456789030"),
   1177     ),
   1178     ("MD24AG000225100013104168", Some("AG000225100013104168")),
   1179     ("ME25505000012345678951", Some("505000012345678951")),
   1180     ("MK07250120000058984", Some("250120000058984")),
   1181     ("MN121234123456789123", Some("1234123456789123")),
   1182     (
   1183         "MR1300020001010000123456753",
   1184         Some("00020001010000123456753"),
   1185     ),
   1186     (
   1187         "MT84MALT011000012345MTLCAST001S",
   1188         Some("MALT011000012345MTLCAST001S"),
   1189     ),
   1190     (
   1191         "MU17BOMM0101101030300200000MUR",
   1192         Some("BOMM0101101030300200000MUR"),
   1193     ),
   1194     (
   1195         "NI45BAPR00000013000003558124",
   1196         Some("BAPR00000013000003558124"),
   1197     ),
   1198     ("NL91ABNA0417164300", Some("ABNA0417164300")),
   1199     ("NO9386011117947", Some("86011117947")),
   1200     ("OM810180000001299123456", Some("0180000001299123456")),
   1201     ("PK36SCBL0000001123456702", Some("SCBL0000001123456702")),
   1202     (
   1203         "PL61109010140000071219812874",
   1204         Some("109010140000071219812874"),
   1205     ),
   1206     (
   1207         "PS92PALS000000000400123456702",
   1208         Some("PALS000000000400123456702"),
   1209     ),
   1210     ("PT50000201231234567890154", Some("000201231234567890154")),
   1211     (
   1212         "QA58DOHB00001234567890ABCDEFG",
   1213         Some("DOHB00001234567890ABCDEFG"),
   1214     ),
   1215     ("RO49AAAA1B31007593840000", Some("AAAA1B31007593840000")),
   1216     ("RS35260005601001611379", Some("260005601001611379")),
   1217     (
   1218         "RU0304452522540817810538091310419",
   1219         Some("04452522540817810538091310419"),
   1220     ),
   1221     ("SA0380000000608010167519", Some("80000000608010167519")),
   1222     (
   1223         "SC18SSCB11010000000000001497USD",
   1224         Some("SSCB11010000000000001497USD"),
   1225     ),
   1226     ("SD2129010501234001", Some("29010501234001")),
   1227     ("SE4550000000058398257466", Some("50000000058398257466")),
   1228     ("SI56263300012039086", Some("263300012039086")),
   1229     ("SK3112000000198742637541", Some("12000000198742637541")),
   1230     (
   1231         "SM86U0322509800000000270100",
   1232         Some("U0322509800000000270100"),
   1233     ),
   1234     ("SO211000001001000100141", Some("1000001001000100141")),
   1235     ("ST23000100010051845310146", Some("000100010051845310146")),
   1236     (
   1237         "SV62CENR00000000000000700025",
   1238         Some("CENR00000000000000700025"),
   1239     ),
   1240     ("TL380080012345678910157", Some("0080012345678910157")),
   1241     ("TN5910006035183598478831", Some("10006035183598478831")),
   1242     ("TR330006100519786457841326", Some("0006100519786457841326")),
   1243     (
   1244         "UA213223130000026007233566001",
   1245         Some("3223130000026007233566001"),
   1246     ),
   1247     ("VA59001123000012345678", Some("001123000012345678")),
   1248     ("VG96VPVG0000012345678901", Some("VPVG0000012345678901")),
   1249     ("XK051212012345678906", Some("1212012345678906")),
   1250     (
   1251         "YE15CBYE0001018861234567891234",
   1252         Some("CBYE0001018861234567891234"),
   1253     ),
   1254 ];