use super::*;
use std::mem;
#[derive(Clone, Debug, Default)]
pub struct HashMap<KM, VM> {
key_mutator: KM,
value_mutator: VM,
}
pub fn hash_map<KM, VM>(key_mutator: KM, value_mutator: VM) -> HashMap<KM, VM> {
HashMap {
key_mutator,
value_mutator,
}
}
impl<KM, VM, K, V> Mutate<std::collections::HashMap<K, V>> for HashMap<KM, VM>
where
KM: Generate<K>,
VM: Generate<V> + Mutate<V>,
K: Eq + Hash,
{
#[inline]
fn mutation_count(
&self,
value: &std::collections::HashMap<K, V>,
shrink: bool,
) -> core::option::Option<u32> {
let mut count = 0u32;
count += !shrink as u32;
count += !value.is_empty() as u32;
for (k, v) in value.iter() {
count += self.value_mutator.mutation_count(v, shrink)?;
count += self.key_mutator.mutation_count(k, shrink)?;
}
Some(count)
}
#[inline]
fn mutate(
&mut self,
c: &mut Candidates,
value: &mut std::collections::HashMap<K, V>,
) -> Result<()> {
if !c.shrink() {
c.mutation(|ctx| {
let k = self.key_mutator.generate(ctx)?;
let v = self.value_mutator.generate(ctx)?;
value.insert(k, v);
Ok(())
})?;
}
if !value.is_empty() {
c.mutation(|ctx| {
let target = ctx.rng().gen_index(value.len()).unwrap();
let mut i = 0;
value.retain(|_, _| {
let keep = i != target;
i += 1;
keep
});
Ok(())
})?;
}
for (_k, v) in value.iter_mut() {
self.value_mutator.mutate(c, v)?;
}
if !value.is_empty() {
let elems = mem::take(value).into_iter();
value.reserve(elems.len());
let mut early_exit = None;
for (mut key, val) in elems {
if early_exit.is_none() {
match self.key_mutator.mutate(c, &mut key) {
Ok(()) => {}
Err(e) if e.is_early_exit() => {
early_exit = Some(e);
}
Err(e) => return Err(e),
}
}
value.insert(key, val);
}
if let Some(e) = early_exit {
return Err(e);
}
}
Ok(())
}
}
impl<KM, VM, K, V> Generate<std::collections::HashMap<K, V>> for HashMap<KM, VM>
where
KM: Generate<K>,
VM: Generate<V> + Mutate<V>,
K: Eq + Hash,
{
#[inline]
fn generate(&mut self, ctx: &mut Context) -> Result<std::collections::HashMap<K, V>> {
self.generate_via_mutate(ctx, 1)
}
}
impl<K, V> DefaultMutate for std::collections::HashMap<K, V>
where
K: DefaultMutate + Eq + Hash,
K::DefaultMutate: Generate<K>,
V: DefaultMutate,
V::DefaultMutate: Generate<V>,
{
type DefaultMutate = HashMap<K::DefaultMutate, V::DefaultMutate>;
}