noodles_cram/io/reader/
records.rs

1use std::{
2    io::{self, Read},
3    vec,
4};
5
6use noodles_sam as sam;
7
8use super::{Container, Reader};
9
10/// An iterator over records of a CRAM reader.
11///
12/// This is created by calling [`Reader::records`].
13pub struct Records<'a, R>
14where
15    R: Read,
16{
17    reader: &'a mut Reader<R>,
18    header: &'a sam::Header,
19    container: Container,
20    records: vec::IntoIter<sam::alignment::RecordBuf>,
21}
22
23impl<'a, R> Records<'a, R>
24where
25    R: Read,
26{
27    pub(crate) fn new(reader: &'a mut Reader<R>, header: &'a sam::Header) -> Self {
28        Self {
29            reader,
30            header,
31            container: Container::default(),
32            records: Vec::new().into_iter(),
33        }
34    }
35
36    fn read_container_records(&mut self) -> io::Result<bool> {
37        if self.reader.read_container(&mut self.container)? == 0 {
38            return Ok(true);
39        }
40
41        let compression_header = self.container.compression_header()?;
42
43        self.records = self
44            .container
45            .slices()
46            .map(|result| {
47                let slice = result?;
48
49                let (core_data_src, external_data_srcs) = slice.decode_blocks()?;
50
51                slice
52                    .records(
53                        self.reader.reference_sequence_repository.clone(),
54                        self.header,
55                        &compression_header,
56                        &core_data_src,
57                        &external_data_srcs,
58                    )
59                    .and_then(|records| {
60                        records
61                            .into_iter()
62                            .map(|record| {
63                                sam::alignment::RecordBuf::try_from_alignment_record(
64                                    self.header,
65                                    &record,
66                                )
67                            })
68                            .collect::<io::Result<Vec<_>>>()
69                    })
70            })
71            .collect::<Result<Vec<_>, _>>()?
72            .into_iter()
73            .flatten()
74            .collect::<Vec<_>>()
75            .into_iter();
76
77        Ok(false)
78    }
79}
80
81impl<R> Iterator for Records<'_, R>
82where
83    R: Read,
84{
85    type Item = io::Result<sam::alignment::RecordBuf>;
86
87    fn next(&mut self) -> Option<Self::Item> {
88        loop {
89            match self.records.next() {
90                Some(r) => return Some(Ok(r)),
91                None => match self.read_container_records() {
92                    Ok(true) => return None,
93                    Ok(false) => {}
94                    Err(e) => return Some(Err(e)),
95                },
96            }
97        }
98    }
99}