1use super::{Collection, Generator, TestCase, labels};
2use crate::control::hegel_internal_assert;
3use crate::test_case::invalid_argument;
4use std::collections::{HashMap, HashSet};
5use std::hash::Hash;
6use std::marker::PhantomData;
7
8pub struct VecGenerator<G, T> {
10 pub(crate) elements: G,
11 pub(crate) min_size: usize,
12 pub(crate) max_size: Option<usize>,
13 pub(crate) unique_by: Option<fn(&T, &T) -> bool>,
14 pub(crate) _phantom: PhantomData<fn(T)>,
15}
16
17impl<G, T> VecGenerator<G, T> {
18 pub fn min_size(mut self, min_size: usize) -> Self {
20 self.min_size = min_size;
21 self
22 }
23
24 pub fn max_size(mut self, max_size: usize) -> Self {
26 self.max_size = Some(max_size);
27 self
28 }
29}
30
31impl<G, T: PartialEq> VecGenerator<G, T> {
32 pub fn unique(mut self, unique: bool) -> Self {
34 self.unique_by = if unique {
35 Some(<T as PartialEq>::eq)
36 } else {
37 None
38 };
39 self
40 }
41}
42
43impl<T, G> Generator<Vec<T>> for VecGenerator<G, T>
44where
45 G: Generator<T>,
46{
47 fn do_draw(&self, tc: &TestCase) -> Vec<T> {
48 if let Some(max) = self.max_size {
49 if self.min_size > max {
50 invalid_argument!("Cannot have max_size < min_size");
51 }
52 }
53 tc.start_span(labels::LIST);
54 let mut collection = Collection::new(tc, self.min_size, self.max_size);
55 let mut result = Vec::new();
56 while collection.more() {
57 let element = self.elements.do_draw(tc);
58 if let Some(eq_fn) = &self.unique_by {
59 if result.iter().any(|existing| eq_fn(existing, &element)) {
60 collection.reject(Some("duplicate element"));
61 continue;
62 }
63 }
64 result.push(element);
65 }
66 tc.stop_span(false);
67 result
68 }
69}
70
71pub fn vecs<T, G: Generator<T>>(elements: G) -> VecGenerator<G, T> {
89 VecGenerator {
90 elements,
91 min_size: 0,
92 max_size: None,
93 unique_by: None,
94 _phantom: PhantomData,
95 }
96}
97
98pub struct HashSetGenerator<G, T> {
100 elements: G,
101 min_size: usize,
102 max_size: Option<usize>,
103 _phantom: PhantomData<fn(T)>,
104}
105
106impl<G, T> HashSetGenerator<G, T> {
107 pub fn min_size(mut self, min_size: usize) -> Self {
109 self.min_size = min_size;
110 self
111 }
112
113 pub fn max_size(mut self, max_size: usize) -> Self {
115 self.max_size = Some(max_size);
116 self
117 }
118}
119
120const MAX_UNIQUE_POOL: usize = 10_000;
124
125impl<T, G> Generator<HashSet<T>> for HashSetGenerator<G, T>
126where
127 G: Generator<T>,
128 T: Eq + Hash,
129{
130 fn do_draw(&self, tc: &TestCase) -> HashSet<T> {
131 if let Some(max) = self.max_size {
132 if self.min_size > max {
133 invalid_argument!("Cannot have max_size < min_size");
134 }
135 }
136 tc.start_span(labels::SET);
137 let set = match self.enumerated_pool() {
138 Some(pool) => self.draw_from_pool(tc, pool),
139 None => self.draw_by_rejection(tc),
140 };
141 tc.stop_span(false);
142 set
143 }
144}
145
146impl<T, G> HashSetGenerator<G, T>
147where
148 G: Generator<T>,
149 T: Eq + Hash,
150{
151 fn enumerated_pool(&self) -> Option<Vec<T>> {
155 let values = self.elements.enumerate_values()?;
156 if values.is_empty() || values.len() > MAX_UNIQUE_POOL {
157 return None;
158 }
159 let mut by_hash: HashMap<u64, Vec<usize>> = HashMap::new();
160 let mut pool: Vec<T> = Vec::new();
161 for v in values {
162 let bucket = by_hash.entry(fingerprint(&v)).or_default();
163 if bucket.iter().any(|&i| pool[i] == v) {
164 continue;
165 }
166 bucket.push(pool.len());
167 pool.push(v);
168 }
169 Some(pool)
170 }
171
172 fn draw_from_pool(&self, tc: &TestCase, mut remaining: Vec<T>) -> HashSet<T> {
177 if self.min_size > remaining.len() {
178 invalid_argument!(
179 "Cannot generate a set: min_size {} is larger than the {} distinct values the element generator can produce",
180 self.min_size,
181 remaining.len()
182 );
183 }
184 let effective_max = self
185 .max_size
186 .map_or(remaining.len(), |m| m.min(remaining.len()));
187 let mut collection = Collection::new(tc, self.min_size, Some(effective_max));
188 let mut set = HashSet::new();
189 loop {
190 if remaining.is_empty() || !collection.more() {
191 break;
192 }
193 let j = tc.generate_integer_i64(0, remaining.len() as i64 - 1) as usize;
194 set.insert(remaining.remove(j));
195 }
196 set
197 }
198
199 fn draw_by_rejection(&self, tc: &TestCase) -> HashSet<T> {
200 let mut collection = Collection::new(tc, self.min_size, self.max_size);
201 let mut set = HashSet::new();
202 while collection.more() {
203 let element = self.elements.do_draw(tc);
204 if !set.insert(element) {
205 collection.reject(Some("duplicate element"));
206 }
207 }
208 hegel_internal_assert!(set.len() >= self.min_size);
209 set
210 }
211}
212
213fn fingerprint<T: Eq + Hash>(v: &T) -> u64 {
216 use std::hash::{DefaultHasher, Hasher};
217 let mut h = DefaultHasher::new();
218 v.hash(&mut h);
219 h.finish()
220}
221
222pub fn hashsets<T, G: Generator<T>>(elements: G) -> HashSetGenerator<G, T> {
226 HashSetGenerator {
227 elements,
228 min_size: 0,
229 max_size: None,
230 _phantom: PhantomData,
231 }
232}
233
234pub struct HashMapGenerator<K, V, KT, VT> {
236 keys: K,
237 values: V,
238 min_size: usize,
239 max_size: Option<usize>,
240 _phantom: PhantomData<fn(KT, VT)>,
241}
242
243impl<K, V, KT, VT> HashMapGenerator<K, V, KT, VT> {
244 pub fn min_size(mut self, min_size: usize) -> Self {
246 self.min_size = min_size;
247 self
248 }
249
250 pub fn max_size(mut self, max_size: usize) -> Self {
252 self.max_size = Some(max_size);
253 self
254 }
255}
256
257impl<K, V, KT, VT> Generator<HashMap<KT, VT>> for HashMapGenerator<K, V, KT, VT>
258where
259 K: Generator<KT>,
260 V: Generator<VT>,
261 KT: Eq + std::hash::Hash,
262{
263 fn do_draw(&self, tc: &TestCase) -> HashMap<KT, VT> {
264 if let Some(max) = self.max_size {
265 if self.min_size > max {
266 invalid_argument!("Cannot have max_size < min_size");
267 }
268 }
269 tc.start_span(labels::MAP);
270 let map = match self.enumerated_key_pool() {
271 Some(pool) => self.draw_from_key_pool(tc, pool),
272 None => self.draw_by_rejection(tc),
273 };
274 tc.stop_span(false);
275 map
276 }
277}
278
279impl<K, V, KT, VT> HashMapGenerator<K, V, KT, VT>
280where
281 K: Generator<KT>,
282 V: Generator<VT>,
283 KT: Eq + std::hash::Hash,
284{
285 fn enumerated_key_pool(&self) -> Option<Vec<KT>> {
289 let values = self.keys.enumerate_values()?;
290 if values.is_empty() || values.len() > MAX_UNIQUE_POOL {
291 return None;
292 }
293 let mut by_hash: HashMap<u64, Vec<usize>> = HashMap::new();
294 let mut pool: Vec<KT> = Vec::new();
295 for v in values {
296 let bucket = by_hash.entry(fingerprint(&v)).or_default();
297 if bucket.iter().any(|&i| pool[i] == v) {
298 continue;
299 }
300 bucket.push(pool.len());
301 pool.push(v);
302 }
303 Some(pool)
304 }
305
306 fn draw_from_key_pool(&self, tc: &TestCase, mut remaining: Vec<KT>) -> HashMap<KT, VT> {
310 if self.min_size > remaining.len() {
311 invalid_argument!(
312 "Cannot generate a map: min_size {} is larger than the {} distinct keys the key generator can produce",
313 self.min_size,
314 remaining.len()
315 );
316 }
317 let effective_max = self
318 .max_size
319 .map_or(remaining.len(), |m| m.min(remaining.len()));
320 let mut collection = Collection::new(tc, self.min_size, Some(effective_max));
321 let mut map = HashMap::new();
322 loop {
323 if remaining.is_empty() || !collection.more() {
324 break;
325 }
326 let j = tc.generate_integer_i64(0, remaining.len() as i64 - 1) as usize;
327 let key = remaining.remove(j);
328 let value = self.values.do_draw(tc);
329 map.insert(key, value);
330 }
331 map
332 }
333
334 fn draw_by_rejection(&self, tc: &TestCase) -> HashMap<KT, VT> {
335 let mut collection = Collection::new(tc, self.min_size, self.max_size);
336 let mut map = HashMap::new();
337 while collection.more() {
338 let key = self.keys.do_draw(tc);
339 match map.entry(key) {
340 std::collections::hash_map::Entry::Occupied(_) => {
341 collection.reject(Some("duplicate key"));
342 }
343 std::collections::hash_map::Entry::Vacant(entry) => {
344 let value = self.values.do_draw(tc);
345 entry.insert(value);
346 }
347 }
348 }
349 hegel_internal_assert!(map.len() >= self.min_size);
350 map
351 }
352}
353
354pub fn hashmaps<KT, VT, K: Generator<KT>, V: Generator<VT>>(
367 keys: K,
368 values: V,
369) -> HashMapGenerator<K, V, KT, VT> {
370 HashMapGenerator {
371 keys,
372 values,
373 min_size: 0,
374 max_size: None,
375 _phantom: PhantomData,
376 }
377}
378
379pub struct ArrayGenerator<G, T, const N: usize> {
381 element: G,
382 _phantom: PhantomData<fn() -> T>,
383}
384
385impl<G, T, const N: usize> ArrayGenerator<G, T, N> {
386 #[doc(hidden)]
387 pub fn new(element: G) -> Self {
388 ArrayGenerator {
389 element,
390 _phantom: PhantomData,
391 }
392 }
393}
394
395pub fn arrays<G: Generator<T> + Send + Sync, T, const N: usize>(
397 element: G,
398) -> ArrayGenerator<G, T, N> {
399 ArrayGenerator::new(element)
400}
401
402impl<G: Generator<T> + Send + Sync, T, const N: usize> Generator<[T; N]>
403 for ArrayGenerator<G, T, N>
404{
405 fn do_draw(&self, tc: &TestCase) -> [T; N] {
406 tc.start_span(labels::TUPLE);
407 let result = std::array::from_fn(|_| self.element.do_draw(tc));
408 tc.stop_span(false);
409 result
410 }
411}