1pub struct Rng {
26 state: u64,
27}
28
29impl Rng {
30 pub fn seeded(seed: u64) -> Self {
32 Self { state: seed }
33 }
34
35 pub fn next_u64(&mut self) -> u64 {
37 self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
38 let mut z = self.state;
39 z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
40 z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
41 z ^= z >> 31;
42 z
43 }
44
45 pub fn range(&mut self, n: u64) -> u64 {
49 if n == 0 {
50 return 0;
51 }
52 self.next_u64() % n
53 }
54}
55
56pub mod csv {
58 use super::Rng;
59
60 pub fn generate<F>(headers: &[&str], rows: usize, seed: u64, mut row_factory: F) -> String
77 where
78 F: FnMut(&mut Rng) -> Vec<String>,
79 {
80 let mut rng = Rng::seeded(seed);
81 let mut out = String::new();
82 out.push_str(&headers.join(","));
83 out.push('\n');
84 for _ in 0..rows {
85 let row = row_factory(&mut rng);
86 out.push_str(&row.join(","));
87 out.push('\n');
88 }
89 out
90 }
91}
92
93pub mod json_array {
95 use super::Rng;
96
97 pub fn generate<F>(count: usize, seed: u64, mut element_factory: F) -> String
112 where
113 F: FnMut(&mut Rng) -> String,
114 {
115 let mut rng = Rng::seeded(seed);
116 let mut out = String::new();
117 out.push('[');
118 for i in 0..count {
119 if i > 0 {
120 out.push(',');
121 }
122 out.push_str(&element_factory(&mut rng));
123 }
124 out.push(']');
125 out
126 }
127}
128
129pub mod bytes {
131 use super::Rng;
132
133 pub fn zeros(n: usize) -> Vec<u8> {
135 vec![0u8; n]
136 }
137
138 pub fn patterned(n: usize, pattern: &[u8]) -> Vec<u8> {
148 if pattern.is_empty() {
149 return zeros(n);
150 }
151 let mut out = Vec::with_capacity(n);
152 while out.len() < n {
153 out.push(pattern[out.len() % pattern.len()]);
154 }
155 out
156 }
157
158 pub fn random(n: usize, seed: u64) -> Vec<u8> {
160 let mut rng = Rng::seeded(seed);
161 let mut out = Vec::with_capacity(n);
162 while out.len() < n {
163 let v = rng.next_u64();
164 for b in v.to_le_bytes() {
165 if out.len() < n {
166 out.push(b);
167 }
168 }
169 }
170 out
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn rng_is_deterministic() {
180 let mut a = Rng::seeded(42);
181 let mut b = Rng::seeded(42);
182 for _ in 0..16 {
183 assert_eq!(a.next_u64(), b.next_u64());
184 }
185 }
186
187 #[test]
188 fn rng_differs_with_seed() {
189 let mut a = Rng::seeded(1);
190 let mut b = Rng::seeded(2);
191 assert_ne!(a.next_u64(), b.next_u64());
192 }
193
194 #[test]
195 fn rng_range_bounds() {
196 let mut r = Rng::seeded(7);
197 for _ in 0..1000 {
198 let v = r.range(10);
199 assert!(v < 10);
200 }
201 assert_eq!(Rng::seeded(0).range(0), 0);
202 }
203
204 #[test]
205 fn csv_generate_is_deterministic() {
206 let g = |seed| {
207 csv::generate(&["a", "b"], 5, seed, |rng| {
208 vec![rng.range(100).to_string(), rng.range(100).to_string()]
209 })
210 };
211 assert_eq!(g(42), g(42));
212 assert_ne!(g(42), g(43));
213 }
214
215 #[test]
216 fn csv_has_header_and_row_count() {
217 let csv = csv::generate(&["x", "y"], 3, 0, |rng| {
218 vec![rng.range(10).to_string(), rng.range(10).to_string()]
219 });
220 assert!(csv.starts_with("x,y\n"));
221 assert_eq!(csv.lines().count(), 4);
222 }
223
224 #[test]
225 fn json_array_round_trip_shape() {
226 let json = json_array::generate(3, 0, |rng| format!("{{\"id\":{}}}", rng.range(100)));
227 assert!(json.starts_with("["));
228 assert!(json.ends_with("]"));
229 assert_eq!(json.matches(',').count(), 2);
231 }
232
233 #[test]
234 fn bytes_zeros_and_patterned() {
235 assert_eq!(bytes::zeros(4), vec![0, 0, 0, 0]);
236 assert_eq!(bytes::patterned(5, &[1, 2]), vec![1, 2, 1, 2, 1]);
237 assert_eq!(bytes::patterned(3, &[]), vec![0, 0, 0]);
238 }
239
240 #[test]
241 fn bytes_random_is_deterministic() {
242 assert_eq!(bytes::random(64, 7), bytes::random(64, 7));
243 assert_ne!(bytes::random(64, 7), bytes::random(64, 8));
244 }
245}