use crate::alignment::phmm::{PhmmError, PhmmNumber};
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum PhmmState {
Match = 0,
Delete = 1,
Insert = 2,
}
impl PhmmState {
pub const VARIANTS: [Self; 3] = [Self::Match, Self::Delete, Self::Insert];
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum PhmmStateOrEnter {
Match = 0,
Delete = 1,
Insert = 2,
Enter = 3,
}
impl PhmmStateOrEnter {
pub const VARIANTS: [Self; 4] = [Self::Match, Self::Delete, Self::Insert, Self::Enter];
}
impl From<PhmmState> for u8 {
#[inline]
fn from(value: PhmmState) -> Self {
value as u8
}
}
impl From<PhmmStateOrEnter> for u8 {
#[inline]
fn from(value: PhmmStateOrEnter) -> Self {
value as u8
}
}
impl From<PhmmState> for usize {
#[inline]
fn from(value: PhmmState) -> Self {
value as usize
}
}
impl From<PhmmStateOrEnter> for usize {
#[inline]
fn from(value: PhmmStateOrEnter) -> Self {
value as usize
}
}
impl From<PhmmState> for PhmmStateOrEnter {
#[inline]
fn from(value: PhmmState) -> Self {
match value {
PhmmState::Match => PhmmStateOrEnter::Match,
PhmmState::Delete => PhmmStateOrEnter::Delete,
PhmmState::Insert => PhmmStateOrEnter::Insert,
}
}
}
impl PhmmState {
#[inline]
#[must_use]
pub(crate) fn get_from(value: PhmmStateOrEnter) -> Option<PhmmState> {
match value {
PhmmStateOrEnter::Match => Some(PhmmState::Match),
PhmmStateOrEnter::Delete => Some(PhmmState::Delete),
PhmmStateOrEnter::Insert => Some(PhmmState::Insert),
PhmmStateOrEnter::Enter => None,
}
}
#[inline]
#[allow(dead_code)]
pub(crate) fn from_op(op: u8) -> Result<Self, PhmmError> {
match op {
b'M' | b'=' | b'X' => Ok(PhmmState::Match),
b'D' => Ok(PhmmState::Delete),
b'I' => Ok(PhmmState::Insert),
op => Err(PhmmError::InvalidCigarOp(op)),
}
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub(crate) struct PhmmTracebackState(u8);
impl PhmmTracebackState {
#[inline]
pub fn is_match(self) -> bool {
self.0 == 0
}
#[inline]
pub fn is_delete(self) -> bool {
self.0 == 1
}
#[inline]
#[allow(dead_code)]
pub fn is_insert(self) -> bool {
self.0 == 2
}
#[inline]
pub fn is_enter(self) -> bool {
self.0 == 3
}
}
impl From<PhmmState> for PhmmTracebackState {
#[inline]
fn from(value: PhmmState) -> Self {
PhmmTracebackState(value as u8)
}
}
impl From<PhmmStateOrEnter> for PhmmTracebackState {
#[inline]
fn from(value: PhmmStateOrEnter) -> Self {
PhmmTracebackState(value as u8)
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub(crate) struct PhmmBacktrackFlags(u8);
impl PhmmBacktrackFlags {
pub fn new() -> Self {
Self(0)
}
#[inline]
#[allow(clippy::verbose_bit_mask)]
pub fn set_match(&mut self, prev_state: impl Into<PhmmTracebackState>) {
let prev_state = prev_state.into();
debug_assert!(prev_state.0 < 4);
debug_assert_eq!(self.0 & 0b00_00_00_11, 0);
self.0 |= prev_state.0;
}
#[inline]
pub fn set_delete(&mut self, prev_state: impl Into<PhmmTracebackState>) {
let prev_state = prev_state.into();
debug_assert!(prev_state.0 < 4);
debug_assert_eq!(self.0 & 0b00_00_11_00, 0);
self.0 |= prev_state.0.wrapping_shl(2);
}
#[inline]
pub fn set_insert(&mut self, prev_state: impl Into<PhmmTracebackState>) {
let prev_state = prev_state.into();
debug_assert!(prev_state.0 < 4);
debug_assert_eq!(self.0 & 0b00_11_00_00, 0);
self.0 |= prev_state.0.wrapping_shl(4);
}
#[inline]
#[must_use]
pub fn get_prev_state(self, current_state: impl Into<PhmmTracebackState>) -> PhmmTracebackState {
let current_state = current_state.into();
debug_assert!(current_state.0 < 4);
let shift = current_state.0.wrapping_mul(2);
let mask = 1u8.wrapping_shl(u32::from(shift)).wrapping_mul(3);
PhmmTracebackState((self.0 & mask) >> shift)
}
}
pub(crate) fn best_state<T: PhmmNumber>(match_val: T, delete_val: T, insert_val: T) -> (PhmmState, T) {
use PhmmState::*;
let mut argmin = Match;
let mut min = match_val;
for (state, val) in [(Delete, delete_val), (Insert, insert_val)] {
if val < min {
argmin = state;
min = val;
}
}
(argmin, min)
}
pub(crate) fn best_state_or_enter<T: PhmmNumber>(
match_val: T, delete_val: T, insert_val: T, enter_val: T,
) -> (PhmmStateOrEnter, T) {
use PhmmStateOrEnter::*;
let mut argmin = Match;
let mut min = match_val;
for (state, val) in [(Delete, delete_val), (Insert, insert_val), (Enter, enter_val)] {
if val < min {
argmin = state;
min = val;
}
}
(argmin, min)
}