sample_std/
lib.rs

1//! Core sampling strategies, along with useful implementations for samplers on
2//! types from [`std`] and the [`quickcheck`] crate.
3//!
4//! The core of this library is the [`Sample`] trait, which uses [`Random`] to
5//! generate arbitrary values from a sampled `Output` type with a custom
6//! "sampling strategy". It also defines a procedure for "shrinking" generated
7//! values, which can be used to generate simple counterexamples against
8//! expected properties.
9//!
10//! This library is generally intended for usage alongside the [`sample_test`][1]
11//! crate. See that crate for macros and examples for using samplers within unit
12//! tests.
13//!
14//! # Sampling Strategies
15//!
16//! The simplest [`Sample`] implementation is for [`Range`]. It is a sampler
17//! that generates values uniformly from the given range, and attempts to shrink
18//! down to the start of the range:
19//!
20//! ```
21//! use sample_std::{Sample, Random};
22//!
23//! let mut s = 10..100;
24//! let v = s.generate(&mut Random::new());
25//! assert!(s.contains(&v));
26//! let mut shrunk = s.shrink(v);
27//! assert_eq!(shrunk.next(), Some(s.start));
28//! if v > s.start {
29//!     assert!(shrunk.next().unwrap() < v)
30//! }
31//! ```
32//!
33//! Samplers are defined for tuples of samplers up to size 8, which can be
34//! used in concert with [`Sample::try_convert`] to combine samplers into a
35//! sampler for a larger type:
36//!
37//! ```
38//! use sample_std::{Chance, Sample, VecSampler, choice};
39//!
40//! struct Large {
41//!     values: Vec<usize>,
42//!     is_blue: bool,
43//!     name: String,
44//! }
45//!
46//! let sampler = (
47//!     VecSampler { length: 0..10, el: 5..20 },
48//!     Chance(0.5),
49//!     choice(["cora".to_string(), "james".to_string()])
50//! ).try_convert(
51//!     |(values, is_blue, name)| Large { values, is_blue, name },
52//!     |large| Some((large.values, large.is_blue, large.name))
53//! );
54//! ```
55//!
56//! For an example of sampling an `enum`, see [`sampler_choice`].
57//!
58//! # Prior Work
59//!
60//! This crate is heavily inspired by [`quickcheck`]. It builds upon it, in
61//! particular by defining samplers for [`Arbitrary`] (see [`arbitrary`]). Many
62//! methods and structs in here were derived from their [`quickcheck`]
63//! counterparts.
64//!
65//! It attempts to iterate and improve on the [`quickcheck`] core idea:
66//!
67//! - Allow definition of multiple sampling strategies for the same type.
68//! - No need to define newtypes for custom sampling strategies.
69//!
70//! There is still some cruft and weirdness from this early attempt to combine
71//! these worldviews:
72//!
73//! - The concept of `size` isn't really necessary in a world with sampling
74//!   strategies.
75//! - The [`Random`] struct could probably just become a type definition around
76//!   the underlying `rng`.
77//!
78//! The core idea for sampling "strategies" comes from [`proptest`][2], which
79//! uses macros instead of combinators for composition, and has more complex
80//! shrinking functionality.
81//!
82//! [1]: https://docs.rs/sample_test/latest/sample_test/
83//! [2]: https://docs.rs/proptest/latest/proptest/
84pub use quickcheck::{Arbitrary, Gen, TestResult, Testable};
85use std::{marker::PhantomData, ops::Range};
86
87pub use rand;
88use rand::{
89    distributions::uniform::SampleUniform, prelude::Distribution, seq::SliceRandom, Rng,
90    SeedableRng,
91};
92
93pub mod recursive;
94
95/// [`Random`] represents a PRNG.
96///
97/// It is a reimplementation of [`quickcheck::Gen`], which does not export the
98/// methods we need to properly generate random values.
99///
100/// It is unspecified whether this is a secure RNG or not. Therefore, callers
101/// should assume it is insecure.
102pub struct Random {
103    pub rng: rand::rngs::SmallRng,
104}
105
106impl Random {
107    pub fn arbitrary<T: Arbitrary>(&self) -> T {
108        let mut qcg = Gen::new(100);
109
110        Arbitrary::arbitrary(&mut qcg)
111    }
112
113    /// Returns a new [Random] instance.
114    pub fn new() -> Self {
115        Random {
116            rng: rand::rngs::SmallRng::from_entropy(),
117        }
118    }
119
120    pub fn from_seed(seed: u64) -> Self {
121        let seed: Vec<u8> = seed
122            .to_be_bytes()
123            .into_iter()
124            .chain(std::iter::repeat(0))
125            .take(32)
126            .collect();
127        Random {
128            rng: rand::rngs::SmallRng::from_seed(seed[0..32].try_into().unwrap()),
129        }
130    }
131
132    /// Choose among the possible alternatives in the slice given. If the slice
133    /// is empty, then `None` is returned. Otherwise, a non-`None` value is
134    /// guaranteed to be returned.
135    pub fn choose<'a, T>(&mut self, slice: &'a [T]) -> Option<&'a T> {
136        slice.choose(&mut self.rng)
137    }
138
139    pub fn gen<T>(&mut self) -> T
140    where
141        rand::distributions::Standard: rand::distributions::Distribution<T>,
142    {
143        self.rng.gen()
144    }
145
146    pub fn gen_range<T, R>(&mut self, range: R) -> T
147    where
148        T: rand::distributions::uniform::SampleUniform,
149        R: rand::distributions::uniform::SampleRange<T>,
150    {
151        self.rng.gen_range(range)
152    }
153}
154
155/// An [`Iterator`] of "smaller" values derived from a given value.
156pub type Shrunk<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
157
158/// User-defined strategies for generating and shrinking an `Output` type.
159pub trait Sample {
160    type Output;
161
162    /// Randomly generate the requested type.
163    fn generate(&mut self, g: &mut Random) -> Self::Output;
164
165    /// Shrink the given value into a "smaller" value. Defaults to an empty
166    /// iterator (which represents that the value cannot be shrunk).
167    fn shrink(&self, _: Self::Output) -> Shrunk<'_, Self::Output> {
168        Box::new(std::iter::empty())
169    }
170
171    /// Convert this sampler into a new sampler with `from` and `try_into`
172    /// functions:
173    ///
174    /// ```
175    /// use sample_std::{Sample, VecSampler};
176    ///
177    /// struct Wrapper {
178    ///     vec: Vec<usize>
179    /// }
180    ///
181    /// impl Wrapper {
182    ///     fn new(vec: Vec<usize>) -> Self {
183    ///         Self { vec }
184    ///     }
185    /// }
186    ///
187    /// let sampler = VecSampler { length: 10..20, el: 1..5 }.try_convert(
188    ///     Wrapper::new,
189    ///     |w| Some(w.vec)
190    /// );
191    /// ```
192    ///
193    /// [`Sample::generate`] will use `from` to convert the inner sampled value
194    /// to the desired type.
195    ///
196    /// [`Sample::shrink`] will use `try_into` to convert the desired type back
197    /// to the inner sampled type, if possible. The inner `shrink` method will
198    /// be called on that type, and all values will be converted back to the
199    /// target type again with `into`.
200    fn try_convert<T, I, F>(self, from: F, try_into: I) -> TryConvert<Self, F, I>
201    where
202        Self: Sized,
203        F: Fn(Self::Output) -> T,
204        I: Fn(T) -> Option<Self::Output>,
205    {
206        TryConvert {
207            inner: self,
208            from,
209            try_into,
210        }
211    }
212
213    /// "Zip" two samplers together. Functionally equivalent to `(self, other)`.
214    fn zip<OS>(self, other: OS) -> Zip<Self, OS>
215    where
216        Self: Sized,
217        OS: Sample,
218    {
219        Zip { t: (self, other) }
220    }
221
222    /// "Resampling" method for chaining samplers.
223    ///
224    /// For sampling, use this sampler as a  "supersampler" that creates a
225    /// "seed" value. The provided function then converts this seed into an
226    /// inner sampler that is used to generate a final value.
227    ///
228    /// This value is returned within a [Chained] wrapper that also captures the
229    /// seed. This allows us to use the "supersampler" in the shrinking process.
230    /// This then shrinks the seed, and then "resamples" (generates new samples)
231    /// with the shrunk inner sampler.
232    ///
233    /// Note that the resulting sampler will only perform a very shallow search
234    /// (`subsamples`) of the shrunk inner sampler space.
235    fn chain_resample<F, RS>(self, transform: F, subsamples: usize) -> ChainResample<Self, F>
236    where
237        Self: Sized,
238        F: Fn(Self::Output) -> RS,
239        RS: Sample,
240    {
241        ChainResample {
242            supersampler: self,
243            transform,
244            subsamples,
245        }
246    }
247}
248
249/// See [`Sample::try_convert`].
250#[derive(Clone)]
251pub struct TryConvert<P, F, I> {
252    pub inner: P,
253    from: F,
254    try_into: I,
255}
256
257impl<P, F, I, T> Sample for TryConvert<P, F, I>
258where
259    P: Sample,
260    F: Fn(P::Output) -> T,
261    I: Fn(T) -> Option<P::Output>,
262{
263    type Output = T;
264
265    fn generate(&mut self, g: &mut Random) -> Self::Output {
266        (self.from)(P::generate(&mut self.inner, g))
267    }
268
269    fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
270        Box::new(
271            (self.try_into)(v)
272                .into_iter()
273                .flat_map(|v| P::shrink(&self.inner, v))
274                .map(&self.from),
275        )
276    }
277}
278
279/// See [`Sample::zip`].
280#[derive(Clone)]
281pub struct Zip<A, B> {
282    t: (A, B),
283}
284
285impl<A, B> Sample for Zip<A, B>
286where
287    A: Sample,
288    B: Sample,
289    A::Output: Clone,
290    B::Output: Clone,
291{
292    type Output = (A::Output, B::Output);
293
294    fn generate(&mut self, g: &mut Random) -> Self::Output {
295        self.t.generate(g)
296    }
297
298    fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
299        self.t.shrink(v)
300    }
301}
302
303macro_rules! replace_expr {
304    ($_t:tt $sub:expr) => {
305        $sub
306    };
307}
308
309macro_rules! none_pad {
310    (($cur:ident) $($post: ident)*) => {
311        (Some($cur), $(replace_expr!($post  None)),*)
312    };
313    ($($pre:ident)+ ($cur:ident) $($post: ident)*) => {
314        ($(replace_expr!($pre  None)),*, Some($cur), $(replace_expr!($post  None)),*)
315    };
316}
317
318macro_rules! shrink_tuple {
319    ($v:ident () $($sample: ident)*) => {
320        let ($(casey::lower!($sample)),*) = $v.clone();
321        let r = std::iter::empty();
322        shrink_tuple!(r $v () ($($sample)*));
323    };
324    ($r:ident $v:ident () ($cur:ident $($sample: ident)*)) => {
325        let (casey::lower!(ref $cur), $(casey::lower!(ref $sample)),*) = $v;
326        let r = $r.chain(
327            $cur.shrink(casey::lower!($cur).clone()).map(move |$cur| {
328                none_pad!(($cur) $($sample)*)
329            })
330        );
331        shrink_tuple!(r $v ($cur) ($($sample)*));
332    };
333    ($r:ident $v:ident ($($pre:ident)+) ($cur:ident $($sample: ident)*)) => {
334        let ($(casey::lower!(ref $pre)),*, casey::lower!(ref $cur), $(casey::lower!(ref $sample)),*) = $v;
335        let r = $r.chain(
336            $cur.shrink(casey::lower!($cur).clone()).map(move |$cur| {
337                none_pad!($($pre)* ($cur) $($sample)*)
338            })
339        );
340        shrink_tuple!(r $v ($($pre)* $cur) ($($sample)*));
341    };
342    ($r:ident $v:ident ($($pre:ident)*) ()) => {
343        let ($(casey::lower!($pre)),*) = $v;
344        return Box::new($r.map(move |($($pre),*)| {
345            ($($pre.unwrap_or(casey::lower!($pre).clone())),*)
346        }))
347    };
348}
349
350macro_rules! sample_tuple {
351    ($($name: ident),*) => {
352
353impl<$($name),*> Sample for ($($name),*,)
354where
355    $($name: Sample),*,
356    $($name::Output: Clone),*,
357{
358    type Output = ($($name::Output),*,);
359
360    #[allow(non_snake_case)]
361    fn generate(&mut self, r: &mut Random) -> Self::Output {
362        let ($(casey::lower!($name)),*,) = self;
363        ($(casey::lower!($name).generate(r)),*,)
364    }
365
366    #[allow(non_snake_case)]
367    fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
368        let ($($name),*,) = self;
369        shrink_tuple!(v () $($name)*);
370    }
371}
372
373    }
374}
375
376impl<A> Sample for (A,)
377where
378    A: Sample,
379{
380    type Output = (A::Output,);
381
382    fn generate(&mut self, g: &mut Random) -> Self::Output {
383        (self.0.generate(g),)
384    }
385
386    fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
387        Box::new(self.0.shrink(v.0).map(|v| (v,)))
388    }
389}
390
391sample_tuple!(A, B);
392sample_tuple!(A, B, C);
393sample_tuple!(A, B, C, D);
394sample_tuple!(A, B, C, D, E);
395sample_tuple!(A, B, C, D, E, F);
396sample_tuple!(A, B, C, D, E, F, G);
397sample_tuple!(A, B, C, D, E, F, G, H);
398
399/// See [`Sample::chain_resample`].
400#[derive(Clone, Debug)]
401pub struct ChainResample<S, F> {
402    supersampler: S,
403    transform: F,
404    subsamples: usize,
405}
406
407/// Capture the `seed` used to generate the given `value`.
408#[derive(Clone, Debug)]
409pub struct Chained<S, V> {
410    seed: S,
411    pub value: V,
412}
413
414impl<S, F, SS> Sample for ChainResample<S, F>
415where
416    S: Sample,
417    S::Output: Clone,
418    SS: Sample + 'static,
419    F: Fn(S::Output) -> SS,
420{
421    type Output = Chained<S::Output, SS::Output>;
422
423    fn generate(&mut self, g: &mut Random) -> Self::Output {
424        let seed = self.supersampler.generate(g);
425        let value = (self.transform)(seed.clone()).generate(g);
426
427        Chained { seed, value }
428    }
429
430    fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
431        Box::new(self.supersampler.shrink(v.seed).flat_map(|shrunk_seed| {
432            let mut g = Random::new();
433            let mut sampler = (self.transform)(shrunk_seed.clone());
434            (0..self.subsamples).map(move |_| Chained {
435                seed: shrunk_seed.clone(),
436                value: sampler.generate(&mut g),
437            })
438        }))
439    }
440}
441
442impl<T> Sample for Box<dyn Sample<Output = T>> {
443    type Output = T;
444
445    fn generate(&mut self, g: &mut Random) -> Self::Output {
446        self.as_mut().generate(g)
447    }
448
449    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
450        self.as_ref().shrink(v)
451    }
452}
453
454impl<T> Sample for Box<dyn Sample<Output = T> + Send + Sync> {
455    type Output = T;
456
457    fn generate(&mut self, g: &mut Random) -> Self::Output {
458        self.as_mut().generate(g)
459    }
460
461    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
462        self.as_ref().shrink(v)
463    }
464}
465
466/// Generate a boolean value with the specified probability (in the range
467/// `0..=1`).
468#[derive(Debug, Clone)]
469pub struct Chance(pub f32);
470
471impl Sample for Chance {
472    type Output = bool;
473
474    fn generate(&mut self, g: &mut Random) -> Self::Output {
475        g.gen_range(0.0..1.0) < self.0
476    }
477}
478
479/// Bridge for creating a [`Sample`] from an [`Arbitrary`] type.
480pub struct ArbitrarySampler<T> {
481    gen: Gen,
482    phantom: PhantomData<T>,
483    validate: fn(&T) -> bool,
484}
485
486impl<T> Clone for ArbitrarySampler<T> {
487    fn clone(&self) -> Self {
488        ArbitrarySampler {
489            gen: Gen::new(self.gen.size()),
490            phantom: self.phantom.clone(),
491            validate: self.validate.clone(),
492        }
493    }
494}
495
496impl<T: Arbitrary> Sample for ArbitrarySampler<T> {
497    type Output = T;
498
499    fn generate(&mut self, _: &mut Random) -> Self::Output {
500        for _ in 0..1000 {
501            let value = Arbitrary::arbitrary(&mut self.gen);
502            if (self.validate)(&value) {
503                return value;
504            }
505        }
506        panic!("could not find valid value after 1000 iterations")
507    }
508
509    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
510        Arbitrary::shrink(&v)
511    }
512}
513
514/// Sampler for any type implementing [`Arbitrary`].
515pub fn arbitrary<T: Arbitrary>() -> ArbitrarySampler<T> {
516    ArbitrarySampler {
517        gen: Gen::new(100),
518        phantom: PhantomData,
519        validate: |_| true,
520    }
521}
522
523/// Sampler for non-NaN [f32]
524pub fn valid_f32() -> ArbitrarySampler<f32> {
525    ArbitrarySampler {
526        gen: Gen::new(100),
527        phantom: PhantomData,
528        validate: |f| !f.is_nan(),
529    }
530}
531
532/// Sampler for non-NaN [f64]
533pub fn valid_f64() -> ArbitrarySampler<f64> {
534    ArbitrarySampler {
535        gen: Gen::new(100),
536        phantom: PhantomData,
537        validate: |f| !f.is_nan(),
538    }
539}
540
541/// Sampler that always generates a fixed value.
542#[derive(Debug, Clone)]
543pub struct Always<T>(pub T);
544
545impl<T: Clone> Sample for Always<T> {
546    type Output = T;
547
548    fn generate(&mut self, _: &mut Random) -> Self::Output {
549        self.0.clone()
550    }
551}
552
553/// Sample from a list of `choice` values.
554///
555/// [`Sample::shrink`] will attempt to shrink down to the first element in the
556/// [`Choice`]:
557///
558/// ```
559/// use sample_std::{Random, Sample, choice};
560///
561/// let mut sampler = choice(["cora", "coraline"]);
562/// let name = sampler.generate(&mut Random::new());
563/// assert!(name.starts_with("cora"));
564///
565/// assert_eq!(sampler.shrink("coraline").next(), Some("cora"));
566/// ```
567pub fn choice<T, II>(choices: II) -> Choice<T>
568where
569    T: Clone + PartialEq,
570    II: IntoIterator<Item = T>,
571{
572    Choice {
573        choices: choices.into_iter().collect(),
574    }
575}
576
577/// See [choice].
578#[derive(Clone, Debug)]
579pub struct Choice<T> {
580    pub choices: Vec<T>,
581}
582
583impl<T> Sample for Choice<T>
584where
585    T: Clone + PartialEq,
586{
587    type Output = T;
588
589    fn generate(&mut self, g: &mut Random) -> Self::Output {
590        g.choose(&self.choices).unwrap().clone()
591    }
592
593    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
594        let ix = self.choices.iter().position(|el| el == &v).unwrap_or(0);
595        Box::new((0..ix).map(|shrunk_ix| self.choices[shrunk_ix].clone()))
596    }
597}
598
599/// Sample values from a sampler randomly drawn from a list of `choices`.
600///
601/// `shrink` attempts to run the [`Sample::shrink`] method from each specified
602/// sampler in order. This allows [`sampler_choice`] to work with choices that
603/// generate `enum` variants (e.g. via [`Sample::try_convert`]):
604///
605/// ```
606/// use std::boxed::Box;
607/// use sample_std::{Sample, sampler_choice};
608///
609/// #[derive(Clone)]
610/// enum Widget {
611///     Bib(usize),
612///     Bob(usize)
613/// }
614///
615/// type WidgetSampler = Box<dyn Sample<Output = Widget>>;
616///
617/// let bibs: WidgetSampler = Box::new((0..100).try_convert(Widget::Bib, |v| match v {
618///     Widget::Bib(u) => Some(u),
619///     _ => None,
620/// }));
621///
622/// let bobs: WidgetSampler = Box::new((100..200).try_convert(Widget::Bob, |v| match v {
623///     Widget::Bob(u) => Some(u),
624///     _ => None,
625/// }));
626///
627/// let widgets = sampler_choice([bibs, bobs]);
628/// ```
629///
630/// This may lead to unexpected shrinking behavior if every sampler in the
631/// [`SamplerChoice`] can shrink a given value.
632pub fn sampler_choice<C, II>(choices: II) -> SamplerChoice<C>
633where
634    II: IntoIterator<Item = C>,
635    C: Sample,
636    <C as Sample>::Output: Clone,
637{
638    SamplerChoice {
639        choices: choices.into_iter().collect(),
640    }
641}
642
643/// See [`sampler_choice`].
644#[derive(Clone, Debug)]
645pub struct SamplerChoice<C> {
646    pub choices: Vec<C>,
647}
648
649impl<C> SamplerChoice<C> {
650    pub fn or(self, other: Self) -> Self {
651        Self {
652            choices: self
653                .choices
654                .into_iter()
655                .chain(other.choices.into_iter())
656                .collect(),
657        }
658    }
659}
660
661impl<C, T> Sample for SamplerChoice<C>
662where
663    C: Sample<Output = T>,
664    T: Clone + 'static,
665{
666    type Output = T;
667
668    fn generate(&mut self, g: &mut Random) -> Self::Output {
669        let ix = g.gen_range(0..self.choices.len());
670        self.choices[ix].generate(g)
671    }
672
673    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
674        Box::new(self.choices.iter().flat_map(move |c| c.shrink(v.clone())))
675    }
676}
677
678impl<T, I> Sample for Range<T>
679where
680    T: SampleUniform + Clone + PartialOrd + 'static,
681    Range<T>: IntoIterator<IntoIter = I>,
682    I: DoubleEndedIterator<Item = T> + 'static,
683{
684    type Output = T;
685
686    fn generate(&mut self, g: &mut Random) -> Self::Output {
687        g.gen_range(self.clone())
688    }
689
690    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
691        if self.start != v {
692            Box::new(
693                std::iter::once(self.start.clone())
694                    .chain((self.start.clone()..v.clone()).into_iter().rev().take(1)),
695            )
696        } else {
697            Box::new(std::iter::empty())
698        }
699    }
700}
701
702/// Sample strings given a "valid" regular expression.
703///
704/// Shrinking is done by shortening the string and testing if the expression
705/// still matches.
706#[derive(Clone, Debug)]
707pub struct Regex {
708    pub dist: rand_regex::Regex,
709    pub re: regex::Regex,
710}
711
712impl Regex {
713    /// Create a new [Regex] sampler with the given `pattern` string.
714    pub fn new(pattern: &str) -> Self {
715        Regex {
716            dist: rand_regex::Regex::compile(pattern, 100).unwrap(),
717            re: regex::Regex::new(pattern).unwrap(),
718        }
719    }
720}
721
722impl Sample for Regex {
723    type Output = String;
724
725    fn generate(&mut self, g: &mut Random) -> Self::Output {
726        self.dist.sample(&mut g.rng)
727    }
728
729    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
730        let re = self.re.clone();
731        // this obviously could be improved via deeper integration with the
732        // underlying regex, but the generation library does not appear to
733        // expose interfaces to do so
734        Box::new(Iterator::flat_map(0..v.len(), move |ix| {
735            let mut shrunk: String = String::with_capacity(v.len());
736            shrunk.push_str(&v[0..ix]);
737            shrunk.push_str(&v[ix..]);
738
739            if re.is_match(&shrunk) {
740                Some(shrunk)
741            } else {
742                None
743            }
744        }))
745    }
746}
747
748/// Sample a [`Vec`] with a length drawn from a `usize` [`Sample`] and elements
749/// drawn from the `el` sampler.
750///
751/// Shrinking attempts to first shrink the length, and then shrink each element
752/// within the [`Vec`].
753#[derive(Debug, Clone)]
754pub struct VecSampler<S, I> {
755    pub length: S,
756    pub el: I,
757}
758
759impl<S, I, T> Sample for VecSampler<S, I>
760where
761    S: Sample<Output = usize>,
762    I: Sample<Output = T>,
763    T: Clone + 'static,
764{
765    type Output = Vec<T>;
766
767    fn generate(&mut self, g: &mut Random) -> Self::Output {
768        Iterator::map(0..self.length.generate(g), |_| self.el.generate(g)).collect()
769    }
770
771    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
772        Box::new(self.length.shrink(v.len()).flat_map(move |new_len| {
773            assert!(new_len < v.len());
774            let gap = v.len() - new_len;
775
776            let iv = v.clone();
777            let iv2 = v.clone();
778
779            Iterator::map(0..new_len, move |cut| {
780                iv[0..cut]
781                    .iter()
782                    .chain(iv[cut + gap..].iter())
783                    .cloned()
784                    .collect()
785            })
786            .chain(Iterator::flat_map(0..v.len(), move |ix| {
787                let vref = iv2.clone();
788                let el = vref[ix].clone();
789                self.el.shrink(el).map(move |shrunk| {
790                    let mut copy: Vec<T> = vref.clone();
791                    copy[ix] = shrunk.clone();
792                    copy.clone()
793                })
794            }))
795        }))
796    }
797}
798
799/// Use a [`Vec`] of `samplers` to generate a new [`Vec`] of equal length, where
800/// each sampler in the [`Vec`] is used to sample the value at its corresponding
801/// position.
802///
803/// Shrinking proceeds per-element within the generated [`Vec`] in index order.
804pub fn sample_all<S>(samplers: Vec<S>) -> SampleAll<S>
805where
806    S: Sample,
807{
808    SampleAll { samplers }
809}
810
811/// See [`sample_all`].
812pub struct SampleAll<S> {
813    pub samplers: Vec<S>,
814}
815
816impl<S> Sample for SampleAll<S>
817where
818    S: Sample,
819    S::Output: Clone,
820{
821    type Output = Vec<S::Output>;
822
823    fn generate(&mut self, g: &mut Random) -> Self::Output {
824        self.samplers.iter_mut().map(|s| s.generate(g)).collect()
825    }
826
827    fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
828        Box::new((0..self.samplers.len()).flat_map(move |ix| {
829            let mut updated = v.clone();
830
831            self.samplers[ix]
832                .shrink(updated[ix].clone())
833                .map(move |sv| {
834                    updated[ix] = sv;
835                    updated.clone()
836                })
837        }))
838    }
839}
840
841#[cfg(test)]
842mod tests {}