1use core::{marker::PhantomData, mem::MaybeUninit};
7use proptest::{
8 strategy::{NewTree, Strategy, ValueTree},
9 test_runner::TestRunner,
10};
11
12#[must_use = "strategies do nothing unless used"]
13#[derive(Clone, Copy, Debug)]
14pub struct UniformArrayStrategy<S, T> {
15 strategy: S,
16 _marker: PhantomData<T>,
17}
18
19impl<S, T> UniformArrayStrategy<S, T> {
20 pub const fn new(strategy: S) -> Self {
21 Self {
22 strategy,
23 _marker: PhantomData,
24 }
25 }
26}
27
28pub struct ArrayValueTree<T> {
29 tree: T,
30 shrinker: usize,
31 last_shrinker: Option<usize>,
32}
33
34impl<T, S, const LANES: usize> Strategy for UniformArrayStrategy<S, [T; LANES]>
35where
36 T: core::fmt::Debug,
37 S: Strategy<Value = T>,
38{
39 type Tree = ArrayValueTree<[S::Tree; LANES]>;
40 type Value = [T; LANES];
41
42 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
43 let tree: [S::Tree; LANES] = unsafe {
44 #[allow(clippy::uninit_assumed_init)]
45 let mut tree: [MaybeUninit<S::Tree>; LANES] = MaybeUninit::uninit().assume_init();
46 for t in tree.iter_mut() {
47 *t = MaybeUninit::new(self.strategy.new_tree(runner)?)
48 }
49 core::mem::transmute_copy(&tree)
50 };
51 Ok(ArrayValueTree {
52 tree,
53 shrinker: 0,
54 last_shrinker: None,
55 })
56 }
57}
58
59impl<T: ValueTree, const LANES: usize> ValueTree for ArrayValueTree<[T; LANES]> {
60 type Value = [T::Value; LANES];
61
62 fn current(&self) -> Self::Value {
63 unsafe {
64 #[allow(clippy::uninit_assumed_init)]
65 let mut value: [MaybeUninit<T::Value>; LANES] = MaybeUninit::uninit().assume_init();
66 for (tree_elem, value_elem) in self.tree.iter().zip(value.iter_mut()) {
67 *value_elem = MaybeUninit::new(tree_elem.current());
68 }
69 core::mem::transmute_copy(&value)
70 }
71 }
72
73 fn simplify(&mut self) -> bool {
74 while self.shrinker < LANES {
75 if self.tree[self.shrinker].simplify() {
76 self.last_shrinker = Some(self.shrinker);
77 return true;
78 } else {
79 self.shrinker += 1;
80 }
81 }
82
83 false
84 }
85
86 fn complicate(&mut self) -> bool {
87 if let Some(shrinker) = self.last_shrinker {
88 self.shrinker = shrinker;
89 if self.tree[shrinker].complicate() {
90 true
91 } else {
92 self.last_shrinker = None;
93 false
94 }
95 } else {
96 false
97 }
98 }
99}