1use super::{BasicGenerator, BoxedGenerator, Collection, Generator, TestCase, labels};
2use crate::cbor_utils::{cbor_map, map_insert};
3use ciborium::Value;
4use std::collections::{HashMap, HashSet};
5use std::hash::Hash;
6use std::marker::PhantomData;
7use std::sync::Arc;
8
9pub struct VecGenerator<G, T> {
11 pub(crate) elements: G,
12 pub(crate) min_size: usize,
13 pub(crate) max_size: Option<usize>,
14 pub(crate) unique_by: Option<fn(&T, &T) -> bool>,
15 pub(crate) _phantom: PhantomData<fn(T)>,
16}
17
18impl<G, T> VecGenerator<G, T> {
19 pub fn min_size(mut self, min_size: usize) -> Self {
21 self.min_size = min_size;
22 self
23 }
24
25 pub fn max_size(mut self, max_size: usize) -> Self {
27 self.max_size = Some(max_size);
28 self
29 }
30}
31
32impl<G, T: PartialEq> VecGenerator<G, T> {
33 pub fn unique(mut self, unique: bool) -> Self {
35 self.unique_by = if unique {
36 Some(<T as PartialEq>::eq)
37 } else {
38 None
39 };
40 self
41 }
42}
43
44impl<T, G> Generator<Vec<T>> for VecGenerator<G, T>
45where
46 G: Generator<T>,
47{
48 fn do_draw(&self, tc: &TestCase) -> Vec<T> {
49 if let Some(max) = self.max_size {
50 assert!(self.min_size <= max, "Cannot have max_size < min_size");
51 }
52 if let Some(basic) = self.as_basic() {
53 basic.do_draw(tc)
54 } else {
55 tc.start_span(labels::LIST);
56 let mut collection = Collection::new(tc, self.min_size, self.max_size);
57 let mut result = Vec::new();
58 while collection.more() {
59 let element = self.elements.do_draw(tc);
60 if let Some(eq_fn) = &self.unique_by {
61 if result.iter().any(|existing| eq_fn(existing, &element)) {
62 collection.reject(Some("duplicate element"));
63 continue;
64 }
65 }
66 result.push(element);
67 }
68 tc.stop_span(false);
69 result
70 }
71 }
72
73 fn as_basic(&self) -> Option<BasicGenerator<'_, Vec<T>>> {
74 if let Some(max) = self.max_size {
75 assert!(self.min_size <= max, "Cannot have max_size < min_size");
76 }
77 if self.unique_by.is_some() {
78 return None;
79 }
80 let basic = self.elements.as_basic()?;
81
82 let mut schema = cbor_map! {
83 "type" => "list",
84 "unique" => false,
85 "elements" => basic.schema().clone(),
86 "min_size" => self.min_size as u64
87 };
88
89 if let Some(max) = self.max_size {
90 map_insert(&mut schema, "max_size", max as u64);
91 }
92
93 Some(BasicGenerator::new(schema, move |raw| {
94 let Value::Array(arr) = raw else {
95 panic!("Expected array, got {:?}", raw) };
97 arr.into_iter().map(|v| basic.parse_raw(v)).collect()
98 }))
99 }
100}
101
102pub fn vecs<T, G: Generator<T>>(elements: G) -> VecGenerator<G, T> {
120 VecGenerator {
121 elements,
122 min_size: 0,
123 max_size: None,
124 unique_by: None,
125 _phantom: PhantomData,
126 }
127}
128
129pub struct HashSetGenerator<G, T> {
131 elements: G,
132 min_size: usize,
133 max_size: Option<usize>,
134 _phantom: PhantomData<fn(T)>,
135}
136
137impl<G, T> HashSetGenerator<G, T> {
138 pub fn min_size(mut self, min_size: usize) -> Self {
140 self.min_size = min_size;
141 self
142 }
143
144 pub fn max_size(mut self, max_size: usize) -> Self {
146 self.max_size = Some(max_size);
147 self
148 }
149}
150
151impl<T, G> Generator<HashSet<T>> for HashSetGenerator<G, T>
152where
153 G: Generator<T>,
154 T: Eq + Hash,
155{
156 fn do_draw(&self, tc: &TestCase) -> HashSet<T> {
157 if let Some(max) = self.max_size {
158 assert!(self.min_size <= max, "Cannot have max_size < min_size");
159 }
160 if let Some(basic) = self.as_basic() {
161 basic.do_draw(tc)
162 } else {
163 tc.start_span(labels::SET);
165 let mut collection = Collection::new(tc, self.min_size, self.max_size);
166 let mut set = HashSet::new();
167 while collection.more() {
168 let element = self.elements.do_draw(tc);
169 if !set.insert(element) {
170 collection.reject(Some("duplicate element"));
171 }
173 }
174 assert!(set.len() >= self.min_size);
176 tc.stop_span(false);
177 set
178 }
180 }
181
182 fn as_basic(&self) -> Option<BasicGenerator<'_, HashSet<T>>> {
183 if let Some(max) = self.max_size {
184 assert!(self.min_size <= max, "Cannot have max_size < min_size");
185 }
186 let basic = self.elements.as_basic()?;
187
188 let mut schema = cbor_map! {
189 "type" => "list",
190 "unique" => true,
191 "elements" => basic.schema().clone(),
192 "min_size" => self.min_size as u64
193 };
194
195 if let Some(max) = self.max_size {
196 map_insert(&mut schema, "max_size", max as u64);
197 }
198
199 Some(BasicGenerator::new(schema, move |raw| {
200 let Value::Array(arr) = raw else {
201 panic!("Expected array, got {:?}", raw) };
203 arr.into_iter().map(|v| basic.parse_raw(v)).collect()
204 }))
205 }
206}
207
208pub fn hashsets<T, G: Generator<T>>(elements: G) -> HashSetGenerator<G, T> {
212 HashSetGenerator {
213 elements,
214 min_size: 0,
215 max_size: None,
216 _phantom: PhantomData,
217 }
218}
219
220pub struct HashMapGenerator<K, V, KT, VT> {
222 keys: K,
223 values: V,
224 min_size: usize,
225 max_size: Option<usize>,
226 _phantom: PhantomData<fn(KT, VT)>,
227}
228
229impl<K, V, KT, VT> HashMapGenerator<K, V, KT, VT> {
230 pub fn min_size(mut self, min_size: usize) -> Self {
232 self.min_size = min_size;
233 self
234 }
235
236 pub fn max_size(mut self, max_size: usize) -> Self {
238 self.max_size = Some(max_size);
239 self
240 }
241}
242
243impl<K, V, KT, VT> Generator<HashMap<KT, VT>> for HashMapGenerator<K, V, KT, VT>
244where
245 K: Generator<KT>,
246 V: Generator<VT>,
247 KT: Eq + std::hash::Hash,
248{
249 fn do_draw(&self, tc: &TestCase) -> HashMap<KT, VT> {
250 if let Some(max) = self.max_size {
251 assert!(self.min_size <= max, "Cannot have max_size < min_size");
252 }
253 if let Some(basic) = self.as_basic() {
254 basic.do_draw(tc)
255 } else {
256 tc.start_span(labels::MAP);
258 let mut collection = Collection::new(tc, self.min_size, self.max_size);
259 let mut map = HashMap::new();
260 while collection.more() {
261 let key = self.keys.do_draw(tc);
262 match map.entry(key) {
263 std::collections::hash_map::Entry::Occupied(_) => {
264 collection.reject(Some("duplicate key"));
265 }
266 std::collections::hash_map::Entry::Vacant(entry) => {
267 let value = self.values.do_draw(tc);
268 entry.insert(value);
269 }
271 }
272 }
273 assert!(map.len() >= self.min_size);
275 tc.stop_span(false);
276 map
277 }
279 }
280
281 fn as_basic(&self) -> Option<BasicGenerator<'_, HashMap<KT, VT>>> {
282 if let Some(max) = self.max_size {
283 assert!(self.min_size <= max, "Cannot have max_size < min_size");
284 }
285 let keys_basic = self.keys.as_basic()?;
286 let values_basic = self.values.as_basic()?;
287
288 let mut schema = cbor_map! {
289 "type" => "dict",
290 "keys" => keys_basic.schema().clone(),
291 "values" => values_basic.schema().clone(),
292 "min_size" => self.min_size as u64
293 };
294
295 if let Some(max) = self.max_size {
296 map_insert(&mut schema, "max_size", max as u64);
297 }
298
299 Some(BasicGenerator::new(schema, move |raw| {
300 let values = match raw {
302 Value::Array(arr) => arr,
303 _ => panic!("Expected array, got {:?}", raw), };
305
306 let mut map = HashMap::new();
307 for value_raw in values {
308 let value = match value_raw {
309 Value::Array(arr) => arr,
310 _ => panic!("Expected array, got {:?}", value_raw), };
312 let mut iter = value.into_iter();
313 let raw_k = iter.next().unwrap();
314 let raw_v = iter.next().unwrap();
315
316 let key = keys_basic.parse_raw(raw_k);
317 let value = values_basic.parse_raw(raw_v);
318
319 map.insert(key, value);
320 }
321 map
322 }))
323 }
324}
325
326pub fn hashmaps<KT, VT, K: Generator<KT>, V: Generator<VT>>(
339 keys: K,
340 values: V,
341) -> HashMapGenerator<K, V, KT, VT> {
342 HashMapGenerator {
343 keys,
344 values,
345 min_size: 0,
346 max_size: None,
347 _phantom: PhantomData,
348 }
349}
350
351pub(crate) struct MappedToValue<T, G> {
352 inner: G,
353 _phantom: PhantomData<fn() -> T>,
354}
355
356impl<T: serde::Serialize, G: Generator<T>> Generator<Value> for MappedToValue<T, G> {
357 fn do_draw(&self, tc: &TestCase) -> Value {
359 crate::cbor_utils::cbor_serialize(&self.inner.do_draw(tc))
360 }
362
363 fn as_basic(&self) -> Option<BasicGenerator<'_, Value>> {
365 let inner_basic = self.inner.as_basic()?;
366 let schema = inner_basic.schema().clone();
367 Some(BasicGenerator::new(schema, move |raw| {
368 let t_val = inner_basic.parse_raw(raw);
369 crate::cbor_utils::cbor_serialize(&t_val)
370 }))
372 }
373}
374
375pub struct FixedDictBuilder<'a> {
380 fields: Vec<(String, BoxedGenerator<'a, Value>)>,
381}
382
383impl<'a> FixedDictBuilder<'a> {
384 pub fn field<T, G>(mut self, name: &str, generator: G) -> Self
387 where
388 G: Generator<T> + Send + Sync + 'a,
389 T: serde::Serialize + 'a,
390 {
392 let boxed = BoxedGenerator {
394 inner: Arc::new(MappedToValue {
395 inner: generator,
396 _phantom: PhantomData,
397 }),
399 };
400 self.fields.push((name.to_string(), boxed)); self }
403
404 pub fn build(self) -> FixedDictGenerator<'a> {
407 FixedDictGenerator {
408 fields: self.fields,
409 }
411 }
412}
413
414pub struct FixedDictGenerator<'a> {
416 fields: Vec<(String, BoxedGenerator<'a, Value>)>,
417}
418
419impl Generator<Value> for FixedDictGenerator<'_> {
420 fn do_draw(&self, tc: &TestCase) -> Value {
422 if let Some(basic) = self.as_basic() {
423 basic.do_draw(tc)
424 } else {
425 tc.start_span(labels::FIXED_DICT);
426 let entries: Vec<(Value, Value)> = self
427 .fields
428 .iter()
429 .map(|(name, g)| (Value::Text(name.clone()), g.do_draw(tc)))
430 .collect();
431 tc.stop_span(false);
432 Value::Map(entries)
433 }
435 }
436
437 fn as_basic(&self) -> Option<BasicGenerator<'_, Value>> {
439 let basics: Vec<BasicGenerator<'_, Value>> = self
440 .fields
441 .iter()
442 .map(|(_, g)| g.as_basic())
443 .collect::<Option<Vec<_>>>()?;
444
445 let schemas: Vec<Value> = basics.iter().map(|b| b.schema().clone()).collect();
446
447 let schema = cbor_map! {
448 "type" => "tuple",
449 "elements" => Value::Array(schemas)
450 };
452
453 let field_names: Vec<String> = self.fields.iter().map(|(name, _)| name.clone()).collect(); Some(BasicGenerator::new(schema, move |raw| {
457 let arr = match raw {
458 Value::Array(arr) => arr,
459 _ => panic!("Expected array from tuple schema, got {:?}", raw),
460 };
462
463 let entries: Vec<(Value, Value)> = field_names
465 .iter()
466 .zip(basics.iter())
467 .zip(arr)
468 .map(|((name, basic), val)| (Value::Text(name.clone()), basic.parse_raw(val)))
469 .collect();
470 Value::Map(entries)
471 }))
473 }
474}
475
476pub fn fixed_dicts<'a>() -> FixedDictBuilder<'a> {
492 FixedDictBuilder { fields: Vec::new() }
493 }
495
496pub struct ArrayGenerator<G, T, const N: usize> {
498 element: G,
499 _phantom: PhantomData<fn() -> T>,
500}
501
502impl<G, T, const N: usize> ArrayGenerator<G, T, N> {
503 #[doc(hidden)]
504 pub fn new(element: G) -> Self {
505 ArrayGenerator {
506 element,
507 _phantom: PhantomData,
508 }
509 }
510}
511
512pub fn arrays<G: Generator<T> + Send + Sync, T, const N: usize>(
514 element: G,
515) -> ArrayGenerator<G, T, N> {
516 ArrayGenerator::new(element)
517}
518
519impl<G: Generator<T> + Send + Sync, T, const N: usize> Generator<[T; N]>
520 for ArrayGenerator<G, T, N>
521{
522 fn do_draw(&self, tc: &TestCase) -> [T; N] {
523 if let Some(basic) = self.as_basic() {
524 basic.do_draw(tc)
525 } else {
526 tc.start_span(labels::TUPLE);
527 let result = std::array::from_fn(|_| self.element.do_draw(tc));
528 tc.stop_span(false);
529 result
530 }
531 }
532
533 fn as_basic(&self) -> Option<BasicGenerator<'_, [T; N]>> {
534 let basic = self.element.as_basic()?;
535
536 let elements = Value::Array((0..N).map(|_| basic.schema().clone()).collect());
537 let schema = cbor_map! {
538 "type" => "tuple",
539 "elements" => elements
540 };
541
542 Some(BasicGenerator::new(schema, move |raw| {
543 let arr = match raw {
544 Value::Array(arr) => arr,
545 _ => panic!("Expected array from tuple schema, got {:?}", raw), };
547 assert_eq!(arr.len(), N);
548 let mut iter = arr.into_iter();
549 std::array::from_fn(|_| basic.parse_raw(iter.next().unwrap()))
550 }))
551 }
552}