use impl_trait_for_tuples::impl_for_tuples;
use rand::distributions::uniform::SampleUniform;
use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign, Sub, SubAssign};
pub trait Allele: Clone + Copy + Send + Sync + std::fmt::Debug {
fn hash_slice(slice: &[Self], hasher: &mut impl Hasher)
where
Self: Sized;
}
#[macro_export]
macro_rules! impl_allele{
($($t:ty),*) => {
$(
impl $crate::allele::Allele for $t {
fn hash_slice(slice: &[Self], hasher: &mut impl ::std::hash::Hasher) {
::std::hash::Hash::hash(slice, hasher);
}
}
)*
}
}
impl_allele!(bool, char, i128, i16, i32, i64, i8, isize, u128, u16, u32, u64, u8, usize);
impl Allele for f32 {
fn hash_slice(slice: &[Self], hasher: &mut impl Hasher) {
let bytes: &[u8] = bytemuck::cast_slice(slice);
bytes.hash(hasher);
}
}
impl Allele for f64 {
fn hash_slice(slice: &[Self], hasher: &mut impl Hasher) {
let bytes: &[u8] = bytemuck::cast_slice(slice);
bytes.hash(hasher);
}
}
#[impl_for_tuples(0, 12)]
impl Allele for Tuple {
for_tuples!( where #( Tuple: Allele + Hash ),* );
fn hash_slice(slice: &[Self], hasher: &mut impl Hasher) {
slice.hash(hasher);
}
}
pub trait RangeAllele:
Allele
+ Add<Output = Self>
+ Sub<Output = Self>
+ AddAssign
+ SubAssign
+ std::cmp::PartialOrd
+ Default
+ bytemuck::NoUninit
+ SampleUniform
{
fn smallest_increment() -> Self;
fn zero() -> Self;
fn one() -> Self;
fn floor(&self) -> Self;
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self;
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self;
fn min(a: Self, b: Self) -> Self {
if a < b { a } else { b }
}
}
impl RangeAllele for f32 {
fn smallest_increment() -> Self {
f32::EPSILON
}
fn zero() -> Self {
0.0
}
fn one() -> Self {
1.0
}
fn floor(&self) -> Self {
f32::floor(*self)
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value + delta;
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value - delta;
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for f64 {
fn smallest_increment() -> Self {
f64::EPSILON
}
fn zero() -> Self {
0.0
}
fn one() -> Self {
1.0
}
fn floor(&self) -> Self {
f64::floor(*self)
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value + delta;
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value - delta;
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for i8 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value.saturating_add(delta);
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value.saturating_sub(delta);
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for i16 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value.saturating_add(delta);
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value.saturating_sub(delta);
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for i32 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value.saturating_add(delta);
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value.saturating_sub(delta);
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for u8 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value.saturating_add(delta);
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value.saturating_sub(delta);
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for u16 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value.saturating_add(delta);
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value.saturating_sub(delta);
if new_value < min_value {
min_value
} else {
new_value
}
}
}
impl RangeAllele for u32 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn clamped_add(current_value: Self, delta: Self, max_value: Self) -> Self {
let new_value = current_value.saturating_add(delta);
if new_value > max_value {
max_value
} else {
new_value
}
}
fn clamped_sub(current_value: Self, delta: Self, min_value: Self) -> Self {
let new_value = current_value.saturating_sub(delta);
if new_value < min_value {
min_value
} else {
new_value
}
}
}