use std::ops::Deref;
use anyhow::Context as _;
use rust_htslib::bcf;
use crate::{common::coords::GenomeRegion, vcf::pipeline::clusterizer::phasing::GtAndPhase};
#[derive(Debug, Clone)]
pub struct InputRecord {
record: bcf::Record,
input_gt: GtAndPhase,
local_gt: Option<GtAndPhase>,
}
impl InputRecord {
pub fn new(record: bcf::Record) -> Self {
let input_gt = GtAndPhase::from_record(&record);
Self {
record,
input_gt,
local_gt: None,
}
}
pub const fn with_gt(record: bcf::Record, input_gt: GtAndPhase) -> Self {
Self {
record,
input_gt,
local_gt: None,
}
}
pub const fn gt(&self) -> GtAndPhase {
match self.local_gt {
Some(gt) => gt,
None => self.input_gt,
}
}
pub const fn input_gt(&self) -> GtAndPhase {
self.input_gt
}
pub fn with_local_gt(&self, local_gt: GtAndPhase) -> Self {
Self {
record: self.record.clone(),
input_gt: self.input_gt,
local_gt: Some(local_gt),
}
}
pub const fn record(&self) -> &bcf::Record {
&self.record
}
pub(super) fn into_record(self) -> bcf::Record {
self.record
}
}
impl Deref for InputRecord {
type Target = bcf::Record;
fn deref(&self) -> &Self::Target {
&self.record
}
}
impl TryFrom<&InputRecord> for GenomeRegion {
type Error = anyhow::Error;
fn try_from(rec: &InputRecord) -> Result<Self, Self::Error> {
Self::try_from(rec.record())
}
}
impl TryFrom<&[InputRecord]> for GenomeRegion {
type Error = anyhow::Error;
fn try_from(recs: &[InputRecord]) -> Result<Self, Self::Error> {
if recs.is_empty() {
anyhow::bail!("empty list of records");
}
let min_pos = recs.iter().map(|r| r.pos()).min().context("not empty")?;
let max_end = recs.iter().map(|r| r.end()).max().context("not empty")?;
let rec = recs.first().context("not empty")?;
let chr = rec
.header()
.rid2name(rec.rid().context("no rid for record.")?)
.context("read error")?;
let gpos =
crate::common::coords::GenomePosition::new_0(chr.into(), usize::try_from(min_pos)?);
Ok(Self::new_bounded(gpos, usize::try_from(max_end - min_pos)?))
}
}