Skip to main content

sweet_potator/recipe/
reader.rs

1use std::{
2    io::{self, BufRead},
3    ops::Not,
4};
5
6pub(super) struct Reader<R> {
7    lines: io::Lines<io::BufReader<R>>,
8    should_trim: bool,
9}
10
11impl<R: io::Read> Reader<R> {
12    pub fn new(reader: R, should_trim: bool) -> Self {
13        let lines = io::BufReader::new(reader).lines();
14        Self { lines, should_trim }
15    }
16
17    pub fn next_block(&mut self) -> io::Result<Option<Vec<String>>> {
18        let trim = |s: &str| (if self.should_trim { s.trim() } else { s }).to_string();
19        let block: Vec<_> = self
20            .lines
21            .by_ref()
22            .map(|line| Ok(trim(&line?)))
23            .skip_while(|res| matches!(res, Ok(line) if line.is_empty()))
24            .take_while(|res| matches!(res, Ok(line) if !line.is_empty()))
25            .collect::<io::Result<_>>()?;
26        Ok(block.is_empty().not().then_some(block))
27    }
28}
29
30#[cfg(test)]
31mod tests {
32
33    use super::*;
34
35    #[test]
36    fn test_normal() {
37        let text = [
38            "",
39            "",
40            "block 1, line 1",
41            "block 1, line 2",
42            " ",
43            "",
44            "",
45            " ",
46            "",
47            "block 2, line 1",
48            "",
49            "",
50        ]
51        .join("\n");
52        let mut reader = Reader::new(io::Cursor::new(text), false);
53        assert_eq!(
54            reader.next_block().unwrap().unwrap(),
55            vec!["block 1, line 1", "block 1, line 2", " "]
56        );
57        assert_eq!(reader.next_block().unwrap().unwrap(), vec![" "]);
58        assert_eq!(
59            reader.next_block().unwrap().unwrap(),
60            vec!["block 2, line 1"]
61        );
62        assert_eq!(reader.next_block().unwrap(), None);
63    }
64
65    #[test]
66    fn test_trimmed() {
67        let text = [" ", "block", " ", "", " ", ""].join("\n");
68        let mut reader = Reader::new(io::Cursor::new(text), true);
69        assert_eq!(reader.next_block().unwrap().unwrap(), vec!["block"]);
70        assert_eq!(reader.next_block().unwrap(), None);
71    }
72}