1use rand::Rng;
2
3use crate::location_values;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq)]
10pub enum Sex {
11 Male,
13 Female,
15}
16
17fn generate_2_to_9_and_create_string<R: Rng>(mut buffer: Vec<u8>, mut rng: R) -> String {
18 for e in buffer[2..=8].iter_mut() {
19 *e = rng.gen_range(b'0'..=b'9');
20 }
21
22 let mut sum = location_values::LOCATION_VALUES[(buffer[0] - b'A') as usize] as u16;
23
24 for (i, e) in buffer[1..=8].iter().enumerate() {
25 sum += ((e - b'0') * (8 - i as u8)) as u16;
26 }
27
28 buffer[9] = ((10 - sum % 10) % 10) as u8 + b'0';
29
30 unsafe { String::from_utf8_unchecked(buffer) }
31}
32
33#[inline]
34fn generate_continue_national<R: Rng>(mut buffer: Vec<u8>, mut rng: R) -> String {
35 buffer[0] = rng.gen_range(b'A'..=b'Z');
36
37 generate_2_to_9_and_create_string(buffer, rng)
38}
39
40#[inline]
41fn generate_continue_resident<R: Rng>(mut buffer: Vec<u8>, mut rng: R) -> String {
42 buffer[0] = {
43 let mut rnd = rng.gen_range(b'A'..(b'A' + 22));
44
45 if rnd >= b'A' + 21 {
46 rnd += 4;
47 } else if rnd >= b'A' + 16 {
48 rnd += 3;
49 } else if rnd >= b'A' + 11 {
50 rnd += 1;
51 }
52
53 rnd
54 };
55
56 generate_2_to_9_and_create_string(buffer, rng)
57}
58
59pub fn generate_national_with_rng<R: Rng>(sex: Option<Sex>, mut rng: R) -> String {
61 let mut buffer = vec![0u8; 10];
62
63 buffer[1] = match sex {
64 Some(Sex::Male) => b'1',
65 Some(Sex::Female) => b'2',
66 None => rng.gen_range(b'1'..=b'2'),
67 };
68
69 generate_continue_national(buffer, rng)
70}
71
72#[inline]
74pub fn generate_national(sex: Option<Sex>) -> String {
75 generate_national_with_rng(sex, rand::thread_rng())
76}
77
78pub fn generate_resident_with_rng<R: Rng>(sex: Option<Sex>, mut rng: R) -> String {
80 let mut buffer = vec![0u8; 10];
81
82 buffer[1] = match sex {
83 Some(Sex::Male) => b'8',
84 Some(Sex::Female) => b'9',
85 None => rng.gen_range(b'8'..=b'9'),
86 };
87
88 generate_continue_resident(buffer, rng)
89}
90
91#[inline]
93pub fn generate_resident(sex: Option<Sex>) -> String {
94 generate_resident_with_rng(sex, rand::thread_rng())
95}
96
97pub fn generate_with_rng<R: Rng>(sex: Option<Sex>, mut rng: R) -> String {
99 let mut buffer = vec![0u8; 10];
100
101 buffer[1] = match sex {
102 Some(Sex::Male) => {
103 let rnd = rng.gen_range(1u8..=2);
104
105 if rnd == 1 {
106 b'1'
107 } else {
108 b'8'
109 }
110 },
111 Some(Sex::Female) => {
112 let rnd = rng.gen_range(1u8..=2);
113
114 if rnd == 1 {
115 b'2'
116 } else {
117 b'9'
118 }
119 },
120 None => {
121 let rnd = rng.gen_range(1u8..=4);
122
123 match rnd {
124 1 => b'1',
125 2 => b'2',
126 3 => b'8',
127 4 => b'9',
128 _ => unreachable!(),
129 }
130 },
131 };
132
133 if buffer[1] <= b'2' {
134 generate_continue_national(buffer, rng)
135 } else {
136 generate_continue_resident(buffer, rng)
137 }
138}
139
140#[inline]
142pub fn generate(sex: Option<Sex>) -> String {
143 generate_with_rng(sex, rand::thread_rng())
144}