use rand::Rng;
use crate::{Chromosome, Crossover, Mutator};
pub trait Genome {
fn mutate(&mut self, mutator: &mut Mutator<impl Rng>);
fn crossover(&mut self, other: &mut Self, crossover: &mut Crossover<impl Rng>);
fn size_hint(&self) -> usize;
}
impl<Ch: Chromosome> Genome for Ch {
#[inline(always)]
fn mutate(&mut self, mutator: &mut Mutator<impl Rng>) {
mutator.chromosome(self);
}
#[inline(always)]
fn crossover(&mut self, other: &mut Self, crossover: &mut Crossover<impl Rng>) {
crossover.chromosome(self, other);
}
fn size_hint(&self) -> usize {
1
}
}
impl<G: Genome> Genome for Vec<G> {
fn mutate(&mut self, mutator: &mut Mutator<impl Rng>) {
mutator.iter(self.iter_mut());
}
fn crossover(&mut self, other: &mut Self, crossover: &mut Crossover<impl Rng>) {
crossover.iter(self.iter_mut(), other.iter_mut());
}
fn size_hint(&self) -> usize {
self.iter().map(|item| item.size_hint()).sum()
}
}
impl<G: Genome> Genome for [G] {
fn mutate(&mut self, mutator: &mut Mutator<impl Rng>) {
mutator.iter(self.iter_mut());
}
fn crossover(&mut self, other: &mut Self, crossover: &mut Crossover<impl Rng>) {
crossover.iter(self.iter_mut(), other.iter_mut());
}
fn size_hint(&self) -> usize {
self.iter().map(|item| item.size_hint()).sum()
}
}
macro_rules! impl_genome_tuple {
( $( $name:ident => $id:tt ),+ ) => {
impl<$($name : Genome),+> Genome for ($($name),+) {
fn mutate(&mut self, mutator: &mut Mutator<impl Rng>) {
mutator
$(.genome(&mut self.$id))+;
}
fn crossover(&mut self, other: &mut Self, crossover: &mut Crossover<impl Rng>) {
crossover
$(.genome(&mut self.$id, &mut other.$id))+;
}
fn size_hint(&self) -> usize {
0
$(+ self.$id.size_hint())+
}
}
}
}
impl_genome_tuple!(G1 => 0, G2 => 1);
impl_genome_tuple!(G1 => 0, G2 => 1, G3 => 2);
impl_genome_tuple!(G1 => 0, G2 => 1, G3 => 2, G4 => 3);
impl_genome_tuple!(G1 => 0, G2 => 1, G3 => 2, G4 => 3, G5 => 4);
impl_genome_tuple!(G1 => 0, G2 => 1, G3 => 2, G4 => 3, G5 => 4, G6 => 5);