use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display};
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub enum AlleleHash {
Crc32(u32),
String(String),
Missing,
}
impl AlleleHash {
pub fn is_missing(&self) -> bool {
matches!(self, AlleleHash::Missing)
}
pub fn as_crc32(&self) -> Option<u32> {
match self {
AlleleHash::Crc32(val) => Some(*val),
_ => None,
}
}
pub fn as_string(&self) -> Option<&str> {
match self {
AlleleHash::String(s) => Some(s),
_ => None,
}
}
pub fn from_crc32(val: u32) -> Self {
if val == u32::MAX {
AlleleHash::Missing
} else {
AlleleHash::Crc32(val)
}
}
pub fn from_string(val: String, missing_marker: &str) -> Self {
if val == missing_marker {
AlleleHash::Missing
} else {
AlleleHash::String(val)
}
}
}
impl Display for AlleleHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AlleleHash::Crc32(val) => write!(f, "{val}"),
AlleleHash::String(s) => write!(f, "{s}"),
AlleleHash::Missing => write!(f, "MISSING"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AlleleHashPair {
pub hash1: AlleleHash,
pub hash2: AlleleHash,
}
impl AlleleHashPair {
pub fn new(hash1: AlleleHash, hash2: AlleleHash) -> Self {
if hash1 <= hash2 {
Self { hash1, hash2 }
} else {
Self {
hash1: hash2,
hash2: hash1,
}
}
}
pub fn has_missing(&self) -> bool {
self.hash1.is_missing() || self.hash2.is_missing()
}
pub fn to_crc_pair(&self) -> Option<(u32, u32)> {
match (&self.hash1, &self.hash2) {
(AlleleHash::Crc32(c1), AlleleHash::Crc32(c2)) => Some((*c1, *c2)),
_ => None,
}
}
}
pub trait AlleleHasher: Send + Sync + Debug {
fn hash_sequence(&self, sequence: &str) -> AlleleHash;
fn parse_allele(&self, allele_str: &str, missing_char: &str) -> Result<AlleleHash, String>;
fn name(&self) -> &'static str;
fn description(&self) -> &'static str;
fn make_pair(&self, hash1: AlleleHash, hash2: AlleleHash) -> AlleleHashPair {
AlleleHashPair::new(hash1, hash2)
}
fn validate_sequence(&self, _sequence: &str) -> Result<(), String> {
Ok(())
}
fn missing_allele(&self) -> AlleleHash {
AlleleHash::Missing
}
}