rosalind/pileup/
source.rs1use crate::core::{AlignedRead, CoreError};
6
7pub trait ReadSource {
11 fn next_read(&mut self) -> Result<Option<AlignedRead>, CoreError>;
13}
14
15#[derive(Debug)]
18pub struct SliceSource {
19 reads: std::vec::IntoIter<AlignedRead>,
20}
21
22impl SliceSource {
23 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}