Skip to main content

rosalind/pileup/
source.rs

1//! Read sources feed coordinate-sorted reads into the pileup engine. `SliceSource`
2//! is an in-memory source (used by the Rust API and tests); a BAM-backed source
3//! lands when the calling path is migrated.
4
5use crate::core::{AlignedRead, CoreError};
6
7/// A source of coordinate-sorted aligned reads for the pileup engine.
8///
9/// Implementations MUST yield reads sorted ascending by `(contig, pos)`.
10pub trait ReadSource {
11    /// Return the next read, or `None` when exhausted.
12    fn next_read(&mut self) -> Result<Option<AlignedRead>, CoreError>;
13}
14
15/// An in-memory read source. Sorts the provided reads by `(contig, pos)` on
16/// construction so callers need not pre-sort.
17#[derive(Debug)]
18pub struct SliceSource {
19    reads: std::vec::IntoIter<AlignedRead>,
20}
21
22impl SliceSource {
23    /// Build a source from reads (sorted by `(contig, pos)` here).
24    pub fn new(mut reads: Vec<AlignedRead>) -> Self {
25        reads.sort_by(|a, b| a.contig.cmp(&b.contig).then(a.pos.0.cmp(&b.pos.0)));
26        Self {
27            reads: reads.into_iter(),
28        }
29    }
30}
31
32impl ReadSource for SliceSource {
33    fn next_read(&mut self) -> Result<Option<AlignedRead>, CoreError> {
34        Ok(self.reads.next())
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use crate::core::{CigarOp, CigarOpKind, Position, SamFlags};
42    use std::sync::Arc;
43
44    fn read(contig: u32, pos: u32) -> AlignedRead {
45        AlignedRead {
46            contig,
47            pos: Position(pos),
48            mapq: 60,
49            flags: SamFlags::default(),
50            cigar: vec![CigarOp::new(CigarOpKind::Match, 4)],
51            seq: Arc::from(b"ACGT".to_vec().into_boxed_slice()),
52            qual: Arc::from(vec![30u8; 4].into_boxed_slice()),
53        }
54    }
55
56    #[test]
57    fn slice_source_yields_reads_sorted_by_contig_then_pos() {
58        let mut src = SliceSource::new(vec![read(1, 50), read(0, 200), read(0, 100)]);
59        let mut order = Vec::new();
60        while let Some(r) = src.next_read().unwrap() {
61            order.push((r.contig, r.pos.0));
62        }
63        assert_eq!(order, vec![(0, 100), (0, 200), (1, 50)]);
64    }
65}