use impl_trait_for_tuples::impl_for_tuples;
use rand::distributions::uniform::SampleUniform;
use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign, Sub};
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
+ Into<f64>
+ std::cmp::PartialOrd
+ Default
+ bytemuck::NoUninit
+ SampleUniform
{
fn smallest_increment() -> Self;
fn zero() -> Self;
fn one() -> Self;
fn floor(&self) -> Self;
fn scale_by_fraction(&self, fraction: f64) -> Self;
fn clamp(test_value: Self, min_value: Self, max_value: Self) -> Self {
if test_value < min_value {
min_value
} else if test_value > max_value {
max_value
} else {
test_value
}
}
}
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 scale_by_fraction(&self, fraction: f64) -> Self {
self * fraction as f32
}
}
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 scale_by_fraction(&self, fraction: f64) -> Self {
self * fraction
}
}
impl RangeAllele for i8 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn scale_by_fraction(&self, fraction: f64) -> Self {
(*self as f64 * fraction).round() as i8
}
}
impl RangeAllele for i16 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn scale_by_fraction(&self, fraction: f64) -> Self {
(*self as f64 * fraction).round() as i16
}
}
impl RangeAllele for i32 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn scale_by_fraction(&self, fraction: f64) -> Self {
(*self as f64 * fraction).round() as i32
}
}
impl RangeAllele for u8 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn scale_by_fraction(&self, fraction: f64) -> Self {
(*self as f64 * fraction).round() as u8
}
}
impl RangeAllele for u16 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn scale_by_fraction(&self, fraction: f64) -> Self {
(*self as f64 * fraction).round() as u16
}
}
impl RangeAllele for u32 {
fn smallest_increment() -> Self {
1
}
fn zero() -> Self {
0
}
fn one() -> Self {
1
}
fn floor(&self) -> Self {
*self
}
fn scale_by_fraction(&self, fraction: f64) -> Self {
(*self as f64 * fraction).round() as u32
}
}