fuzzcheck 0.12.1

A modular, structure-aware, and feedback-driven fuzzing engine for Rust functions
Documentation
use std::any::Any;

use super::CrossoverStep;
use crate::{DefaultMutator, Mutator, CROSSOVER_RATE};

/// Default mutator of `Box<T>`
#[derive(Default)]
pub struct BoxMutator<M> {
    mutator: M,
    rng: fastrand::Rng,
}
impl<M> BoxMutator<M> {
    #[no_coverage]
    pub fn new(mutator: M) -> Self {
        Self {
            mutator,
            rng: fastrand::Rng::new(),
        }
    }
}
#[derive(Clone)]
pub struct MutationStep<T, MS> {
    crossover_step: CrossoverStep<T>,
    inner: MS,
}

pub enum UnmutateToken<T, U> {
    Replace(T),
    Inner(U),
}

impl<T: Clone + 'static, M: Mutator<T>> Mutator<Box<T>> for BoxMutator<M> {
    #[doc(hidden)]
    type Cache = M::Cache;
    #[doc(hidden)]
    type MutationStep = MutationStep<T, M::MutationStep>;
    #[doc(hidden)]
    type ArbitraryStep = M::ArbitraryStep;
    #[doc(hidden)]
    type UnmutateToken = UnmutateToken<T, M::UnmutateToken>;

    #[doc(hidden)]
    #[no_coverage]
    fn default_arbitrary_step(&self) -> Self::ArbitraryStep {
        self.mutator.default_arbitrary_step()
    }
    #[doc(hidden)]
    #[no_coverage]
    fn is_valid(&self, value: &Box<T>) -> bool {
        self.mutator.is_valid(value)
    }
    #[doc(hidden)]
    #[no_coverage]
    fn validate_value(&self, value: &Box<T>) -> Option<Self::Cache> {
        self.mutator.validate_value(value)
    }
    #[doc(hidden)]
    #[no_coverage]
    fn default_mutation_step(&self, value: &Box<T>, cache: &Self::Cache) -> Self::MutationStep {
        MutationStep {
            crossover_step: CrossoverStep::default(),
            inner: self.mutator.default_mutation_step(value, cache),
        }
    }

    #[doc(hidden)]
    #[no_coverage]
    fn global_search_space_complexity(&self) -> f64 {
        self.mutator.global_search_space_complexity()
    }

    #[doc(hidden)]
    #[no_coverage]
    fn max_complexity(&self) -> f64 {
        self.mutator.max_complexity()
    }

    #[doc(hidden)]
    #[no_coverage]
    fn min_complexity(&self) -> f64 {
        self.mutator.min_complexity()
    }

    #[doc(hidden)]
    #[no_coverage]
    fn complexity(&self, value: &Box<T>, cache: &Self::Cache) -> f64 {
        self.mutator.complexity(value, cache)
    }

    #[doc(hidden)]
    #[no_coverage]
    fn ordered_arbitrary(&self, step: &mut Self::ArbitraryStep, max_cplx: f64) -> Option<(Box<T>, f64)> {
        if let Some((value, cache)) = self.mutator.ordered_arbitrary(step, max_cplx) {
            Some((Box::new(value), cache))
        } else {
            None
        }
    }

    #[doc(hidden)]
    #[no_coverage]
    fn random_arbitrary(&self, max_cplx: f64) -> (Box<T>, f64) {
        let (value, cache) = self.mutator.random_arbitrary(max_cplx);
        (Box::new(value), cache)
    }

    #[doc(hidden)]
    #[no_coverage]
    fn ordered_mutate(
        &self,
        value: &mut Box<T>,
        cache: &mut Self::Cache,
        step: &mut Self::MutationStep,
        subvalue_provider: &dyn crate::SubValueProvider,
        max_cplx: f64,
    ) -> Option<(Self::UnmutateToken, f64)> {
        if self.rng.u8(..CROSSOVER_RATE) == 0 {
            if let Some((subvalue, subcplx)) = step.crossover_step.get_next_subvalue(subvalue_provider, max_cplx) {
                if self.mutator.is_valid(subvalue) {
                    let mut replacer = subvalue.clone();
                    std::mem::swap(value.as_mut(), &mut replacer);
                    return Some((UnmutateToken::Replace(replacer), subcplx));
                }
            }
        }
        if let Some((t, cplx)) = self
            .mutator
            .ordered_mutate(value, cache, &mut step.inner, subvalue_provider, max_cplx)
        {
            Some((UnmutateToken::Inner(t), cplx))
        } else {
            None
        }
    }

    #[doc(hidden)]
    #[no_coverage]
    fn random_mutate(&self, value: &mut Box<T>, cache: &mut Self::Cache, max_cplx: f64) -> (Self::UnmutateToken, f64) {
        let (t, cplx) = self.mutator.random_mutate(value, cache, max_cplx);
        (UnmutateToken::Inner(t), cplx)
    }

    #[doc(hidden)]
    #[no_coverage]
    fn unmutate(&self, value: &mut Box<T>, cache: &mut Self::Cache, t: Self::UnmutateToken) {
        match t {
            UnmutateToken::Replace(x) => **value = x,
            UnmutateToken::Inner(t) => self.mutator.unmutate(value, cache, t),
        }
    }

    #[doc(hidden)]
    #[no_coverage]
    fn visit_subvalues<'a>(&self, value: &'a Box<T>, cache: &'a Self::Cache, visit: &mut dyn FnMut(&'a dyn Any, f64)) {
        self.mutator.visit_subvalues(value, cache, visit)
    }
}

impl<T> DefaultMutator for Box<T>
where
    T: DefaultMutator + 'static,
{
    #[doc(hidden)]
    type Mutator = BoxMutator<<T as DefaultMutator>::Mutator>;
    #[doc(hidden)]
    #[no_coverage]
    fn default_mutator() -> Self::Mutator {
        Self::Mutator::new(T::default_mutator())
    }
}