use rand::Rng;
use crate::error::{Result, WriteError};
pub const RNG_SEED: u64 = 42;
#[derive(Debug, Clone, Copy, Default)]
pub enum Policy {
#[default]
IgnoreSequence,
BreakOnInvalid,
RandomDraw,
SetToA,
SetToC,
SetToG,
SetToT,
}
impl Policy {
fn fill_with_known(sequence: &[u8], val: u8, ibuf: &mut Vec<u8>) {
for &n in sequence {
ibuf.push(match n {
b'A' | b'C' | b'G' | b'T' => n,
_ => val,
});
}
}
fn fill_with_random<R: Rng>(sequence: &[u8], rng: &mut R, ibuf: &mut Vec<u8>) {
for &n in sequence {
ibuf.push(match n {
b'A' | b'C' | b'G' | b'T' => n,
_ => match rng.random_range(0..4) {
0 => b'A',
1 => b'C',
2 => b'G',
3 => b'T',
_ => unreachable!(),
},
});
}
}
pub fn handle<R: Rng>(&self, sequence: &[u8], ibuf: &mut Vec<u8>, rng: &mut R) -> Result<bool> {
ibuf.clear();
match self {
Self::IgnoreSequence => Ok(false),
Self::BreakOnInvalid => {
let seq_str = std::str::from_utf8(sequence)?.to_string();
Err(WriteError::InvalidNucleotideSequence(seq_str).into())
}
Self::RandomDraw => {
Self::fill_with_random(sequence, rng, ibuf);
Ok(true)
}
Self::SetToA => {
Self::fill_with_known(sequence, b'A', ibuf);
Ok(true)
}
Self::SetToC => {
Self::fill_with_known(sequence, b'C', ibuf);
Ok(true)
}
Self::SetToG => {
Self::fill_with_known(sequence, b'G', ibuf);
Ok(true)
}
Self::SetToT => {
Self::fill_with_known(sequence, b'T', ibuf);
Ok(true)
}
}
}
}