radiant/loader/
header.rs

1use super::{LoadError, LoadResult, ReadExt};
2use std::io::BufRead;
3
4const EOL: u8 = 0xA;
5
6pub(crate) fn parse_header<R: BufRead>(mut reader: R) -> LoadResult<(usize, usize, R)> {
7    // Skip first paragraph
8    loop {
9        let mut next_is_eol = || reader.read_byte().map(|b| b == EOL);
10        if next_is_eol()? && next_is_eol()? {
11            break;
12        }
13    }
14
15    DimParser::new(reader)?.parse()
16}
17
18struct DimParser<R> {
19    reader: R,
20    byte: u8,
21}
22
23impl<R: BufRead> DimParser<R> {
24    fn new(mut reader: R) -> LoadResult<Self> {
25        let byte = reader.read_byte()?;
26        Ok(Self { reader, byte })
27    }
28
29    fn parse(mut self) -> LoadResult<(usize, usize, R)> {
30        self.eat_spaces()?;
31        let y = self.expect_y()?;
32        self.expect_spaces()?;
33        let x = self.expect_x()?;
34        self.eat_spaces()?;
35        self.expect_eol()?;
36        Ok((x, y, self.reader))
37    }
38
39    fn eat_spaces(&mut self) -> LoadResult<bool> {
40        let mut ate_any = false;
41        while self.byte == b' ' {
42            ate_any = true;
43            self.eat()?;
44        }
45        Ok(ate_any)
46    }
47
48    fn expect_spaces(&mut self) -> LoadResult {
49        match self.eat_spaces()? {
50            true => Ok(()),
51            false => Err(LoadError::Header),
52        }
53    }
54
55    fn eat(&mut self) -> LoadResult<u8> {
56        self.byte = self.reader.read_byte()?;
57        Ok(self.byte)
58    }
59
60    fn expect<B: AsRef<[u8]>>(&mut self, bytes: B) -> LoadResult {
61        for &byte in bytes.as_ref() {
62            if self.byte == byte {
63                self.eat()?;
64            } else {
65                return Err(LoadError::Header);
66            }
67        }
68        Ok(())
69    }
70
71    fn expect_y(&mut self) -> LoadResult<usize> {
72        self.expect(b"-Y")?;
73        self.expect_spaces()?;
74        self.expect_usize()
75    }
76
77    fn expect_x(&mut self) -> LoadResult<usize> {
78        self.expect(b"+X")?;
79        self.expect_spaces()?;
80        self.expect_usize()
81    }
82
83    fn expect_usize(&mut self) -> LoadResult<usize> {
84        let mut value: usize = 0;
85        if !self.byte.is_ascii_digit() {
86            return Err(LoadError::Header);
87        }
88        loop {
89            value = value
90                .checked_mul(10)
91                .ok_or(LoadError::Header)?
92                .checked_add((self.byte - b'0') as usize)
93                .ok_or(LoadError::Header)?;
94            if !self.eat()?.is_ascii_digit() {
95                return Ok(value);
96            }
97        }
98    }
99
100    fn expect_eol(&mut self) -> LoadResult {
101        match self.byte {
102            EOL => Ok(()),
103            _ => Err(LoadError::Header),
104        }
105    }
106}