1fb6c1f39Sopenharmony_ciuse std::iter::repeat;
2fb6c1f39Sopenharmony_ci
3fb6c1f39Sopenharmony_ci/// Create a sequence of tests that should be run by memchr implementations.
4fb6c1f39Sopenharmony_cipub fn memchr_tests() -> Vec<MemchrTest> {
5fb6c1f39Sopenharmony_ci    let mut tests = Vec::new();
6fb6c1f39Sopenharmony_ci    for statict in MEMCHR_TESTS {
7fb6c1f39Sopenharmony_ci        assert!(!statict.corpus.contains("%"), "% is not allowed in corpora");
8fb6c1f39Sopenharmony_ci        assert!(!statict.corpus.contains("#"), "# is not allowed in corpora");
9fb6c1f39Sopenharmony_ci        assert!(!statict.needles.contains(&b'%'), "% is an invalid needle");
10fb6c1f39Sopenharmony_ci        assert!(!statict.needles.contains(&b'#'), "# is an invalid needle");
11fb6c1f39Sopenharmony_ci
12fb6c1f39Sopenharmony_ci        let t = MemchrTest {
13fb6c1f39Sopenharmony_ci            corpus: statict.corpus.to_string(),
14fb6c1f39Sopenharmony_ci            needles: statict.needles.to_vec(),
15fb6c1f39Sopenharmony_ci            positions: statict.positions.to_vec(),
16fb6c1f39Sopenharmony_ci        };
17fb6c1f39Sopenharmony_ci        tests.push(t.clone());
18fb6c1f39Sopenharmony_ci        tests.extend(t.expand());
19fb6c1f39Sopenharmony_ci    }
20fb6c1f39Sopenharmony_ci    tests
21fb6c1f39Sopenharmony_ci}
22fb6c1f39Sopenharmony_ci
23fb6c1f39Sopenharmony_ci/// A set of tests for memchr-like functions.
24fb6c1f39Sopenharmony_ci///
25fb6c1f39Sopenharmony_ci/// These tests mostly try to cover the short string cases. We cover the longer
26fb6c1f39Sopenharmony_ci/// string cases via the benchmarks (which are tests themselves), via
27fb6c1f39Sopenharmony_ci/// quickcheck tests and via automatic expansion of each test case (by
28fb6c1f39Sopenharmony_ci/// increasing the corpus size). Finally, we cover different alignment cases
29fb6c1f39Sopenharmony_ci/// in the tests by varying the starting point of the slice.
30fb6c1f39Sopenharmony_ciconst MEMCHR_TESTS: &[MemchrTestStatic] = &[
31fb6c1f39Sopenharmony_ci    // one needle (applied to memchr + memchr2 + memchr3)
32fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "a", needles: &[b'a'], positions: &[0] },
33fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "aa", needles: &[b'a'], positions: &[0, 1] },
34fb6c1f39Sopenharmony_ci    MemchrTestStatic {
35fb6c1f39Sopenharmony_ci        corpus: "aaa",
36fb6c1f39Sopenharmony_ci        needles: &[b'a'],
37fb6c1f39Sopenharmony_ci        positions: &[0, 1, 2],
38fb6c1f39Sopenharmony_ci    },
39fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "", needles: &[b'a'], positions: &[] },
40fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "z", needles: &[b'a'], positions: &[] },
41fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "zz", needles: &[b'a'], positions: &[] },
42fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "zza", needles: &[b'a'], positions: &[2] },
43fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "zaza", needles: &[b'a'], positions: &[1, 3] },
44fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "zzza", needles: &[b'a'], positions: &[3] },
45fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "\x00a", needles: &[b'a'], positions: &[1] },
46fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "\x00", needles: &[b'\x00'], positions: &[0] },
47fb6c1f39Sopenharmony_ci    MemchrTestStatic {
48fb6c1f39Sopenharmony_ci        corpus: "\x00\x00",
49fb6c1f39Sopenharmony_ci        needles: &[b'\x00'],
50fb6c1f39Sopenharmony_ci        positions: &[0, 1],
51fb6c1f39Sopenharmony_ci    },
52fb6c1f39Sopenharmony_ci    MemchrTestStatic {
53fb6c1f39Sopenharmony_ci        corpus: "\x00a\x00",
54fb6c1f39Sopenharmony_ci        needles: &[b'\x00'],
55fb6c1f39Sopenharmony_ci        positions: &[0, 2],
56fb6c1f39Sopenharmony_ci    },
57fb6c1f39Sopenharmony_ci    MemchrTestStatic {
58fb6c1f39Sopenharmony_ci        corpus: "zzzzzzzzzzzzzzzza",
59fb6c1f39Sopenharmony_ci        needles: &[b'a'],
60fb6c1f39Sopenharmony_ci        positions: &[16],
61fb6c1f39Sopenharmony_ci    },
62fb6c1f39Sopenharmony_ci    MemchrTestStatic {
63fb6c1f39Sopenharmony_ci        corpus: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza",
64fb6c1f39Sopenharmony_ci        needles: &[b'a'],
65fb6c1f39Sopenharmony_ci        positions: &[32],
66fb6c1f39Sopenharmony_ci    },
67fb6c1f39Sopenharmony_ci    // two needles (applied to memchr2 + memchr3)
68fb6c1f39Sopenharmony_ci    MemchrTestStatic {
69fb6c1f39Sopenharmony_ci        corpus: "az",
70fb6c1f39Sopenharmony_ci        needles: &[b'a', b'z'],
71fb6c1f39Sopenharmony_ci        positions: &[0, 1],
72fb6c1f39Sopenharmony_ci    },
73fb6c1f39Sopenharmony_ci    MemchrTestStatic {
74fb6c1f39Sopenharmony_ci        corpus: "az",
75fb6c1f39Sopenharmony_ci        needles: &[b'a', b'z'],
76fb6c1f39Sopenharmony_ci        positions: &[0, 1],
77fb6c1f39Sopenharmony_ci    },
78fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "az", needles: &[b'x', b'y'], positions: &[] },
79fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "az", needles: &[b'a', b'y'], positions: &[0] },
80fb6c1f39Sopenharmony_ci    MemchrTestStatic { corpus: "az", needles: &[b'x', b'z'], positions: &[1] },
81fb6c1f39Sopenharmony_ci    MemchrTestStatic {
82fb6c1f39Sopenharmony_ci        corpus: "yyyyaz",
83fb6c1f39Sopenharmony_ci        needles: &[b'a', b'z'],
84fb6c1f39Sopenharmony_ci        positions: &[4, 5],
85fb6c1f39Sopenharmony_ci    },
86fb6c1f39Sopenharmony_ci    MemchrTestStatic {
87fb6c1f39Sopenharmony_ci        corpus: "yyyyaz",
88fb6c1f39Sopenharmony_ci        needles: &[b'z', b'a'],
89fb6c1f39Sopenharmony_ci        positions: &[4, 5],
90fb6c1f39Sopenharmony_ci    },
91fb6c1f39Sopenharmony_ci    // three needles (applied to memchr3)
92fb6c1f39Sopenharmony_ci    MemchrTestStatic {
93fb6c1f39Sopenharmony_ci        corpus: "xyz",
94fb6c1f39Sopenharmony_ci        needles: &[b'x', b'y', b'z'],
95fb6c1f39Sopenharmony_ci        positions: &[0, 1, 2],
96fb6c1f39Sopenharmony_ci    },
97fb6c1f39Sopenharmony_ci    MemchrTestStatic {
98fb6c1f39Sopenharmony_ci        corpus: "zxy",
99fb6c1f39Sopenharmony_ci        needles: &[b'x', b'y', b'z'],
100fb6c1f39Sopenharmony_ci        positions: &[0, 1, 2],
101fb6c1f39Sopenharmony_ci    },
102fb6c1f39Sopenharmony_ci    MemchrTestStatic {
103fb6c1f39Sopenharmony_ci        corpus: "zxy",
104fb6c1f39Sopenharmony_ci        needles: &[b'x', b'a', b'z'],
105fb6c1f39Sopenharmony_ci        positions: &[0, 1],
106fb6c1f39Sopenharmony_ci    },
107fb6c1f39Sopenharmony_ci    MemchrTestStatic {
108fb6c1f39Sopenharmony_ci        corpus: "zxy",
109fb6c1f39Sopenharmony_ci        needles: &[b't', b'a', b'z'],
110fb6c1f39Sopenharmony_ci        positions: &[0],
111fb6c1f39Sopenharmony_ci    },
112fb6c1f39Sopenharmony_ci    MemchrTestStatic {
113fb6c1f39Sopenharmony_ci        corpus: "yxz",
114fb6c1f39Sopenharmony_ci        needles: &[b't', b'a', b'z'],
115fb6c1f39Sopenharmony_ci        positions: &[2],
116fb6c1f39Sopenharmony_ci    },
117fb6c1f39Sopenharmony_ci];
118fb6c1f39Sopenharmony_ci
119fb6c1f39Sopenharmony_ci/// A description of a test on a memchr like function.
120fb6c1f39Sopenharmony_ci#[derive(Clone, Debug)]
121fb6c1f39Sopenharmony_cipub struct MemchrTest {
122fb6c1f39Sopenharmony_ci    /// The thing to search. We use `&str` instead of `&[u8]` because they
123fb6c1f39Sopenharmony_ci    /// are nicer to write in tests, and we don't miss much since memchr
124fb6c1f39Sopenharmony_ci    /// doesn't care about UTF-8.
125fb6c1f39Sopenharmony_ci    ///
126fb6c1f39Sopenharmony_ci    /// Corpora cannot contain either '%' or '#'. We use these bytes when
127fb6c1f39Sopenharmony_ci    /// expanding test cases into many test cases, and we assume they are not
128fb6c1f39Sopenharmony_ci    /// used. If they are used, `memchr_tests` will panic.
129fb6c1f39Sopenharmony_ci    corpus: String,
130fb6c1f39Sopenharmony_ci    /// The needles to search for. This is intended to be an "alternation" of
131fb6c1f39Sopenharmony_ci    /// needles. The number of needles may cause this test to be skipped for
132fb6c1f39Sopenharmony_ci    /// some memchr variants. For example, a test with 2 needles cannot be used
133fb6c1f39Sopenharmony_ci    /// to test `memchr`, but can be used to test `memchr2` and `memchr3`.
134fb6c1f39Sopenharmony_ci    /// However, a test with only 1 needle can be used to test all of `memchr`,
135fb6c1f39Sopenharmony_ci    /// `memchr2` and `memchr3`. We achieve this by filling in the needles with
136fb6c1f39Sopenharmony_ci    /// bytes that we never used in the corpus (such as '#').
137fb6c1f39Sopenharmony_ci    needles: Vec<u8>,
138fb6c1f39Sopenharmony_ci    /// The positions expected to match for all of the needles.
139fb6c1f39Sopenharmony_ci    positions: Vec<usize>,
140fb6c1f39Sopenharmony_ci}
141fb6c1f39Sopenharmony_ci
142fb6c1f39Sopenharmony_ci/// Like MemchrTest, but easier to define as a constant.
143fb6c1f39Sopenharmony_ci#[derive(Clone, Debug)]
144fb6c1f39Sopenharmony_cipub struct MemchrTestStatic {
145fb6c1f39Sopenharmony_ci    corpus: &'static str,
146fb6c1f39Sopenharmony_ci    needles: &'static [u8],
147fb6c1f39Sopenharmony_ci    positions: &'static [usize],
148fb6c1f39Sopenharmony_ci}
149fb6c1f39Sopenharmony_ci
150fb6c1f39Sopenharmony_ciimpl MemchrTest {
151fb6c1f39Sopenharmony_ci    pub fn one<F: Fn(u8, &[u8]) -> Option<usize>>(&self, reverse: bool, f: F) {
152fb6c1f39Sopenharmony_ci        let needles = match self.needles(1) {
153fb6c1f39Sopenharmony_ci            None => return,
154fb6c1f39Sopenharmony_ci            Some(needles) => needles,
155fb6c1f39Sopenharmony_ci        };
156fb6c1f39Sopenharmony_ci        // We test different alignments here. Since some implementations use
157fb6c1f39Sopenharmony_ci        // AVX2, which can read 32 bytes at a time, we test at least that.
158fb6c1f39Sopenharmony_ci        // Moreover, with loop unrolling, we sometimes process 64 (sse2) or 128
159fb6c1f39Sopenharmony_ci        // (avx) bytes at a time, so we include that in our offsets as well.
160fb6c1f39Sopenharmony_ci        //
161fb6c1f39Sopenharmony_ci        // You might think this would cause most needles to not be found, but
162fb6c1f39Sopenharmony_ci        // we actually expand our tests to include corpus sizes all the way up
163fb6c1f39Sopenharmony_ci        // to >500 bytes, so we should exercise most branches.
164fb6c1f39Sopenharmony_ci        for align in 0..130 {
165fb6c1f39Sopenharmony_ci            let corpus = self.corpus(align);
166fb6c1f39Sopenharmony_ci            assert_eq!(
167fb6c1f39Sopenharmony_ci                self.positions(align, reverse).get(0).cloned(),
168fb6c1f39Sopenharmony_ci                f(needles[0], corpus.as_bytes()),
169fb6c1f39Sopenharmony_ci                "search for {:?} failed in: {:?} (len: {}, alignment: {})",
170fb6c1f39Sopenharmony_ci                needles[0] as char,
171fb6c1f39Sopenharmony_ci                corpus,
172fb6c1f39Sopenharmony_ci                corpus.len(),
173fb6c1f39Sopenharmony_ci                align
174fb6c1f39Sopenharmony_ci            );
175fb6c1f39Sopenharmony_ci        }
176fb6c1f39Sopenharmony_ci    }
177fb6c1f39Sopenharmony_ci
178fb6c1f39Sopenharmony_ci    pub fn two<F: Fn(u8, u8, &[u8]) -> Option<usize>>(
179fb6c1f39Sopenharmony_ci        &self,
180fb6c1f39Sopenharmony_ci        reverse: bool,
181fb6c1f39Sopenharmony_ci        f: F,
182fb6c1f39Sopenharmony_ci    ) {
183fb6c1f39Sopenharmony_ci        let needles = match self.needles(2) {
184fb6c1f39Sopenharmony_ci            None => return,
185fb6c1f39Sopenharmony_ci            Some(needles) => needles,
186fb6c1f39Sopenharmony_ci        };
187fb6c1f39Sopenharmony_ci        for align in 0..130 {
188fb6c1f39Sopenharmony_ci            let corpus = self.corpus(align);
189fb6c1f39Sopenharmony_ci            assert_eq!(
190fb6c1f39Sopenharmony_ci                self.positions(align, reverse).get(0).cloned(),
191fb6c1f39Sopenharmony_ci                f(needles[0], needles[1], corpus.as_bytes()),
192fb6c1f39Sopenharmony_ci                "search for {:?}|{:?} failed in: {:?} \
193fb6c1f39Sopenharmony_ci                 (len: {}, alignment: {})",
194fb6c1f39Sopenharmony_ci                needles[0] as char,
195fb6c1f39Sopenharmony_ci                needles[1] as char,
196fb6c1f39Sopenharmony_ci                corpus,
197fb6c1f39Sopenharmony_ci                corpus.len(),
198fb6c1f39Sopenharmony_ci                align
199fb6c1f39Sopenharmony_ci            );
200fb6c1f39Sopenharmony_ci        }
201fb6c1f39Sopenharmony_ci    }
202fb6c1f39Sopenharmony_ci
203fb6c1f39Sopenharmony_ci    pub fn three<F: Fn(u8, u8, u8, &[u8]) -> Option<usize>>(
204fb6c1f39Sopenharmony_ci        &self,
205fb6c1f39Sopenharmony_ci        reverse: bool,
206fb6c1f39Sopenharmony_ci        f: F,
207fb6c1f39Sopenharmony_ci    ) {
208fb6c1f39Sopenharmony_ci        let needles = match self.needles(3) {
209fb6c1f39Sopenharmony_ci            None => return,
210fb6c1f39Sopenharmony_ci            Some(needles) => needles,
211fb6c1f39Sopenharmony_ci        };
212fb6c1f39Sopenharmony_ci        for align in 0..130 {
213fb6c1f39Sopenharmony_ci            let corpus = self.corpus(align);
214fb6c1f39Sopenharmony_ci            assert_eq!(
215fb6c1f39Sopenharmony_ci                self.positions(align, reverse).get(0).cloned(),
216fb6c1f39Sopenharmony_ci                f(needles[0], needles[1], needles[2], corpus.as_bytes()),
217fb6c1f39Sopenharmony_ci                "search for {:?}|{:?}|{:?} failed in: {:?} \
218fb6c1f39Sopenharmony_ci                 (len: {}, alignment: {})",
219fb6c1f39Sopenharmony_ci                needles[0] as char,
220fb6c1f39Sopenharmony_ci                needles[1] as char,
221fb6c1f39Sopenharmony_ci                needles[2] as char,
222fb6c1f39Sopenharmony_ci                corpus,
223fb6c1f39Sopenharmony_ci                corpus.len(),
224fb6c1f39Sopenharmony_ci                align
225fb6c1f39Sopenharmony_ci            );
226fb6c1f39Sopenharmony_ci        }
227fb6c1f39Sopenharmony_ci    }
228fb6c1f39Sopenharmony_ci
229fb6c1f39Sopenharmony_ci    pub fn iter_one<'a, I, F>(&'a self, reverse: bool, f: F)
230fb6c1f39Sopenharmony_ci    where
231fb6c1f39Sopenharmony_ci        F: FnOnce(u8, &'a [u8]) -> I,
232fb6c1f39Sopenharmony_ci        I: Iterator<Item = usize>,
233fb6c1f39Sopenharmony_ci    {
234fb6c1f39Sopenharmony_ci        if let Some(ns) = self.needles(1) {
235fb6c1f39Sopenharmony_ci            self.iter(reverse, f(ns[0], self.corpus.as_bytes()));
236fb6c1f39Sopenharmony_ci        }
237fb6c1f39Sopenharmony_ci    }
238fb6c1f39Sopenharmony_ci
239fb6c1f39Sopenharmony_ci    pub fn iter_two<'a, I, F>(&'a self, reverse: bool, f: F)
240fb6c1f39Sopenharmony_ci    where
241fb6c1f39Sopenharmony_ci        F: FnOnce(u8, u8, &'a [u8]) -> I,
242fb6c1f39Sopenharmony_ci        I: Iterator<Item = usize>,
243fb6c1f39Sopenharmony_ci    {
244fb6c1f39Sopenharmony_ci        if let Some(ns) = self.needles(2) {
245fb6c1f39Sopenharmony_ci            self.iter(reverse, f(ns[0], ns[1], self.corpus.as_bytes()));
246fb6c1f39Sopenharmony_ci        }
247fb6c1f39Sopenharmony_ci    }
248fb6c1f39Sopenharmony_ci
249fb6c1f39Sopenharmony_ci    pub fn iter_three<'a, I, F>(&'a self, reverse: bool, f: F)
250fb6c1f39Sopenharmony_ci    where
251fb6c1f39Sopenharmony_ci        F: FnOnce(u8, u8, u8, &'a [u8]) -> I,
252fb6c1f39Sopenharmony_ci        I: Iterator<Item = usize>,
253fb6c1f39Sopenharmony_ci    {
254fb6c1f39Sopenharmony_ci        if let Some(ns) = self.needles(3) {
255fb6c1f39Sopenharmony_ci            self.iter(reverse, f(ns[0], ns[1], ns[2], self.corpus.as_bytes()));
256fb6c1f39Sopenharmony_ci        }
257fb6c1f39Sopenharmony_ci    }
258fb6c1f39Sopenharmony_ci
259fb6c1f39Sopenharmony_ci    /// Test that the positions yielded by the given iterator match the
260fb6c1f39Sopenharmony_ci    /// positions in this test. If reverse is true, then reverse the positions
261fb6c1f39Sopenharmony_ci    /// before comparing them.
262fb6c1f39Sopenharmony_ci    fn iter<I: Iterator<Item = usize>>(&self, reverse: bool, it: I) {
263fb6c1f39Sopenharmony_ci        assert_eq!(
264fb6c1f39Sopenharmony_ci            self.positions(0, reverse),
265fb6c1f39Sopenharmony_ci            it.collect::<Vec<usize>>(),
266fb6c1f39Sopenharmony_ci            r"search for {:?} failed in: {:?}",
267fb6c1f39Sopenharmony_ci            self.needles.iter().map(|&b| b as char).collect::<Vec<char>>(),
268fb6c1f39Sopenharmony_ci            self.corpus
269fb6c1f39Sopenharmony_ci        );
270fb6c1f39Sopenharmony_ci    }
271fb6c1f39Sopenharmony_ci
272fb6c1f39Sopenharmony_ci    /// Expand this test into many variations of the same test.
273fb6c1f39Sopenharmony_ci    ///
274fb6c1f39Sopenharmony_ci    /// In particular, this will generate more tests with larger corpus sizes.
275fb6c1f39Sopenharmony_ci    /// The expected positions are updated to maintain the integrity of the
276fb6c1f39Sopenharmony_ci    /// test.
277fb6c1f39Sopenharmony_ci    ///
278fb6c1f39Sopenharmony_ci    /// This is important in testing a memchr implementation, because there are
279fb6c1f39Sopenharmony_ci    /// often different cases depending on the length of the corpus.
280fb6c1f39Sopenharmony_ci    ///
281fb6c1f39Sopenharmony_ci    /// Note that we extend the corpus by adding `%` bytes, which we
282fb6c1f39Sopenharmony_ci    /// don't otherwise use as a needle.
283fb6c1f39Sopenharmony_ci    fn expand(&self) -> Vec<MemchrTest> {
284fb6c1f39Sopenharmony_ci        let mut more = Vec::new();
285fb6c1f39Sopenharmony_ci
286fb6c1f39Sopenharmony_ci        // Add bytes to the start of the corpus.
287fb6c1f39Sopenharmony_ci        for i in 1..515 {
288fb6c1f39Sopenharmony_ci            let mut t = self.clone();
289fb6c1f39Sopenharmony_ci            let mut new_corpus: String = repeat('%').take(i).collect();
290fb6c1f39Sopenharmony_ci            new_corpus.push_str(&t.corpus);
291fb6c1f39Sopenharmony_ci            t.corpus = new_corpus;
292fb6c1f39Sopenharmony_ci            t.positions = t.positions.into_iter().map(|p| p + i).collect();
293fb6c1f39Sopenharmony_ci            more.push(t);
294fb6c1f39Sopenharmony_ci        }
295fb6c1f39Sopenharmony_ci        // Add bytes to the end of the corpus.
296fb6c1f39Sopenharmony_ci        for i in 1..515 {
297fb6c1f39Sopenharmony_ci            let mut t = self.clone();
298fb6c1f39Sopenharmony_ci            let padding: String = repeat('%').take(i).collect();
299fb6c1f39Sopenharmony_ci            t.corpus.push_str(&padding);
300fb6c1f39Sopenharmony_ci            more.push(t);
301fb6c1f39Sopenharmony_ci        }
302fb6c1f39Sopenharmony_ci
303fb6c1f39Sopenharmony_ci        more
304fb6c1f39Sopenharmony_ci    }
305fb6c1f39Sopenharmony_ci
306fb6c1f39Sopenharmony_ci    /// Return the corpus at the given alignment.
307fb6c1f39Sopenharmony_ci    ///
308fb6c1f39Sopenharmony_ci    /// If the alignment exceeds the length of the corpus, then this returns
309fb6c1f39Sopenharmony_ci    /// an empty slice.
310fb6c1f39Sopenharmony_ci    fn corpus(&self, align: usize) -> &str {
311fb6c1f39Sopenharmony_ci        self.corpus.get(align..).unwrap_or("")
312fb6c1f39Sopenharmony_ci    }
313fb6c1f39Sopenharmony_ci
314fb6c1f39Sopenharmony_ci    /// Return exactly `count` needles from this test. If this test has less
315fb6c1f39Sopenharmony_ci    /// than `count` needles, then add `#` until the number of needles
316fb6c1f39Sopenharmony_ci    /// matches `count`. If this test has more than `count` needles, then
317fb6c1f39Sopenharmony_ci    /// return `None` (because there is no way to use this test data for a
318fb6c1f39Sopenharmony_ci    /// search using fewer needles).
319fb6c1f39Sopenharmony_ci    fn needles(&self, count: usize) -> Option<Vec<u8>> {
320fb6c1f39Sopenharmony_ci        if self.needles.len() > count {
321fb6c1f39Sopenharmony_ci            return None;
322fb6c1f39Sopenharmony_ci        }
323fb6c1f39Sopenharmony_ci
324fb6c1f39Sopenharmony_ci        let mut needles = self.needles.to_vec();
325fb6c1f39Sopenharmony_ci        for _ in needles.len()..count {
326fb6c1f39Sopenharmony_ci            // we assume # is never used in tests.
327fb6c1f39Sopenharmony_ci            needles.push(b'#');
328fb6c1f39Sopenharmony_ci        }
329fb6c1f39Sopenharmony_ci        Some(needles)
330fb6c1f39Sopenharmony_ci    }
331fb6c1f39Sopenharmony_ci
332fb6c1f39Sopenharmony_ci    /// Return the positions in this test, reversed if `reverse` is true.
333fb6c1f39Sopenharmony_ci    ///
334fb6c1f39Sopenharmony_ci    /// If alignment is given, then all positions greater than or equal to that
335fb6c1f39Sopenharmony_ci    /// alignment are offset by the alignment. Positions less than the
336fb6c1f39Sopenharmony_ci    /// alignment are dropped.
337fb6c1f39Sopenharmony_ci    fn positions(&self, align: usize, reverse: bool) -> Vec<usize> {
338fb6c1f39Sopenharmony_ci        let positions = if reverse {
339fb6c1f39Sopenharmony_ci            let mut positions = self.positions.to_vec();
340fb6c1f39Sopenharmony_ci            positions.reverse();
341fb6c1f39Sopenharmony_ci            positions
342fb6c1f39Sopenharmony_ci        } else {
343fb6c1f39Sopenharmony_ci            self.positions.to_vec()
344fb6c1f39Sopenharmony_ci        };
345fb6c1f39Sopenharmony_ci        positions
346fb6c1f39Sopenharmony_ci            .into_iter()
347fb6c1f39Sopenharmony_ci            .filter(|&p| p >= align)
348fb6c1f39Sopenharmony_ci            .map(|p| p - align)
349fb6c1f39Sopenharmony_ci            .collect()
350fb6c1f39Sopenharmony_ci    }
351fb6c1f39Sopenharmony_ci}
352