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 ];