use std::fs::File;
use std::io::Read;
use std::path::Path;
#[derive(Debug)]
pub struct Input(String);
impl Input {
pub fn new(input: String) -> Self {
Self(input)
}
pub fn from_file(path: impl AsRef<Path>) -> std::io::Result<Self> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(Self(contents))
}
pub fn raw(&self) -> &str {
&self.0
}
pub fn lines(&self) -> std::str::Lines<'_> {
self.0.lines()
}
pub fn traverse<T, E>(
&self,
f: impl FnMut(&str) -> Result<T, E>,
) -> Result<impl Iterator<Item = T>, E> {
Ok(self
.lines()
.map(f)
.collect::<Result<Vec<_>, _>>()?
.into_iter())
}
}
impl From<&str> for Input {
fn from(value: &str) -> Self {
Self::new(value.to_owned())
}
}
impl From<String> for Input {
fn from(value: String) -> Self {
Self::new(value)
}
}
#[cfg(test)]
mod tests {
use indoc::indoc;
use pretty_assertions::assert_eq;
use super::*;
#[test]
pub fn test_traverse_with_oks() {
let input = Input::from(indoc! {"
1
2
3
4
5
"});
assert_eq!(
input
.traverse(|line| line.parse::<usize>())
.map(|iter| iter.sum::<usize>()),
Ok(1 + 2 + 3 + 4 + 5)
);
}
#[test]
pub fn test_traverse_with_errs() {
let input = Input::from(indoc! {"
1
2
oops
4
5
"});
assert_eq!(
input
.traverse(|line| line.parse::<usize>())
.map(|iter| iter.sum::<usize>())
.is_err(),
true
);
}
}