use crate::{
data::{
arbitrary::{ArbitrarySpecs, CigarSpecs, ClampAlignment, NucleotidesSpecs, StringSpecs},
cigar::{Cigar, LenInAlignment},
sam::SamData,
},
prelude::{Len, Nucleotides, QualityScores},
};
use arbitrary::{Arbitrary, Unstructured};
use std::num::NonZeroUsize;
impl<'a> Arbitrary<'a> for SamData {
#[inline]
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(SamData::new(
String::arbitrary(u)?,
u16::arbitrary(u)?,
String::arbitrary(u)?,
usize::arbitrary(u)?,
u8::arbitrary(u)?,
Cigar::arbitrary(u)?,
Nucleotides::arbitrary(u)?,
QualityScores::arbitrary(u)?,
))
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct SamDataSpecs {
pub qname: StringSpecs,
pub rname: StringSpecs,
pub cigar: CigarSpecs,
pub seq: NucleotidesSpecs,
pub nonzero_pos: bool,
pub cap_end_pos: bool,
pub correct_seq_len: bool,
}
impl<'a> ArbitrarySpecs<'a> for SamDataSpecs {
type Output = SamData;
#[inline]
fn make_arbitrary(&self, u: &mut Unstructured<'a>) -> arbitrary::Result<Self::Output> {
let mut cigar = self.cigar.make_arbitrary(u)?;
let mut seq = self.seq.make_arbitrary(u)?;
if self.correct_seq_len {
cigar.clamp_query_len(seq.len());
seq.shorten_to(cigar.query_len_in_alignment());
}
let pos = match (self.nonzero_pos, self.cap_end_pos) {
(false, false) => usize::arbitrary(u)?,
(false, true) => {
if let Some(match_len) = cigar.ref_len_in_alignment_checked() {
u.int_in_range(0..=(usize::MAX - match_len))?
} else {
usize::arbitrary(u)?
}
}
(true, false) => NonZeroUsize::arbitrary(u)?.into(),
(true, true) => {
if let Some(match_len) = cigar.ref_len_in_alignment_checked()
&& match_len < usize::MAX
{
u.int_in_range(1..=(usize::MAX - match_len))?
} else {
NonZeroUsize::arbitrary(u)?.get()
}
}
};
Ok(SamData::new(
self.qname.make_arbitrary(u)?,
u16::arbitrary(u)?,
self.rname.make_arbitrary(u)?,
pos,
u8::arbitrary(u)?,
cigar,
seq,
QualityScores::arbitrary(u)?,
))
}
}