1use crate::ValidationError;
2
3pub fn validate(input: &str) -> Result<(), ValidationError> {
26 let input = input.trim().to_uppercase();
27
28 if !input.starts_with("EC") {
29 return Err(ValidationError::InvalidFormat);
30 }
31
32 if input.len() != 24 {
33 return Err(ValidationError::InvalidLength);
34 }
35
36 if !input.chars().all(|c| c.is_ascii_alphanumeric()) {
37 return Err(ValidationError::InvalidFormat);
38 }
39
40 let rearranged: String = input[4..].to_string() + &input[..4];
41
42 let mut remainder = 0u32;
43
44 for c in rearranged.chars() {
45 if c.is_ascii_digit() {
46 let digit = c as u32 - '0' as u32;
47 if digit <= 9 {
48 remainder = (remainder * 10 + digit) % 97;
49 } else {
50 return Err(ValidationError::InvalidFormat);
51 }
52 } else {
53 let value = (c as u32) - ('A' as u32) + 10;
54 if (10..=35).contains(&value) {
55 remainder = (remainder * 100 + value) % 97;
56 } else {
57 return Err(ValidationError::InvalidFormat);
58 }
59 }
60 }
61
62 if remainder != 1 {
63 return Err(ValidationError::InvalidCheckDigit);
64 }
65
66 Ok(())
67}
68
69pub fn is_valid(input: &str) -> bool {
83 validate(input).is_ok()
84}
85
86pub fn format(input: &str) -> Option<String> {
105 if validate(input).is_ok() {
106 let input = input.trim().to_uppercase();
107 let chars: Vec<char> = input.chars().collect();
108 let mut result = String::new();
109
110 for (i, c) in chars.iter().enumerate() {
111 if i > 0 && i % 4 == 0 {
112 result.push(' ');
113 }
114 result.push(*c);
115 }
116
117 Some(result)
118 } else {
119 None
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn valid_iban() {
129 let result = validate("EC8912345678901234567890");
130 assert!(result.is_err());
131 }
132
133 #[test]
134 fn wrong_country() {
135 assert_eq!(
136 validate("XX1234567890123456789012"),
137 Err(ValidationError::InvalidFormat)
138 );
139 }
140
141 #[test]
142 fn wrong_length() {
143 assert_eq!(
144 validate("EC12345678901234567890123"),
145 Err(ValidationError::InvalidLength)
146 );
147 }
148
149 #[test]
150 fn wrong_check_digit() {
151 assert_eq!(
152 validate("EC9912345678901234567890"),
153 Err(ValidationError::InvalidCheckDigit)
154 );
155 }
156
157 #[test]
158 fn format_invalid() {
159 assert!(format("invalid").is_none());
160 }
161}