1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
//! A reader of [LCOV records].
//!
//! The [`Reader`] structure reads LCOV records from arbitrary buffered reader.
//!
//! If you want to create a reader which reads am LCOV tracefile, you can use [`open_file`] function.
//!
//! [LCOV records]: ../enum.Record.html
//! [`Reader`]: struct.Reader.html
//! [`open_file`]: ../fn.open_file.html
use super::record::{ParseRecordError, Record};
use std::fs::File;
use std::io::{self, BufRead, BufReader, Lines};
use std::path::Path;
/// Reading an LCOV records from a buffered reader.
#[derive(Debug)]
pub struct Reader<B> {
lines: Lines<B>,
line: u32,
}
impl<B> Reader<B> {
/// Creates a new `Reader`.
///
/// # Examples
///
/// ```rust
/// use std::io::BufReader;
/// use std::fs::File;
/// use lcov::Reader;
///
/// # fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// let input = "\
/// TN:test_name
/// SF:/path/to/source/file.rs
/// DA:1,2
/// DA:3,0
/// DA:5,6
/// LF:3
/// LH:2
/// end_of_record
/// ";
///
/// let reader = Reader::new(input.as_bytes());
/// # Ok(())
/// # }
/// # fn main() {}
/// ```
pub fn new(buf: B) -> Self
where
B: BufRead,
{
Reader {
lines: buf.lines(),
line: 0,
}
}
}
impl Reader<BufReader<File>> {
/// Opens an LCOV tracefile.
///
/// # Example
///
/// ```rust
/// use lcov::Reader;
/// #
/// # fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// let reader = Reader::open_file("report.info")?;
/// # Ok(())
/// # }
/// # fn main() {}
/// ```
pub fn open_file<P>(path: P) -> Result<Self, io::Error>
where
P: AsRef<Path>,
{
Ok(Reader::new(BufReader::new(File::open(path)?)))
}
}
/// All possible errors that can occur when reading LCOV tracefile.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// An error indicating that I/O operation failed.
///
/// This error occurs when the underlying reader returns an error.
#[error("{}", _0)]
Io(#[from] io::Error),
/// An error indicating that record parsing failed.
///
/// # Examples
///
/// ```rust
/// # use matches::assert_matches;
/// # fn main() {
/// use lcov::Reader;
/// use lcov::reader::Error as ReadError;
/// use lcov::record::ParseRecordError;
/// let mut reader = Reader::new("FOO:1,2".as_bytes());
/// assert_matches!(reader.next(), Some(Err(ReadError::ParseRecord(1, ParseRecordError::UnknownRecord))));
/// # }
/// ```
#[error("invalid record syntax at line {}: {}", _0, _1)]
ParseRecord(u32, #[source] ParseRecordError),
}
impl<B> Iterator for Reader<B>
where
B: BufRead,
{
type Item = Result<Record, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.lines.next().map(|line| {
line.map_err(Error::Io).and_then(|line| {
self.line += 1;
line.parse().map_err(|e| Error::ParseRecord(self.line, e))
})
})
}
}