nanocov 0.1.0

Rust Coverage Calculator and QC Plot Generation Tool
Documentation
// src/io/mod.rs
// IO module for nanocov: BAM/BED reading, coverage writing

pub mod async_io;
pub mod statistics;

use crate::utils::ReadStats;

use crate::cli::Cli;

#[derive(Debug, Clone, Copy)]
pub struct CoverageSummary {
    pub total_coverage: u64,
    pub analyzed_bases: u64,
}

impl CoverageSummary {
    pub fn mean_coverage(self) -> f64 {
        if self.analyzed_bases > 0 {
            self.total_coverage as f64 / self.analyzed_bases as f64
        } else {
            0.0
        }
    }
}

/// Calculate the reference span from a CIGAR string
/// This properly handles different CIGAR operations to get the actual alignment length on the reference
fn calculate_reference_span(cigar: &noodles_bam::record::Cigar) -> u32 {
    cigar
        .iter()
        .filter_map(|op_result| {
            if let Ok(op) = op_result {
                use noodles_sam::alignment::record::cigar::op::Kind;
                match op.kind() {
                    // Operations that consume reference sequence
                    Kind::Match
                    | Kind::Deletion
                    | Kind::Skip
                    | Kind::SequenceMatch
                    | Kind::SequenceMismatch => Some(op.len() as u32),
                    // Operations that don't consume reference: Insertion, SoftClip, HardClip, Pad
                    Kind::Insertion | Kind::SoftClip | Kind::HardClip | Kind::Pad => None,
                }
            } else {
                None // Skip invalid CIGAR operations
            }
        })
        .sum()
}

/// Async version of run_coverage that uses the async pipeline
pub async fn run_coverage_async(
    cli: &Cli,
    read_stats: Option<ReadStats>,
) -> Result<CoverageSummary, Box<dyn std::error::Error>> {
    // Use the async pipeline implementation and map the error type
    async_io::run_coverage_async_pipeline(cli, read_stats)
        .await
        .map_err(|e| e as Box<dyn std::error::Error>)
}