1use std::io::{BufRead, BufReader, Lines, Read};
2
3use crate::{FromTokens, LineCount, ReadLineError, ReadTokensError, Take};
4
5#[cfg(doc)]
6use std::io::Stdin;
7
8#[derive(Debug)]
10pub struct TokenReader<R> {
11 lines: Lines<R>,
12}
13
14impl<R: BufRead> TokenReader<R> {
15 pub fn new(buf_read: R) -> Self {
17 TokenReader {
18 lines: buf_read.lines(),
19 }
20 }
21
22 pub fn line<T>(&mut self) -> Result<T, ReadTokensError<T::Error>>
56 where
57 T: FromTokens,
58 {
59 let line = self.line_raw()?;
60 let tokens = line.split_whitespace();
61
62 T::from_tokens(tokens).map_err(|source| ReadTokensError::ParseError { source, line })
63 }
64
65 pub fn line_raw(&mut self) -> Result<String, ReadLineError> {
83 let line = self.lines.next();
84 let line = line.ok_or_else(|| ReadLineError::EndOfFile)?;
85 let line = line.map_err(|source| ReadLineError::IoError { source })?;
86
87 Ok(line)
88 }
89
90 pub fn take<T>(&mut self, count: usize) -> Take<'_, T, R, usize>
111 where
112 T: FromTokens,
113 {
114 Take::new(self, count)
115 }
116
117 pub fn take_count<T, S>(&mut self, count: S) -> Take<'_, T, R, S>
138 where
139 T: FromTokens,
140 S: LineCount,
141 {
142 Take::new(self, count)
143 }
144}
145
146impl<R: Read> TokenReader<BufReader<R>> {
147 pub fn from_read(read: R) -> Self {
151 TokenReader::new(BufReader::new(read))
152 }
153}
154
155impl<R> From<R> for TokenReader<R>
156where
157 R: BufRead,
158{
159 fn from(value: R) -> Self {
163 TokenReader::new(value)
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use crate::{ReadLineError, ReadTokensError, TokenReader};
170
171 #[test]
172 fn can_be_constructed_from_bufread() {
173 let mut input = TokenReader::new("Hello".as_bytes());
174 assert_eq!(input.line_raw().unwrap(), "Hello");
175 }
176
177 #[test]
178 fn can_be_constructed_from_read() {
179 let mut input = TokenReader::from_read("Hello".as_bytes());
180 assert_eq!(input.line_raw().unwrap(), "Hello");
181 }
182
183 #[test]
184 fn can_be_constructed_with_from() {
185 let mut input: TokenReader<_> = "Hello".as_bytes().into();
186 assert_eq!(input.line_raw().unwrap(), "Hello");
187 }
188
189 #[test]
190 fn reads_raw_lines() {
191 let mut input = TokenReader::new("First\nSecond\n".as_bytes());
192 assert_eq!(input.line_raw().unwrap(), "First");
193 assert_eq!(input.line_raw().unwrap(), "Second");
194 assert!(matches!(input.line_raw(), Err(ReadLineError::EndOfFile)));
195 }
196
197 #[test]
198 fn reads_single_value() {
199 let mut input = TokenReader::new("13".as_bytes());
200 let value: Vec<i8> = input.line().unwrap();
201 assert_eq!(value, vec![13]);
202 }
203
204 #[test]
205 fn reads_multiple_values() {
206 let mut input = TokenReader::new("40 50 60".as_bytes());
207 let value: Vec<i8> = input.line().unwrap();
208 assert_eq!(value, vec![40, 50, 60]);
209 }
210
211 #[test]
212 fn reads_empty_values() {
213 let mut input = TokenReader::new(" ".as_bytes());
214 let value: Vec<i8> = input.line().unwrap();
215 assert_eq!(value, vec![]);
216 }
217
218 #[test]
219 fn ignores_multiple_whitespace_characters() {
220 let mut input = TokenReader::new("1\t\r \t 7".as_bytes());
221 let value: Vec<i8> = input.line().unwrap();
222 assert_eq!(value, vec![1, 7]);
223 }
224
225 #[test]
226 fn ignores_start_and_end() {
227 let mut input = TokenReader::new(" \t123 \r".as_bytes());
228 let value: Vec<i8> = input.line().unwrap();
229 assert_eq!(value, vec![123]);
230 }
231
232 #[test]
233 fn returns_end_of_file() {
234 let mut input = TokenReader::new("5\n".as_bytes());
235
236 let _ = input.line::<Vec<i8>>().unwrap();
237 let result = input.line::<Vec<i8>>();
238
239 assert!(matches!(result, Err(ReadTokensError::EndOfFile)));
240 }
241
242 #[test]
243 fn returns_parse_error() {
244 let mut input = TokenReader::new("one\n".as_bytes());
245
246 let result = input.line::<Vec<i8>>();
247
248 match result {
249 Err(ReadTokensError::ParseError { source: _, line }) => {
250 assert_eq!(line, "one");
251 }
252 _ => panic!("expected error, got {result:?}"),
253 }
254 }
255
256 #[test]
257 fn take_gets_multiple_lines() {
258 let mut input = TokenReader::new("0\n1\n2\nx".as_bytes());
259
260 for (i, value) in input.take(3).enumerate() {
261 let (value,): (usize,) = value.unwrap();
262 assert_eq!(value, i);
263 }
264 }
265
266 #[test]
267 fn take_count_gets_multiple_lines() {
268 let mut input = TokenReader::new("0\n1\n2\nx".as_bytes());
269
270 for (i, value) in input.take_count(3u64).enumerate() {
271 let (value,): (usize,) = value.unwrap();
272 assert_eq!(value, i);
273 }
274 }
275}