11#[ derive( Debug , thiserror:: Error ) ]
22pub enum Error {
33 #[ error( "Not valid: The length should be 9, [X/Y/Z] + [7 numbers] + [Check digit]. Got {0} characters." ) ]
4- BadLenght ( usize ) ,
4+ BadLength ( usize ) ,
55 #[ error( "Not valid: The first character should be a 'X', 'Y' or 'Z'. Got {0}" ) ]
66 NieBadPrefix ( char ) ,
77 #[ error( "Not valid: Char '{0}' at position {1} is not a number" ) ]
@@ -10,35 +10,34 @@ pub enum Error {
1010 InvalidCheckNumber ( char , char ) ,
1111}
1212
13+ const NIF_LETTERS : [ char ; 23 ] = [
14+ 'T' , 'R' , 'W' , 'A' , 'G' , 'M' , 'Y' , 'F' , 'P' , 'D' , 'X' , 'B' , 'N' , 'J' , 'Z' , 'S' , 'Q' , 'V' ,
15+ 'H' , 'L' , 'C' , 'K' , 'E' ,
16+ ] ;
17+
18+ #[ inline]
1319pub fn check_digit_nif ( val : u32 ) -> char {
1420 // Calculates the check digit based on the remainder.
15- let letters: [ char ; 23 ] = [
16- 'T' , 'R' , 'W' , 'A' , 'G' , 'M' , 'Y' , 'F' , 'P' , 'D' , 'X' , 'B' , 'N' , 'J' , 'Z' , 'S' , 'Q' , 'V' ,
17- 'H' , 'L' , 'C' , 'K' , 'E' ,
18- ] ;
1921 let remainder = val % 23 ;
20- letters [ remainder as usize ]
22+ NIF_LETTERS [ remainder as usize ]
2123}
2224
2325pub fn is_valid_nie ( v : & str ) -> Result < ( ) , Error > {
2426 // Validate a NIE - Número de Identidad de Extranjero (NIE)
2527 // https://es.wikipedia.org/wiki/N%C3%BAmero_de_identidad_de_extranjero
26- //
27- // Note that this function only considers a NIE valid under the INT/2058/2008 regulation.
28+ // Only considers validity under INT/2058/2008 regulation.
29+
2830 if v. len ( ) != 9 {
29- Err ( Error :: BadLenght ( v. len ( ) ) ) ?
31+ Err ( Error :: BadLength ( v. len ( ) ) ) ?
3032 }
3133
3234 let first_letter = v. chars ( ) . next ( ) . unwrap ( ) . to_ascii_lowercase ( ) ;
3335
34- let value = if first_letter == 'x' {
35- 0
36- } else if first_letter == 'y' {
37- 1
38- } else if first_letter == 'z' {
39- 2
40- } else {
41- Err ( Error :: NieBadPrefix ( first_letter) ) ?
36+ let value = match first_letter {
37+ 'x' => 0 ,
38+ 'y' => 1 ,
39+ 'z' => 2 ,
40+ other => return Err ( Error :: NieBadPrefix ( other) ) ,
4241 } ;
4342
4443 let numbers = & v[ 1 ..v. len ( ) ] ;
@@ -49,10 +48,10 @@ pub fn is_valid_nif(v: &str) -> Result<(), Error> {
4948 // Validate a NIF - Número de Identificación Fiscal (NIF)
5049 // https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_fiscal
5150 if v. len ( ) != 9 {
52- Err ( Error :: BadLenght ( v. len ( ) ) ) ?
51+ Err ( Error :: BadLength ( v. len ( ) ) ) ?
5352 }
5453
55- let letter = v. chars ( ) . last ( ) . unwrap ( ) ;
54+ let letter = v. chars ( ) . last ( ) . unwrap ( ) . to_ascii_uppercase ( ) ;
5655 let numbers = & v[ ..v. len ( ) - 1 ] ;
5756
5857 for ( index, c) in numbers. chars ( ) . enumerate ( ) {
@@ -91,8 +90,19 @@ mod tests {
9190 assert_ne ! ( check_digit_nif( 00000000 ) , 'D' ) ;
9291 }
9392
93+ #[ test]
94+ fn test_valid_nif ( ) {
95+ is_valid_nif ( "24591177Z" ) . unwrap ( ) ;
96+ is_valid_nif ( "21178533h" ) . unwrap ( ) ;
97+ is_valid_nif ( "84731432F" ) . unwrap ( ) ;
98+ is_valid_nif ( "65553805X" ) . unwrap ( ) ;
99+ is_valid_nif ( "97294190g" ) . unwrap ( ) ;
100+ }
101+
94102 #[ test]
95103 fn test_invalid_nif ( ) {
104+ is_valid_nif ( "" ) . unwrap_err ( ) ;
105+ is_valid_nif ( "5393710G " ) . unwrap_err ( ) ;
96106 is_valid_nif ( "53493710G" ) . unwrap_err ( ) ;
97107 is_valid_nif ( "6´420582W" ) . unwrap_err ( ) ;
98108 is_valid_nif ( "X6725600C" ) . unwrap_err ( ) ;
0 commit comments