1use crate::config::FakerConfig;
4
5pub const U_LETTERS: [char; 26] = [
7 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
8 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
9];
10
11pub const L_LETTERS: [char; 26] = [
13 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
14 't', 'u', 'v', 'w', 'x', 'y', 'z',
15];
16
17pub const LETTERS: [char; 52] = {
19 let mut letters = [' '; 52];
20 let mut i = 0;
21 while i < 26 {
22 letters[i] = U_LETTERS[i];
23 letters[i + 26] = L_LETTERS[i];
24 i += 1;
25 }
26 letters
27};
28
29pub const DIGITS: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
31
32pub const HEX_UPPER: [char; 16] = [
34 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
35];
36
37pub const HEX_LOWER: [char; 16] = [
39 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
40];
41
42pub const ALPHANUMERIC: [char; 62] = {
44 let mut chars = [' '; 62];
45 let mut i = 0;
46 while i < 26 {
47 chars[i] = U_LETTERS[i];
48 chars[i + 26] = L_LETTERS[i];
49 i += 1;
50 }
51 let mut j = 0;
53 while j < 10 {
54 chars[52 + j] = DIGITS[j];
55 j += 1;
56 }
57 chars
58};
59
60pub fn numerify(template: &str) -> String {
63 let config = FakerConfig::current();
64 let mut result = String::new();
65 let mut chars = template.chars().peekable();
66
67 while let Some(c) = chars.next() {
68 if c == '#' {
69 let prev_is_hash = result.ends_with('#');
71 if !prev_is_hash {
72 let is_first_in_sequence = result.is_empty() || !result.ends_with('#');
74
75 if is_first_in_sequence && chars.peek().is_some() {
76 result.push(config.rand_char(&['1', '2', '3', '4', '5', '6', '7', '8', '9']));
78 } else {
79 result.push(config.rand_char(&DIGITS));
80 }
81 } else {
82 result.push(config.rand_char(&DIGITS));
83 }
84 } else {
85 result.push(c);
86 }
87 }
88
89 while result.contains("##") {
91 result = result.replace("##", "#");
92 }
93
94 result
95}
96
97pub fn letterify(template: &str) -> String {
99 let config = FakerConfig::current();
100 template.replace('?', &config.rand_char(&LETTERS).to_string())
101}
102
103pub fn bothify(template: &str) -> String {
105 letterify(&numerify(template))
106}
107
108pub fn sample<T: Clone>(items: &[T]) -> T {
110 FakerConfig::current().sample(items)
111}
112
113pub fn sample_many<T: Clone>(items: &[T], count: usize) -> Vec<T> {
115 let config = FakerConfig::current();
116 (0..count).map(|_| config.sample(items)).collect()
117}
118
119pub fn rand_in_range(min: u32, max: u32) -> u32 {
121 if max < min {
122 return min;
123 }
124 FakerConfig::current().rand_range(min, max)
125}
126
127pub fn parse(template: &str) -> String {
129 let mut result = template.to_string();
130
131 while result.contains("#{") {
134 if let Some(start) = result.find("#{") {
135 if let Some(end) = result[start..].find('}') {
136 let placeholder = &result[start + 2..start + end];
137 let replacement = fetch_value(placeholder);
138 result = format!(
139 "{}{}{}",
140 &result[..start],
141 replacement,
142 &result[start + end + 1..]
143 );
144 } else {
145 break;
146 }
147 } else {
148 break;
149 }
150 }
151
152 result
153}
154
155fn fetch_value(key: &str) -> String {
156 key.to_string()
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_numerify() {
167 let result = numerify("###");
168 assert_eq!(result.len(), 3);
169 assert!(result.chars().all(|c| c.is_ascii_digit()));
170 }
171
172 #[test]
173 fn test_letterify() {
174 let result = letterify("???");
175 assert_eq!(result.len(), 3);
176 assert!(result.chars().all(|c| c.is_alphabetic()));
177 }
178
179 #[test]
180 fn test_bothify() {
181 let result = bothify("???###");
182 assert_eq!(result.len(), 6);
183 }
184
185 #[test]
186 fn test_sample() {
187 let items = vec![1, 2, 3, 4, 5];
188 let result = sample(&items);
189 assert!(items.contains(&result));
190 }
191
192 #[test]
193 fn test_rand_in_range() {
194 let result = rand_in_range(1, 10);
195 assert!((1..=10).contains(&result));
196 }
197}