use core::num::NonZeroUsize;
use rand::Rng;
use crate::neighbour::Neighbour;
use crate::random::Random;
use super::Gene;
impl Gene for char {}
impl Random for char {
fn random<RNG>(rng: &mut RNG) -> Self
where
RNG: Rng,
{
rng.gen()
}
}
impl Neighbour for char {
fn random_forward_neighbour<RNG>(&self, rng: &mut RNG, maximal_distance: NonZeroUsize) -> Option<char>
where
RNG: Rng,
{
if maximal_distance.get() == 1 {
return self.successor(rng);
}
// instead of collecting and then deciding on a concrete distance, we decide beforehand
// and then try to reach that point
let distance = rng.gen_range(1..=maximal_distance.get());
let mut current_char = *self;
// this implementation is not perfect and should be revised, both for speed and actual functionality
// preferably, we should have a range of chars and then randomly choose.
for _ in 0..distance {
if let Some(new_char) = non_rng_successor(current_char) {
current_char = new_char;
} else {
return None;
}
}
Some(current_char)
}
fn random_backward_neighbour<RNG>(&self, rng: &mut RNG, maximal_distance: NonZeroUsize) -> Option<char>
where
RNG: Rng,
{
if maximal_distance.get() == 1 {
return self.predecessor(rng);
}
// instead of collecting and then deciding on a concrete distance, we decide beforehand
// and then try to reach that point
let distance = rng.gen_range(1..=maximal_distance.get());
let mut current_char = *self;
// this implementation is not perfect and should be revised, both for speed and actual functionality
// preferably, we should have a range of chars and then randomly choose.
for _ in 0..distance {
if let Some(new_char) = non_rng_predecessor(current_char) {
current_char = new_char;
} else {
return None;
}
}
Some(current_char)
}
fn successor<RNG>(&self, _rng: &mut RNG) -> Option<char>
where
RNG: Rng,
{
non_rng_successor(*self)
}
fn predecessor<RNG>(&self, _rng: &mut RNG) -> Option<char>
where
RNG: Rng,
{
non_rng_predecessor(*self)
}
}
/// MISSING DOCS
fn non_rng_successor(char: char) -> Option<char> {
if char == char::MAX {
// we're at the biggest possible value, so we can't go higher
None
} else {
// we're not at the maximum, but we may hit 0xd800
if char == '\u{d7ff}' {
Some('\u{e000}')
} else {
// This is okay as we're checking the `char::MAX` case further above, thus `char` has to be
// some valid value which won't cause an overflow.
#[allow(clippy::arithmetic_side_effects, clippy::integer_arithmetic)]
char::from_u32(u32::from(char) + 1)
}
}
}
/// MISSING DOCS
fn non_rng_predecessor(char: char) -> Option<char> {
if char == '\u{0}' {
// we're at the smallest possible value, so we can't go lower
None
} else {
// we're not at the minimum, but we may hit 0xdfff
if char == '\u{e000}' {
Some('\u{d7ff}')
} else {
// This is okay as we're checking the zero case further above, thus `char` has to be
// some valid value which won't cause an underflow.
#[allow(clippy::arithmetic_side_effects, clippy::integer_arithmetic)]
char::from_u32(u32::from(char) - 1)
}
}
}
// invalid range: '\u{d800}'..='\u{dfff}'