fuzzcheck/mutators/
alternation.rs

1use std::any::Any;
2use std::cell::Cell;
3use std::cmp::Ordering;
4use std::marker::PhantomData;
5
6use crate::Mutator;
7
8/**
9A mutator that wraps multiple different mutators of the same type.
10
11```
12use fuzzcheck::mutators::alternation::AlternationMutator;
13use fuzzcheck::mutators::integer_within_range::U8WithinRangeMutator;
14
15let m1 = U8WithinRangeMutator::new(3 ..= 10);
16let m2 = U8WithinRangeMutator::new(78 ..= 200);
17
18let m = AlternationMutator::new(vec![m1, m2], 0.0);
19
20// m will produce values either in 3..=10 or in 78..=200
21```
22*/
23pub struct AlternationMutator<T, M>
24where
25    T: Clone + 'static,
26    M: Mutator<T>,
27{
28    mutators: Vec<M>,
29    rng: fastrand::Rng,
30    added_complexity: f64,
31    initialized: Cell<bool>,
32    min_complexity: Cell<f64>,
33    max_complexity: Cell<f64>,
34    search_space_complexity: Cell<f64>,
35    _phantom: PhantomData<T>,
36}
37
38impl<T, M> AlternationMutator<T, M>
39where
40    T: Clone + 'static,
41    M: Mutator<T>,
42{
43    #[coverage(off)]
44    pub fn new(mutators: Vec<M>, added_complexity: f64) -> Self {
45        assert!(!mutators.is_empty());
46
47        Self {
48            mutators,
49            rng: fastrand::Rng::default(),
50            added_complexity,
51            initialized: Cell::new(false),
52            min_complexity: Cell::new(std::f64::INFINITY),
53            max_complexity: Cell::new(std::f64::INFINITY),
54            search_space_complexity: Cell::new(std::f64::INFINITY),
55            _phantom: PhantomData,
56        }
57    }
58}
59
60#[doc(hidden)]
61#[derive(Clone)]
62pub struct ArbitraryStep<AS> {
63    inner: Vec<AS>,
64    indices: Vec<usize>,
65    idx: usize,
66}
67
68#[doc(hidden)]
69#[derive(Clone)]
70pub struct MutationStep<MS, AS> {
71    step: usize,
72    mutator_idx: usize,
73    inner: MS,
74    arbitrary: AS,
75}
76
77#[doc(hidden)]
78#[derive(Clone)]
79pub struct Cache<C> {
80    inner: C,
81    mutator_idx: usize,
82}
83
84#[doc(hidden)]
85pub enum UnmutateToken<T, U> {
86    Replace(T),
87    Inner(usize, U),
88}
89
90impl<T, M> AlternationMutator<T, M>
91where
92    T: Clone + 'static,
93    M: Mutator<T>,
94{
95    #[coverage(off)]
96    fn complexity_from_inner(&self, cplx: f64) -> f64 {
97        cplx + self.added_complexity
98    }
99}
100
101impl<T, M> Mutator<T> for AlternationMutator<T, M>
102where
103    T: Clone + 'static + 'static,
104    M: Mutator<T>,
105{
106    #[doc(hidden)]
107    type Cache = Vec<Cache<M::Cache>>;
108    #[doc(hidden)]
109    type MutationStep = Vec<MutationStep<M::MutationStep, Self::ArbitraryStep>>;
110    #[doc(hidden)]
111    type ArbitraryStep = ArbitraryStep<M::ArbitraryStep>;
112    #[doc(hidden)]
113    type UnmutateToken = UnmutateToken<T, M::UnmutateToken>;
114
115    #[doc(hidden)]
116    #[coverage(off)]
117    fn initialize(&self) {
118        for mutator in self.mutators.iter() {
119            mutator.initialize();
120        }
121
122        let complexity_from_choice = crate::mutators::size_to_cplxity(self.mutators.len());
123
124        let search_space_complexity = self
125            .mutators
126            .iter()
127            .map(
128                #[coverage(off)]
129                |m| {
130                    let cplx = m.global_search_space_complexity();
131                    if cplx == 0. {
132                        complexity_from_choice
133                    } else {
134                        cplx
135                    }
136                },
137            )
138            .max_by(
139                #[coverage(off)]
140                |x, y| x.partial_cmp(y).unwrap_or(Ordering::Equal),
141            )
142            .unwrap();
143
144        let max_complexity = self
145            .mutators
146            .iter()
147            .map(
148                #[coverage(off)]
149                |m| m.max_complexity() + self.added_complexity,
150            )
151            .max_by(
152                #[coverage(off)]
153                |x1, x2| x1.partial_cmp(x2).unwrap_or(Ordering::Equal),
154            )
155            .unwrap();
156        let min_complexity = self
157            .mutators
158            .iter()
159            .map(
160                #[coverage(off)]
161                |m| m.min_complexity() + self.added_complexity,
162            )
163            .min_by(
164                #[coverage(off)]
165                |x1, x2| x1.partial_cmp(x2).unwrap_or(Ordering::Equal),
166            )
167            .unwrap();
168
169        self.min_complexity.set(min_complexity);
170        self.max_complexity.set(max_complexity);
171        self.search_space_complexity.set(search_space_complexity);
172
173        for mutator in self.mutators.iter() {
174            mutator.initialize();
175        }
176        self.initialized.set(true);
177    }
178
179    #[doc(hidden)]
180    #[coverage(off)]
181    fn default_arbitrary_step(&self) -> Self::ArbitraryStep {
182        Self::ArbitraryStep {
183            inner: self
184                .mutators
185                .iter()
186                .map(
187                    #[coverage(off)]
188                    |m| m.default_arbitrary_step(),
189                )
190                .collect(),
191            indices: (0..self.mutators.len()).collect(),
192            idx: 0,
193        }
194    }
195
196    #[doc(hidden)]
197    #[coverage(off)]
198    fn is_valid(&self, value: &T) -> bool {
199        for m in self.mutators.iter() {
200            if m.is_valid(value) {
201                return true;
202            }
203        }
204        false
205    }
206
207    #[doc(hidden)]
208    #[coverage(off)]
209    fn validate_value(&self, value: &T) -> Option<Self::Cache> {
210        let mut caches = vec![];
211        for (idx, mutator) in self.mutators.iter().enumerate() {
212            if let Some(c) = mutator.validate_value(value) {
213                caches.push(Cache {
214                    inner: c,
215                    mutator_idx: idx,
216                });
217            }
218        }
219        if caches.is_empty() {
220            None
221        } else {
222            Some(caches)
223        }
224    }
225
226    #[doc(hidden)]
227    #[coverage(off)]
228    fn default_mutation_step(&self, value: &T, cache: &Self::Cache) -> Self::MutationStep {
229        cache
230            .iter()
231            .map(
232                #[coverage(off)]
233                |c| {
234                    let m = &self.mutators[c.mutator_idx];
235                    MutationStep {
236                        step: 0,
237                        mutator_idx: c.mutator_idx,
238                        inner: m.default_mutation_step(value, &c.inner),
239                        arbitrary: {
240                            let mut step = self.default_arbitrary_step();
241                            step.indices.remove(c.mutator_idx);
242                            step
243                        },
244                    }
245                },
246            )
247            .collect()
248    }
249
250    #[doc(hidden)]
251    #[coverage(off)]
252    fn global_search_space_complexity(&self) -> f64 {
253        self.search_space_complexity.get()
254    }
255
256    #[doc(hidden)]
257    #[coverage(off)]
258    fn max_complexity(&self) -> f64 {
259        self.max_complexity.get()
260    }
261
262    #[doc(hidden)]
263    #[coverage(off)]
264    fn min_complexity(&self) -> f64 {
265        self.min_complexity.get()
266    }
267
268    #[doc(hidden)]
269    #[coverage(off)]
270    fn complexity(&self, value: &T, cache: &Self::Cache) -> f64 {
271        let cache = &cache[0];
272        self.complexity_from_inner(self.mutators[cache.mutator_idx].complexity(value, &cache.inner))
273    }
274
275    #[doc(hidden)]
276    #[coverage(off)]
277    fn ordered_arbitrary(&self, step: &mut Self::ArbitraryStep, max_cplx: f64) -> Option<(T, f64)> {
278        if step.indices.is_empty() {
279            return None;
280        }
281        if max_cplx < self.min_complexity() {
282            return None;
283        }
284
285        let idx = step.indices[step.idx % step.indices.len()];
286        let mutator = &self.mutators[idx];
287        let inner_step = &mut step.inner[idx];
288        if let Some((v, c)) = mutator.ordered_arbitrary(inner_step, max_cplx) {
289            step.idx += 1;
290            Some((v, self.complexity_from_inner(c)))
291        } else {
292            step.indices.remove(step.idx % step.indices.len());
293            self.ordered_arbitrary(step, max_cplx)
294        }
295    }
296
297    #[doc(hidden)]
298    #[coverage(off)]
299    fn random_arbitrary(&self, max_cplx: f64) -> (T, f64) {
300        let idx = self.rng.usize(..self.mutators.len());
301        let mutator = &self.mutators[idx];
302
303        let (v, c) = mutator.random_arbitrary(max_cplx);
304        (v, self.complexity_from_inner(c))
305    }
306
307    #[doc(hidden)]
308    #[coverage(off)]
309    fn ordered_mutate(
310        &self,
311        value: &mut T,
312        cache: &mut Self::Cache,
313        step: &mut Self::MutationStep,
314        subvalue_provider: &dyn crate::SubValueProvider,
315        max_cplx: f64,
316    ) -> Option<(Self::UnmutateToken, f64)> {
317        if max_cplx < self.min_complexity() {
318            return None;
319        }
320        if step.is_empty() {
321            return None;
322        }
323
324        if self.rng.usize(..100) == 0 {
325            let (new_value, cplx) = self.random_arbitrary(max_cplx);
326            let old_value = ::std::mem::replace(value, new_value);
327            return Some((UnmutateToken::Replace(old_value), cplx));
328        }
329
330        let step_idx = self.rng.usize(..step.len());
331        let chosen_step = &mut step[step_idx];
332        chosen_step.step += 1;
333        // TODO: instead of 20, should be the sum of all important arbitraries of the sub mutators
334        // and maybe it shouldn't be done all at the beginning, but be interspersed in between the
335        // important mutations of the current mutator
336        if chosen_step.step < 20 {
337            if let Some((mut v, cplx)) = self.ordered_arbitrary(&mut chosen_step.arbitrary, max_cplx) {
338                std::mem::swap(value, &mut v);
339                return Some((UnmutateToken::Replace(v), cplx));
340            }
341        }
342
343        let mutator_idx = chosen_step.mutator_idx;
344        let chosen_cache = cache
345            .iter_mut()
346            .find(
347                #[coverage(off)]
348                |c| c.mutator_idx == mutator_idx,
349            )
350            .unwrap();
351
352        let idx = chosen_cache.mutator_idx;
353        assert_eq!(idx, mutator_idx);
354
355        let mutator = &self.mutators[idx];
356        if let Some((t, cplx)) = mutator.ordered_mutate(
357            value,
358            &mut chosen_cache.inner,
359            &mut chosen_step.inner,
360            subvalue_provider,
361            max_cplx,
362        ) {
363            Some((UnmutateToken::Inner(idx, t), self.complexity_from_inner(cplx)))
364        } else {
365            if let Some((mut v, cplx)) = self.ordered_arbitrary(&mut chosen_step.arbitrary, max_cplx) {
366                std::mem::swap(value, &mut v);
367                Some((UnmutateToken::Replace(v), cplx))
368            } else {
369                step.remove(step_idx);
370                if step.is_empty() {
371                    None
372                } else {
373                    self.ordered_mutate(value, cache, step, subvalue_provider, max_cplx)
374                }
375            }
376        }
377    }
378
379    #[doc(hidden)]
380    #[coverage(off)]
381    fn random_mutate(&self, value: &mut T, cache: &mut Self::Cache, max_cplx: f64) -> (Self::UnmutateToken, f64) {
382        let cache_idx = self.rng.usize(..cache.len());
383        let cache = &mut cache[cache_idx];
384
385        let idx = cache.mutator_idx;
386        let mutator = &self.mutators[idx];
387        // this ensures that `arbitrary` is used instead of a unit mutator that will return
388        // the same thing every time
389        // there should be a better way to prevent this though
390        // maybe it's time to give random_mutate a MutationStep too?
391        // TODO: should use the global search space complexity here instead of max complexity?
392        if self.rng.usize(..100) == 0 || mutator.max_complexity() < 0.1 {
393            let (new_value, cplx) = self.random_arbitrary(max_cplx);
394            let old_value = ::std::mem::replace(value, new_value);
395            return (UnmutateToken::Replace(old_value), cplx);
396        }
397
398        let (t, cplx) = mutator.random_mutate(value, &mut cache.inner, max_cplx);
399        (UnmutateToken::Inner(idx, t), self.complexity_from_inner(cplx))
400    }
401
402    #[doc(hidden)]
403    #[coverage(off)]
404    fn unmutate(&self, value: &mut T, cache: &mut Self::Cache, t: Self::UnmutateToken) {
405        match t {
406            UnmutateToken::Replace(v) => {
407                let _ = std::mem::replace(value, v);
408            }
409            UnmutateToken::Inner(idx, t) => {
410                let mutator = &self.mutators[idx];
411                let cache = cache
412                    .iter_mut()
413                    .find(
414                        #[coverage(off)]
415                        |c| c.mutator_idx == idx,
416                    )
417                    .unwrap();
418                mutator.unmutate(value, &mut cache.inner, t);
419            }
420        }
421    }
422
423    #[doc(hidden)]
424    #[coverage(off)]
425    fn visit_subvalues<'a>(&self, value: &'a T, cache: &'a Self::Cache, visit: &mut dyn FnMut(&'a dyn Any, f64)) {
426        for cache in cache.iter() {
427            let mutator_idx = cache.mutator_idx;
428            let mutator = &self.mutators[mutator_idx];
429            mutator.visit_subvalues(value, &cache.inner, visit);
430        }
431    }
432}