test_helpers/
array.rs

1//! Generic-length array strategy.
2
3// Adapted from proptest's array code
4// Copyright 2017 Jason Lingle
5
6use 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}