tw_id_num/
generate.rs

1use rand::Rng;
2
3use crate::location_values;
4
5/// 性別。
6///
7/// * 國民身分證統一編號:男性為**1**;女性為**2**。
8/// * 新式外來人口統一證號:男性為**8**;女性為**9**。
9#[derive(Debug, Copy, Clone, Eq, PartialEq)]
10pub enum Sex {
11    /// 男性
12    Male,
13    /// 女性
14    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
59/// 產生國民身分證統一編號。
60pub 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/// 產生國民身分證統一編號。
73#[inline]
74pub fn generate_national(sex: Option<Sex>) -> String {
75    generate_national_with_rng(sex, rand::thread_rng())
76}
77
78/// 產生新式外來人口統一證號。
79pub 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/// 產生新式外來人口統一證號。
92#[inline]
93pub fn generate_resident(sex: Option<Sex>) -> String {
94    generate_resident_with_rng(sex, rand::thread_rng())
95}
96
97/// 產生國民身分證統一編號或是新式外來人口統一證號。
98pub 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/// 產生國民身分證統一編號或是新式外來人口統一證號。
141#[inline]
142pub fn generate(sex: Option<Sex>) -> String {
143    generate_with_rng(sex, rand::thread_rng())
144}