1use once_cell::sync::Lazy;
4use rand::Rng;
5use rand::seq::SliceRandom;
6use std::fs;
7
8static PHONE_PREFIXES_CN: Lazy<Vec<String>> =
10 Lazy::new(|| load_data_from_file("data/generators/number/phone_prefixes_cn.txt"));
11
12static AREA_CODES_CN: Lazy<Vec<String>> =
14 Lazy::new(|| load_data_from_file("data/generators/number/area_codes_cn.txt"));
15
16fn load_data_from_file(file_path: &str) -> Vec<String> {
18 match fs::read_to_string(file_path) {
19 Ok(content) => content
20 .lines()
21 .map(|line| line.trim().to_string())
22 .filter(|line| !line.is_empty())
23 .collect(),
24 Err(_) => {
25 match file_path {
27 "data/generators/number/phone_prefixes_cn.txt" => vec![
28 "130".to_string(),
29 "131".to_string(),
30 "132".to_string(),
31 "133".to_string(),
32 "134".to_string(),
33 "135".to_string(),
34 ],
35 "data/generators/number/area_codes_cn.txt" => vec![
36 "110000".to_string(),
37 "120000".to_string(),
38 "130000".to_string(),
39 "140000".to_string(),
40 "150000".to_string(),
41 "210000".to_string(),
42 ],
43 _ => vec!["Default".to_string()],
44 }
45 }
46 }
47}
48
49pub fn integer(min: i64, max: i64) -> i64 {
51 let mut rng = rand::thread_rng();
52 rng.gen_range(min..=max)
53}
54
55pub fn float(min: f64, max: f64) -> f64 {
57 let mut rng = rand::thread_rng();
58 rng.gen_range(min..=max)
59}
60
61pub fn float_with_precision(min: f64, max: f64, precision: usize) -> f64 {
63 let value = float(min, max);
64 let multiplier = 10_f64.powi(precision as i32);
65 (value * multiplier).round() / multiplier
66}
67
68pub fn positive_integer(max: i64) -> i64 {
70 integer(1, max)
71}
72
73pub fn negative_integer(min: i64) -> i64 {
75 integer(min, -1)
76}
77
78pub fn percentage() -> f64 {
80 float(0.0, 100.0)
81}
82
83pub fn probability() -> f64 {
85 float(0.0, 1.0)
86}
87
88pub fn currency(min: f64, max: f64) -> f64 {
90 float_with_precision(min, max, 2)
91}
92
93pub fn age() -> u8 {
95 let mut rng = rand::thread_rng();
96 rng.gen_range(1..=120)
97}
98
99pub fn adult_age() -> u8 {
101 let mut rng = rand::thread_rng();
102 rng.gen_range(18..=80)
103}
104
105pub fn child_age() -> u8 {
107 let mut rng = rand::thread_rng();
108 rng.gen_range(1..=17)
109}
110
111pub fn score() -> u8 {
113 let mut rng = rand::thread_rng();
114 rng.gen_range(0..=100)
115}
116
117pub fn passing_score() -> u8 {
119 let mut rng = rand::thread_rng();
120 rng.gen_range(60..=100)
121}
122
123pub fn failing_score() -> u8 {
125 let mut rng = rand::thread_rng();
126 rng.gen_range(0..=59)
127}
128
129pub fn temperature_celsius() -> f64 {
131 float_with_precision(-50.0, 50.0, 1)
132}
133
134pub fn temperature_fahrenheit() -> f64 {
136 float_with_precision(-58.0, 122.0, 1)
137}
138
139pub fn random_int(min: i32, max: i32) -> i32 {
141 let mut rng = rand::thread_rng();
142 rng.gen_range(min..=max)
143}
144
145pub fn random_float(min: f64, max: f64) -> f64 {
147 let mut rng = rand::thread_rng();
148 rng.gen_range(min..=max)
149}
150
151pub fn weight_kg() -> f64 {
153 float_with_precision(40.0, 150.0, 1)
154}
155
156pub fn bmi() -> f64 {
158 float_with_precision(15.0, 40.0, 1)
159}
160
161pub fn credit_card_number() -> String {
163 let mut rng = rand::thread_rng();
164 (0..16)
165 .map(|_| rng.gen_range(0..=9).to_string())
166 .collect::<Vec<_>>()
167 .join("")
168}
169
170pub fn phone_number_cn() -> String {
172 let mut rng = rand::thread_rng();
173 use rand::seq::SliceRandom;
174
175 let prefix = PHONE_PREFIXES_CN.choose(&mut rng).unwrap();
176 let suffix: String = (0..8).map(|_| rng.gen_range(0..=9).to_string()).collect();
177
178 format!("{}{}", prefix, suffix)
179}
180
181pub fn teenager_age() -> u8 {
183 let mut rng = rand::thread_rng();
184 rng.gen_range(13..=19)
185}
186
187pub fn senior_age() -> u8 {
189 let mut rng = rand::thread_rng();
190 rng.gen_range(60..=100)
191}
192
193pub fn price() -> f64 {
195 let mut rng = rand::thread_rng();
196 rng.gen_range(0.01..=9999.99)
197}
198
199pub fn salary() -> u32 {
201 let mut rng = rand::thread_rng();
202 rng.gen_range(20000..=1000000)
203}
204
205pub fn phone_number() -> String {
207 phone_number_cn()
208}
209
210pub fn credit_card() -> String {
212 credit_card_number()
213}
214
215pub fn bank_card_cn() -> String {
217 let mut rng = rand::thread_rng();
218 let prefixes = ["6225", "6227", "6228", "6229", "6230"]; let prefix = prefixes.choose(&mut rng).unwrap();
220 let remaining_digits: String = (0..12)
221 .map(|_| rng.gen_range(0..=9).to_string())
222 .collect();
223 format!("{}{}", prefix, remaining_digits)
224}
225
226pub fn id_card_cn() -> String {
228 let mut rng = rand::thread_rng();
229 use rand::seq::SliceRandom;
230
231 let area_code = AREA_CODES_CN.choose(&mut rng).unwrap();
233
234 let year = rng.gen_range(1950..=2005);
236 let month = rng.gen_range(1..=12);
237 let day = rng.gen_range(1..=28);
238 let birth_date = format!("{:04}{:02}{:02}", year, month, day);
239
240 let sequence = format!("{:03}", rng.gen_range(1..=999));
242
243 let first_17 = format!("{}{}{}", area_code, birth_date, sequence);
245
246 let check_digit = calculate_id_check_digit(&first_17);
248
249 format!("{}{}", first_17, check_digit)
250}
251
252fn calculate_id_check_digit(first_17: &str) -> char {
254 let weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
255 let check_chars = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
256
257 let sum: usize = first_17
258 .chars()
259 .enumerate()
260 .map(|(i, c)| c.to_digit(10).unwrap() as usize * weights[i])
261 .sum();
262
263 check_chars[sum % 11]
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269
270 #[test]
271 fn test_integer() {
272 let num = integer(1, 10);
273 assert!(num >= 1 && num <= 10);
274 }
275
276 #[test]
277 fn test_float_with_precision() {
278 let num = float_with_precision(1.0, 2.0, 2);
279 let decimal_places = format!("{:.10}", num)
280 .split('.')
281 .nth(1)
282 .unwrap()
283 .trim_end_matches('0')
284 .len();
285 assert!(decimal_places <= 2);
286 }
287
288 #[test]
289 fn test_adult_age() {
290 let age = adult_age();
291 assert!(age >= 18 && age <= 80);
292 }
293
294 #[test]
295 fn test_phone_number_cn() {
296 let phone = phone_number_cn();
297 assert_eq!(phone.len(), 11);
298 assert!(phone.starts_with('1'));
299 }
300
301 #[test]
302 fn test_id_card_cn() {
303 let id = id_card_cn();
304 assert_eq!(id.len(), 18);
305 assert!(id.chars().take(17).all(|c| c.is_ascii_digit()));
306 }
307
308 #[test]
309 fn test_credit_card_number() {
310 let card = credit_card_number();
311 assert_eq!(card.len(), 16);
312 assert!(card.chars().all(|c| c.is_ascii_digit()));
313 }
314}