pub trait Mutate<T>where
T: ?Sized,{
// Required method
fn mutate(
&mut self,
mutations: &mut Candidates<'_>,
value: &mut T,
) -> Result<()>;
// Provided methods
fn or<M>(self, other: M) -> Or<Self, M>
where Self: Sized { ... }
fn map<F>(self, f: F) -> Map<Self, F>
where Self: Sized,
F: FnMut(&mut Context, &mut T) -> Result<()> { ... }
fn proj<F, U>(self, f: F) -> Proj<Self, F>
where Self: Sized,
F: FnMut(&mut U) -> &mut T { ... }
fn by_ref(&mut self) -> &mut Self
where Self: Sized { ... }
}Expand description
A trait for mutating values.
You can think of Mutate<T> as a streaming iterator of Ts but instead of
internally containing and yielding access to the Ts, it takes an &mut T
as an argument and mutates it in place.
The main method is the mutate method, which applies one
of many potential mutations to the given value, or returns an error.
§Example: Using a Type’s Default Mutator
Many types implement the DefaultMutate trait, which provides a default
mutator for that type. You can use this default mutator by calling
mutate on a Session with a value of
that type.
use mutatis::{Context, Session};
let mut session = Session::new();
let mut x = 1234;
session.mutate(&mut x)?;
for _ in 0..5 {
session.mutate(&mut x)?;
println!("mutated x is {x}");
}
panic!();
// Example output:
//
// mutated x is 1682887620§Example: Using Custom Mutators
use mutatis::{mutators as m, Mutate, Session};
// Define a mutator for `u32`s that only creates multiples-of-four
let mut mutator = m::u32()
.map(|_ctx, x| {
*x = *x & !3; // Clear the bottom two bits to make `x` a multiple of four.
Ok(())
});
// Mutate a value a bunch of times!
let mut x = 1234;
let mut session = Session::new();
for _ in 0..5 {
session.mutate_with(&mut mutator, &mut x)?;
println!("mutated x is {x}");
}
panic!();
// Example output:
//
// mutated x is 2436583184
// mutated x is 2032949584
// mutated x is 2631247496
// mutated x is 199875380
// mutated x is 3751781284§Exhaustion
A mutator may become exhausted, meaning that it doesn’t have any more
mutations it can perform for a given value. In this case, the mutator may
return an error of kind
ErrorKind::Exhausted. Many mutators
are effectively inexhaustible (or it would be prohibitively expensive to
precisely track whether they’ve already emitted every possible variant of a
value) and therefore it is valid for a mutator to never report exhaustion.
You may also ignore exhaustion errors via the
mutatis::error::ResultExt::ignore_exhausted
extension method.
Note that you should never return an ErrorKind::Exhausted error from your
own manual Mutate implementations. Instead, simply avoid registering any
candidate mutations and, if no other sibling or parent mutators have any
potential mutations either, then the library will return an exhaustion error
for you.
§Many-to-Many
Note that the relationship between mutator types and mutated types is not one-to-one: a single mutator type can mutate many different types, and a single type can be mutated by many different mutator types. This gives you the flexibility to define new mutators for existing types (including those that are not defined by your own crate).
use mutatis::{
mutators as m, DefaultMutate, Mutate, Session, Candidates,
Result,
};
#[derive(Mutate)] // Derive a default mutator for `Foo`s.
pub struct Foo(u32);
// Also define and implement a second mutator type for `Foo` by hand!
pub struct AlignedFooMutator{
inner: <Foo as DefaultMutate>::DefaultMutate,
alignment: u32,
}
impl Mutate<Foo> for AlignedFooMutator {
fn mutate(&mut self, mutations: &mut Candidates, foo: &mut Foo) -> Result<()> {
self.inner
.by_ref()
.map(|_context, foo| {
// Clear the bottom bits to keep the `Foo` "aligned".
debug_assert!(self.alignment.is_power_of_two());
let mask = !(self.alignment - 1);
foo.0 = foo.0 & mask;
Ok(())
})
.mutate(mutations, foo)
}
}Required Methods§
sourcefn mutate(
&mut self,
mutations: &mut Candidates<'_>,
value: &mut T,
) -> Result<()>
fn mutate( &mut self, mutations: &mut Candidates<'_>, value: &mut T, ) -> Result<()>
Pseudo-randomly mutate the given value.
§Calling the mutate Method
If you just want to mutate a value, use Session::mutate or
Session::mutate_with instead of invoking this trait method
directly. See their documentation for more details.
§Implementing the mutate Method
Register every mutation that a mutator could perform by invoking the
mutations.mutation(...) function, passing in
a closure that performs that mutation, updating value and self as
necessary.
mutate implementations must only mutate self and the given value
from inside a registered mutation closure. It must not update self or
modify value outside of one of those mutation closures.
Furthermore, all mutate implementations must be deterministic: given
the same inputs, the same set of mutations must be registered in the
same order.
These requirements exist because, under the hood, the mutate method is
called twice for every mutation that is actually performed:
-
First,
mutateis called to count all the possible mutations that could be performed. In this phase, the mutation closures are ignored. -
Next, a random index
ibetween0and that count is chosen. This is the index of the mutation that we will actually be applied. -
Finally,
mutateis called again. In this phase, theith mutation closure is invoked, applying the mutation, while all others are ignored.
Note that the registered mutations are roughly uniformly selected from, so if you wish to skew the distribution of mutations, making certain mutations more probable than others, you may register mutations multiple times or register overlapping mutations.
§Example
use mutatis::{
mutators as m, Generate, Mutate, Session, Candidates,
Result,
};
// A custom mutator that creates pairs where the first element is less
// than or equal to the second.
pub struct OrderedPairs;
impl Mutate<(u64, u64)> for OrderedPairs {
fn mutate(
&mut self,
mutations: &mut Candidates<'_>,
pair: &mut (u64, u64),
) -> Result<()> {
// We *cannot* mutate `self` or `pair` out here.
if *pair != (0, 0) {
// Note: we register this mutation -- even when not
// shrinking and even though the subsequent mutation
// subsumes this one -- to bias the distribution towards
// smaller values.
mutations.mutation(|ctx| {
// We *can* mutate `self` and `pair` inside here.
let a = m::range(0..=pair.0).generate(ctx)?;
let b = m::range(0..=pair.1).generate(ctx)?;
*pair = (a.min(b), a.max(b));
Ok(())
})?;
}
if !mutations.shrink() {
// Only register this fully-general mutation when we are
// not shrinking, as this can grow the pair.
mutations.mutation(|ctx| {
// We *can* mutate `self` and `pair` inside here.
let a = m::u64().generate(ctx)?;
let b = m::u64().generate(ctx)?;
*pair = (a.min(b), a.max(b));
Ok(())
})?;
}
Ok(())
}
}
// Create a pair.
let mut pair = (1000, 2000);
// And mutate it a bunch of times!
let mut session = Session::new();
for _ in 0..3 {
session.mutate_with(&mut OrderedPairs, &mut pair)?;
println!("mutated pair is {pair:?}");
}
// Example output:
//
// mutated pair is (11, 861)
// mutated pair is (8, 818)
// mutated pair is (3305948426120559093, 16569598107406464568)Provided Methods§
sourcefn or<M>(self, other: M) -> Or<Self, M>where
Self: Sized,
fn or<M>(self, other: M) -> Or<Self, M>where
Self: Sized,
Create a new mutator that performs either this mutation or the other
mutation.
§Example
use mutatis::{mutators as m, Mutate, Session};
let mut session = Session::new();
// Either generate `-1`...
let mut mutator = m::just(-1)
// ...or values in the range `0x40..=0x4f`...
.or(m::range(0x40..=0x4f))
// ...or values with just a single bit set.
.or(m::range(0..=31).map(|_ctx, x| {
*x = 1 << *x;
Ok(())
}));
let mut value = 0;
for _ in 0..5 {
session.mutate_with(&mut mutator, &mut value)?;
println!("mutated value is {value:#x}");
}
// Example output:
//
// mutated value is 0x4a
// mutated value is 0xffffffff
// mutated value is 0x400000
// mutated value is 0x20000000
// mutated value is 0x4esourcefn map<F>(self, f: F) -> Map<Self, F>
fn map<F>(self, f: F) -> Map<Self, F>
Map a function over the mutations produced by this mutator.
§Example
use mutatis::{mutators as m, Mutate, Session};
let mut session = Session::new();
let mut mutator = m::i32().map(|context, value| {
// Ensure that the value is always positive.
if *value <= 0 {
*value = i32::from(context.rng().gen_u16());
}
Ok(())
});
let mut value = -42;
for _ in 0..10 {
session.mutate_with(&mut mutator, &mut value)?;
assert!(value > 0, "the mutated value is always positive");
}sourcefn proj<F, U>(self, f: F) -> Proj<Self, F>
fn proj<F, U>(self, f: F) -> Proj<Self, F>
Given a projection function F: FnMut(&mut U) -> &mut T, turn this
Mutate<T> into a Mutate<U>.
§Example
use mutatis::{mutators as m, Mutate, Session};
#[derive(Debug)]
pub struct NewType(u32);
let mut value = NewType(0);
let mut mutator = m::u32().proj(|x: &mut NewType| &mut x.0);
let mut session = Session::new();
for _ in 0..3 {
session.mutate_with(&mut mutator, &mut value)?;
println!("mutated value is {value:?}");
}
// Example output:
//
// mutated value is NewType(3729462868)
// mutated value is NewType(49968845)
// mutated value is NewType(2440803355)sourcefn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
Borrows a mutator, rather than consuming it.
This is useful to allow applying mutator adapters while still retaining ownership of the original mutator.
§Example
use mutatis::{mutators as m, Mutate, Session};
let mut mutator = m::u32().map(|_context, x| {
*x = *x & !3;
Ok(())
});
let mut value = 1234;
let mut session = Session::new();
{
let mut borrowed_mutator = mutator.by_ref().map(|_context, x| {
*x = x.wrapping_add(1);
Ok(())
});
session.mutate_with(&mut borrowed_mutator, &mut value)?;
println!("first mutated value is {value}");
}
// In the outer scope, we can still use the original mutator.
session.mutate_with(&mut mutator, &mut value)?;
println!("second mutated value is {value}");
// Example output:
//
// first mutated value is 3729462869
// second mutated value is 49968844