1pub fn is_valid(id: &str) -> bool {
10 if id.len() != 10 {
11 return false;
12 }
13 let mut a: [u8; 11] = [0; 11];
14 let mut iter = id.chars();
15 let first_letter = iter.next().unwrap();
16 if let 'A'...'Z' = first_letter {
17 let pair = code_map(first_letter);
18 a[0] = pair[0];
19 a[1] = pair[1];
20 } else {
21 return false;
22 }
23
24 let mut i = 2;
25 for c in iter {
26 if let '0'...'9' = c {
27 a[i] = c as u8 - '0' as u8;
28 i += 1;
29 } else {
30 return false;
31 }
32 }
33 sum(&a) % 10 == 0
34}
35
36pub fn generate() -> String {
39 generate_prefix("")
40}
41
42pub fn generate_prefix(prefix: &str) -> String {
60 if prefix.len() > 9 {
61 panic!("prefix is too long");
62 }
63
64 use rand::Rng;
65 let mut rng = rand::thread_rng();
66
67 if prefix.is_empty() {
68 return generate_prefix(&format!(
69 "{}{}",
70 rng.gen_range(b'A', b'Z') as char,
71 rng.gen_range(1, 3)
72 ));
73 }
74
75 if prefix.len() == 1 {
76 return generate_prefix(&format!("{}{}", prefix, rng.gen_range(1, 3)));
77 }
78
79 let first_letter = prefix.chars().next().unwrap();
80 if let 'A'...'Z' = first_letter {
81 } else {
82 panic!("prefix is not valid")
83 }
84
85 let pair = code_map(first_letter);
86 let mut a: [u8; 11] = [pair[0], pair[1], 0, 0, 0, 0, 0, 0, 0, 0, 0];
87 let mut a_index = 2;
88 for i in prefix[1..].chars() {
89 if let '0'...'9' = i {
90 } else {
91 panic!("prefix is not valid")
92 }
93 a[a_index] = i as u8 - '0' as u8;
94 a_index += 1;
95 }
96 let len = a.len() - 1;
97 for i in &mut a[a_index..len] {
98 *i = rng.gen::<u8>() % 10;
99 }
100 a[len] = (10 - (sum(&a) % 10) as u8) % 10;
101 a[prefix.len() + 1..]
102 .iter()
103 .fold(String::from(prefix), |s, i| s + &i.to_string())
104}
105
106fn sum(ary: &[u8]) -> u16 {
107 static MULTIPLIERS: [u8; 11] = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1];
108 ary.iter().enumerate().fold(0, |acc, (index, value)| {
109 acc + (MULTIPLIERS[index] * value) as u16
110 })
111}
112
113fn code_map(c: char) -> [u8; 2] {
114 static CODE_MAP: [[u8; 2]; 26] = [
115 [1, 0],
116 [1, 1],
117 [1, 2],
118 [1, 3],
119 [1, 4],
120 [1, 5],
121 [1, 6],
122 [1, 7],
123 [3, 4],
124 [1, 8],
125 [1, 9],
126 [2, 0],
127 [2, 1],
128 [2, 2],
129 [3, 5],
130 [2, 3],
131 [2, 4],
132 [2, 5],
133 [2, 6],
134 [2, 7],
135 [2, 8],
136 [2, 9],
137 [3, 2],
138 [3, 0],
139 [3, 1],
140 [3, 3],
141 ];
142 CODE_MAP[(c as u8 - 'A' as u8) as usize]
143}
144
145#[cfg(test)]
146mod tests {
147 #[test]
148 fn is_valid() {
149 assert!(super::is_valid("A123456789"));
150 assert!(!super::is_valid("A1234567899"));
151 assert!(!super::is_valid("Z123456789"));
152 assert!(!super::is_valid(""));
153 assert!(!super::is_valid("A一二三四五六七八九"));
154 }
155
156 #[test]
157 fn generate() {
158 let id = super::generate_prefix("A1");
159 assert!(id.starts_with("A1"));
160 assert!(super::is_valid(&id));
161
162 let id = super::generate_prefix("A");
163 assert!(id.starts_with("A"));
164 assert!(super::is_valid(&id));
165
166 let id = super::generate_prefix("");
167 assert!(super::is_valid(&id));
168
169 let id = super::generate();
170 assert!(super::is_valid(&id));
171 }
172}