1use std::marker::PhantomData;
74use std::fmt::{self, Display};
75use std::error::Error;
76use std::iter::{Iterator, Filter};
77use std::fs::File;
78use std::io::{self, Read, BufReader, BufRead, Lines};
79use std::path::Path;
80use std::str::FromStr;
81
82pub fn from_file_lines<T>(p: &Path) -> Result<ParseListIterator<T, Filter<Lines<BufReader<File>>, fn(&Result<String, io::Error>) -> bool>>, io::Error>
83where T: FromStr,
84 T::Err: Error + Send + Sync + 'static {
85 let f = File::open(p)?;
86 Ok(from_read_lines(f))
87}
88
89pub fn from_read_lines<T, R>(r: R) -> ParseListIterator<T, Filter<Lines<BufReader<R>>, fn(&Result<String, io::Error>) -> bool>>
90where T: FromStr,
91 T::Err: Error + Send + Sync + 'static,
92 R: Read {
93 let r: BufReader<R> = BufReader::new(r);
94 from_bufread_lines(r)
95}
96
97pub fn from_bufread_lines<T, B>(b: B) -> ParseListIterator<T, Filter<Lines<B>, fn(&Result<String, io::Error>) -> bool>>
98where T: FromStr,
99 T::Err: Error + Send + Sync + 'static,
100 B: BufRead {
101
102 fn nonblank(lr: &Result<String, io::Error>) -> bool {
103 let trimmed = lr.as_ref().map(|l| !l.trim().is_empty());
104 let nonblank = trimmed.unwrap_or(true);
105 nonblank
106 }
107
108 let without_blanks = b.lines().filter(nonblank as fn(&Result<String, io::Error>) -> bool);
109
110 from_iter(without_blanks)
111}
112
113pub fn from_iter<T, I>(i: I) -> ParseListIterator<T, I>
116where T: FromStr,
117 T::Err: Error + Send + Sync + 'static,
118 I: Iterator<Item = Result<String, io::Error>> {
119 ParseListIterator::<T, I>(i, PhantomData)
120}
121
122pub struct ParseListIterator<T, I> (I, PhantomData<T>)
123where T: FromStr,
124 T::Err: Error + Send + Sync + 'static,
125 I: Iterator<Item = Result<String, io::Error>>;
126
127impl<T, I> Iterator for ParseListIterator<T, I>
128where T: FromStr,
129 T::Err: Error + Send + Sync + 'static,
130 I: Iterator<Item = Result<String, io::Error>>
131{
132
133 type Item = Result<T, ParseListError<T::Err>>;
134
135 fn next(&mut self) -> Option<Self::Item> {
136 self.0.next().map(string_result_to_item_result)
137 }
138}
139
140fn string_result_to_item_result<T>(v: Result<String, io::Error>) -> Result<T, ParseListError<T::Err>>
141where T: FromStr,
142 T::Err: Error + Send + Sync + 'static {
143 match v {
144 Ok(v) => {
145 match str::parse(&v) {
146 Ok(v) => Ok(v),
147 Err(e) => Err(ParseListError::Parse(e))
148 }
149 }
150 Err(e) => Err(ParseListError::Io(e))
151 }
152}
153
154#[derive(Debug)]
155pub enum ParseListError<TE>
156where TE: Error + Send + Sync + 'static {
157 Io(io::Error),
158 Parse(TE),
159}
160
161impl<TE> Error for ParseListError<TE>
162where TE: Error + Send + Sync + 'static { }
163
164impl<TE> Display for ParseListError<TE>
165where TE: Error + Send + Sync + 'static {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 match self {
168 ParseListError::Io(e) => Display::fmt(e, f),
169 ParseListError::Parse(e) => Display::fmt(e, f),
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use tempdir::TempDir;
177 use big_s::S;
178 use super::*;
179
180 #[test]
181 fn from_iter_vec() {
182 let a = vec![Ok(S("0")), Ok(S("1")), Ok(S("2"))];
183 let b: Vec<Result<u32, _>> = from_iter(a.into_iter()).collect();
184 let b: Result<Vec<u32>, _> = b.into_iter().collect();
185 let b = b.unwrap();
186 assert!(b == vec![0, 1, 2]);
187 }
188
189 #[test]
191 fn from_iter_vec_fail_middle() {
192 use std::num::ParseIntError;
193 let e: io::Error = io::Error::from(io::ErrorKind::NotFound);
194 let a: Vec<Result<String, io::Error>> = vec![Ok(S("0")), Err(e), Ok(S("2"))];
195 let b: Vec<Result<u32, ParseListError<ParseIntError>>> = from_iter(a.into_iter()).collect();
196 assert!(b.len() == 3);
197 assert!(b[0].as_ref().unwrap() == &0);
198 assert!(b[1].is_err());
199 assert!(b[2].as_ref().unwrap() == &2);
200 }
201
202
203 #[test]
204 fn from_iter_vec_ignore_errors() {
205 let e: io::Error = io::Error::from(io::ErrorKind::NotFound);
206 let a: Vec<Result<String, io::Error>> = vec![Ok(S("0")), Err(e), Ok(S("2"))];
207 let b: Vec<u32> = from_iter(a.into_iter())
208 .filter_map(Result::ok).collect();
209 assert!(b.len() == 2);
210 assert!(b[0] == 0);
211 assert!(b[1] == 2);
212 }
213
214 #[test]
215 fn from_bufread_lines_slice() {
216 let a = "0\n1\n2".as_bytes();
217 let b: Vec<Result<u32, _>> = from_bufread_lines(a).collect();
218 let b: Result<Vec<u32>, _> = b.into_iter().collect();
219 let b = b.unwrap();
220 assert!(b == vec![0, 1, 2]);
221 }
222
223 #[test]
224 fn from_bufread_lines_slice_fail_middle() {
225 let a = "0\nboop\n2".as_bytes();
226 let b: Vec<Result<u32, _>> = from_bufread_lines(a).collect();
227 assert!(b.len() == 3);
228 assert!(b[0].as_ref().unwrap() == &0);
229 assert!(b[1].is_err());
230 assert!(b[2].as_ref().unwrap() == &2);
231 }
232
233 #[test]
234 fn from_bufread_lines_cursor() {
235 use std::io::Cursor;
236 let a = Cursor::new("0\n1\n2".as_bytes());
237 let b: Vec<Result<u32, _>> = from_bufread_lines(a).collect();
238 let b: Result<Vec<u32>, _> = b.into_iter().collect();
239 let b = b.unwrap();
240 assert!(b == vec![0, 1, 2]);
241 }
242
243 #[test]
244 fn from_read_lines_slice() {
245 let a = "0\n1\n2".as_bytes();
246 let b: Vec<Result<u32, _>> = from_read_lines(a).collect();
247 let b: Result<Vec<u32>, _> = b.into_iter().collect();
248 let b = b.unwrap();
249 assert!(b == vec![0, 1, 2]);
250 }
251
252 #[test]
253 fn from_read_lines_cursor() {
254 use std::io::Cursor;
255 let a = Cursor::new("0\n1\n2".as_bytes());
256 let b: Vec<Result<u32, _>> = from_read_lines(a).collect();
257 let b: Result<Vec<u32>, _> = b.into_iter().collect();
258 let b = b.unwrap();
259 assert!(b == vec![0, 1, 2]);
260 }
261
262 #[test]
263 fn from_read_lines_file() {
264 use std::fs;
265 let tmp_dir = TempDir::new("tmp").unwrap();
266 let file_path = tmp_dir.path().join("list");
267 fs::write(&file_path, "0\n1\n2").unwrap();
268 let f = File::open(file_path).unwrap();
269 let b: Vec<Result<u32, _>> = from_read_lines(f).collect();
270 let b: Result<Vec<u32>, _> = b.into_iter().collect();
271 let b = b.unwrap();
272 assert!(b == vec![0, 1, 2]);
273 }
274
275 #[test]
276 fn from_read_lines_file_slice() {
277 use std::fs;
278 let tmp_dir = TempDir::new("tmp").unwrap();
279 let file_path = tmp_dir.path().join("list");
280 fs::write(&file_path, "0\n1\n2").unwrap();
281 let f = File::open(file_path).unwrap();
282 let b: Vec<Result<u32, _>> = from_read_lines(&f).collect();
283 let b: Result<Vec<u32>, _> = b.into_iter().collect();
284 let b = b.unwrap();
285 assert!(b == vec![0, 1, 2]);
286 }
287
288 #[test]
289 fn from_file_lines_success() {
290 use std::fs;
291 let tmp_dir = TempDir::new("tmp").unwrap();
292 let file_path = tmp_dir.path().join("list");
293 fs::write(&file_path, "0\n1\n2\n3\n4").unwrap();
294
295 let v = from_file_lines(&file_path);
296 let v: Vec<Result<u32, _>> = v.unwrap().collect();
297 let v: Result<Vec<u32>, _> = v.into_iter().collect();
298 let v = v.unwrap();
299 assert!(v == vec![0, 1, 2, 3, 4]);
300 }
301
302 #[test]
303 fn from_file_lines_success_min_annotations() {
304 use std::fs;
305 let tmp_dir = TempDir::new("tmp").unwrap();
306 let file_path = tmp_dir.path().join("list");
307 fs::write(&file_path, "0\n1\n2\n3\n4").unwrap();
308
309 let v = from_file_lines(&file_path);
310 let v: Vec<_> = v.unwrap().collect();
311 let v: Result<Vec<u32>, _> = v.into_iter().collect();
312 let v = v.unwrap();
313 assert!(v == vec![0, 1, 2, 3, 4]);
314 }
315
316 #[test]
317 fn from_file_lines_ignore_errors() -> Result<(), io::Error> {
318 use std::fs;
319 let tmp_dir = TempDir::new("tmp").unwrap();
320 let file_path = tmp_dir.path().join("list");
321 fs::write(&file_path, "0\n1\n2\n3\n4").unwrap();
322 let b: Vec<u32> = from_file_lines(&file_path)?
323 .filter_map(Result::ok).collect();
324 assert!(b == vec![0, 1, 2, 3, 4]);
325 Ok(())
326 }
327
328 #[test]
329 fn from_file_lines_not_found() {
330 let tmp_dir = TempDir::new("tmp").unwrap();
331 let file_path = tmp_dir.path().join("list");
332 let b = from_file_lines::<u32>(&file_path);
333 assert!(b.is_err());
334 }
335}
336