noodles_bcf/io/reader/header/
vcf_header.rs

1//! BCF header VCF header reader.
2
3use std::io::{self, BufRead, BufReader, Read, Take};
4
5/// A BCF header VCF header reader.
6pub struct Reader<R> {
7    inner: BufReader<Take<R>>,
8    is_eol: bool,
9}
10
11impl<R> Reader<R>
12where
13    R: Read,
14{
15    pub(super) fn new(inner: R, len: u64) -> Self {
16        Self {
17            inner: BufReader::new(inner.take(len)),
18            is_eol: true,
19        }
20    }
21
22    /// Discards all input until EOF.
23    pub fn discard_to_end(&mut self) -> io::Result<usize> {
24        let mut n = 0;
25
26        loop {
27            let src = self.inner.fill_buf()?;
28
29            if src.is_empty() {
30                return Ok(n);
31            }
32
33            let len = src.len();
34
35            self.inner.consume(len);
36
37            n += len;
38        }
39    }
40}
41
42impl<R> Read for Reader<R>
43where
44    R: Read,
45{
46    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
47        let mut src = self.fill_buf()?;
48        let amt = src.read(buf)?;
49
50        if !src.is_empty() {
51            self.is_eol = false;
52        }
53
54        self.consume(amt);
55
56        Ok(amt)
57    }
58}
59
60impl<R> BufRead for Reader<R>
61where
62    R: Read,
63{
64    fn fill_buf(&mut self) -> io::Result<&[u8]> {
65        use memchr::memchr;
66
67        const NUL: u8 = 0x00;
68        const LINE_FEED: u8 = b'\n';
69
70        let src = self.inner.fill_buf()?;
71
72        let buf = if self.is_eol && src.first().map(|&b| b == NUL).unwrap_or(true) {
73            &[]
74        } else if let Some(i) = memchr(LINE_FEED, src) {
75            self.is_eol = true;
76            &src[..=i]
77        } else {
78            self.is_eol = false;
79            src
80        };
81
82        Ok(buf)
83    }
84
85    fn consume(&mut self, amt: usize) {
86        self.inner.consume(amt);
87    }
88}