From d91165207f12dfb5b64fab80a9fe2e2bc82670b2 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 14 Dec 2020 18:08:16 +0100 Subject: [PATCH] 2020: switch to anyhow --- Cargo.lock | 3 +++ aoc/Cargo.toml | 1 + aoc/src/lib.rs | 14 +++------- aoc2020/src/day01.rs | 12 ++++----- aoc2020/src/day02.rs | 18 ++++++------- aoc2020/src/day03.rs | 12 +++++---- aoc2020/src/day04.rs | 14 +++++----- aoc2020/src/day05.rs | 26 +++++++++---------- aoc2020/src/day06.rs | 10 +++++--- aoc2020/src/day07.rs | 20 +++++++-------- aoc2020/src/day08.rs | 26 +++++++++---------- aoc2020/src/day09.rs | 26 +++++++++---------- aoc2020/src/day10.rs | 26 ++++++++----------- aoc2020/src/day11.rs | 16 ++++++------ aoc2020/src/day12.rs | 24 ++++++++--------- aoc2020/src/day13.rs | 28 ++++++++++---------- aoc2020/src/day14.rs | 61 ++++++++++++++++++-------------------------- aoc2020/src/main.rs | 3 ++- 18 files changed, 161 insertions(+), 179 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4181c25..e8b1e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,6 +9,9 @@ checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" [[package]] name = "aoc" version = "0.1.0" +dependencies = [ + "anyhow", +] [[package]] name = "aoc2015" diff --git a/aoc/Cargo.toml b/aoc/Cargo.toml index 7a169c1..5387799 100644 --- a/aoc/Cargo.toml +++ b/aoc/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0" diff --git a/aoc/src/lib.rs b/aoc/src/lib.rs index beab3ae..e5ac9c9 100644 --- a/aoc/src/lib.rs +++ b/aoc/src/lib.rs @@ -1,12 +1,6 @@ use std::env; -pub type Error = Box; -pub type Result = std::result::Result; - -#[macro_export] -macro_rules! err { - ($($string:expr),+) => (Box::::from(format!($($string),+))) -} +use anyhow::{Context, Result}; pub type DayFunc = fn() -> Result; @@ -16,15 +10,15 @@ pub fn run(days: &[DayFunc]) -> Result<()> { match args.next() { Some(arg) => { - let day: usize = arg.parse().expect("Please provide a day number"); - let res = days[day - 1]().map_err(|e| err!("error running day specified: {}", e))?; + let day: usize = arg.parse().context("couldn't parse day number")?; + let res = days[day - 1]().context("error running day specified")?; println!("{}", res); } None => { for (i, day) in days.iter().enumerate() { let i = i + 1; println!("day{}: ", i); - let res = day().map_err(|e| err!("error running day {}: {}", i, e))?; + let res = day().with_context(|| format!("error running day {}", i))?; println!("{}", res); } } diff --git a/aoc2020/src/day01.rs b/aoc2020/src/day01.rs index 2ce70d1..cd5220f 100644 --- a/aoc2020/src/day01.rs +++ b/aoc2020/src/day01.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::fmt::Write; -use aoc::{err, Result}; +use anyhow::{anyhow, Result}; const INPUT: &str = include_str!("../input/day01.txt"); @@ -17,7 +17,7 @@ pub fn run() -> Result { fn part1(input: &str) -> Result { let entries = input .lines() - .map(|line| line.parse::().map_err(|e| err!("{}", e))) + .map(|line| line.parse::().map_err(anyhow::Error::new)) .collect::>>()?; let (a, b) = find_2020_2_sum(&entries)?; @@ -28,8 +28,8 @@ fn part1(input: &str) -> Result { fn part2(input: &str) -> Result { let entries = input .lines() - .map(|line| line.parse::().map_err(|e| err!("{}", e))) - .collect::>>()?; + .map(|line| line.parse::().map_err(anyhow::Error::new)) + .collect::>>()?; let (a, b, c) = find_2020_3_sum(&entries)?; @@ -47,7 +47,7 @@ fn find_2020_2_sum(entries: &[i64]) -> Result<(i64, i64)> { } } - Err(err!("couldn't find 2 elements that sum to 2020")) + Err(anyhow!("couldn't find 2 elements that sum to 2020")) } fn find_2020_3_sum(entries: &[i64]) -> Result<(i64, i64, i64)> { @@ -70,7 +70,7 @@ fn find_2020_3_sum(entries: &[i64]) -> Result<(i64, i64, i64)> { } } - Err(err!("couldn't find 2 elements that sum to 2020")) + Err(anyhow!("couldn't find 2 elements that sum to 2020")) } #[cfg(test)] diff --git a/aoc2020/src/day02.rs b/aoc2020/src/day02.rs index 47b1f51..66696f5 100644 --- a/aoc2020/src/day02.rs +++ b/aoc2020/src/day02.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use std::str::FromStr; -use aoc::{err, Result}; +use anyhow::{Context, Result}; const INPUT: &str = include_str!("../input/day02.txt"); @@ -44,28 +44,28 @@ impl PassPolicy { } impl FromStr for PassPolicy { - type Err = aoc::Error; + type Err = anyhow::Error; fn from_str(s: &str) -> Result { let s = s.trim_end(); let space = s .find(' ') - .ok_or_else(|| err!("couldn't parse password policy: didn't find space"))?; + .context("couldn't parse password policy: didn't find space")?; let dash = s .find('-') - .ok_or_else(|| err!("couldn't parse password policy: didn't find dash"))?; + .context("couldn't parse password policy: didn't find dash")?; let min_bound = s[..dash] .parse::() - .map_err(|e| err!("couldn't parse range: {}", e))?; + .context("couldn't parse range")?; let max_bound = s[(dash + 1)..space] .parse::() - .map_err(|e| err!("couldn't parse range: {}", e))?; + .context("couldn't parse range")?; let colon = s .find(':') - .ok_or_else(|| err!("couldn't parse password policy: didn't find colon"))?; + .context("couldn't parse password policy: didn't find colon")?; let letter = s.as_bytes()[colon - 1]; @@ -92,7 +92,7 @@ pub fn run() -> Result { fn part1(input: &str) -> Result { let policies = input .lines() - .map(|line| line.parse::().map_err(|e| err!("{}", e))) + .map(|line| line.parse::()) .collect::>>()?; Ok(policies @@ -104,7 +104,7 @@ fn part1(input: &str) -> Result { fn part2(input: &str) -> Result { let policies = input .lines() - .map(|line| line.parse::().map_err(|e| err!("{}", e))) + .map(|line| line.parse::()) .collect::>>()?; Ok(policies diff --git a/aoc2020/src/day03.rs b/aoc2020/src/day03.rs index 28e8232..326a62f 100644 --- a/aoc2020/src/day03.rs +++ b/aoc2020/src/day03.rs @@ -3,9 +3,11 @@ use std::iter::FromIterator; use std::ops::Index; use std::str::FromStr; +use anyhow::Result; + const INPUT: &str = include_str!("../input/day03.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -14,13 +16,13 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let forest = input.parse()?; Ok(count_trees(&forest, (3, 1))) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let forest = input.parse()?; let slopes = &[(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]; @@ -89,9 +91,9 @@ impl Index for Forest { } impl FromStr for Forest { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { let trees = s .lines() .map(|line| line.chars().map(|c| matches!(c, '#')).collect()) diff --git a/aoc2020/src/day04.rs b/aoc2020/src/day04.rs index 569d222..3cc5cc5 100644 --- a/aoc2020/src/day04.rs +++ b/aoc2020/src/day04.rs @@ -3,9 +3,11 @@ use std::fmt::Write; use std::ops::RangeInclusive; use std::str::FromStr; +use anyhow::Result; + const INPUT: &str = include_str!("../input/day04.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -14,7 +16,7 @@ pub fn run() -> aoc::Result { Ok(res) } -fn get_passports(input: &str) -> aoc::Result> { +fn get_passports(input: &str) -> Result> { let mut passports: Vec = Vec::new(); let mut passport = String::new(); @@ -35,13 +37,13 @@ fn get_passports(input: &str) -> aoc::Result> { Ok(passports) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let passports = get_passports(input)?; Ok(passports.iter().filter(|p| p.is_complete()).count()) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let passports = get_passports(input)?; Ok(passports @@ -89,9 +91,9 @@ impl Passport { } impl FromStr for Passport { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { let mut fields: HashMap<&str, String> = s .split_whitespace() .map(|f| { diff --git a/aoc2020/src/day05.rs b/aoc2020/src/day05.rs index 4cf1866..198f084 100644 --- a/aoc2020/src/day05.rs +++ b/aoc2020/src/day05.rs @@ -1,11 +1,11 @@ use std::fmt::Write; use std::str::FromStr; -use aoc::err; +use anyhow::{anyhow, bail, Context, Result}; const INPUT: &str = include_str!("../input/day05.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -14,26 +14,24 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let seats = input .lines() .map(|line| line.parse()) - .collect::>>() - .map_err(|e| err!("{}", e))?; + .collect::>>()?; seats .iter() .map(|seat| seat.id()) .max() - .ok_or_else(|| err!("0 seats processed")) + .context("0 seats processed") } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let mut seats = input .lines() .map(|line| line.parse()) - .collect::>>() - .map_err(|e| err!("{}", e))?; + .collect::>>()?; // Seats will be sorted by lexicographical order of fields thanks to `derive(PartialOrd, Ord)`, // which should produce the same result as a manual implementation of `Ord` and `PartialOrd` @@ -49,7 +47,7 @@ fn part2(input: &str) -> aoc::Result { } } - Err(err!("didn't find missing seat")) + Err(anyhow!("didn't find missing seat")) } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -65,11 +63,11 @@ impl Seat { } impl FromStr for Seat { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { if s.len() != 10 { - return Err(err!("Seat encoding must be 10 chars long: {}", s)); + bail!("Seat encoding must be 10 chars long: {}", s); } let (mut row_begin, mut row_end) = (0, 128); @@ -90,7 +88,7 @@ impl FromStr for Seat { 'R' => { col_begin += col_range; } - _ => return Err(err!("Wrong char while decoding seat: `{}`", c)), + _ => bail!("Wrong char while decoding seat: `{}`", c), } } diff --git a/aoc2020/src/day06.rs b/aoc2020/src/day06.rs index c7db5a5..810f75b 100644 --- a/aoc2020/src/day06.rs +++ b/aoc2020/src/day06.rs @@ -1,9 +1,11 @@ use std::collections::HashSet; use std::fmt::Write; +use anyhow::Result; + const INPUT: &str = include_str!("../input/day06.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -12,7 +14,7 @@ pub fn run() -> aoc::Result { Ok(res) } -fn get_groups(input: &str) -> aoc::Result> { +fn get_groups(input: &str) -> Result> { let mut groups = Vec::new(); let mut answers = Vec::new(); @@ -36,7 +38,7 @@ fn get_groups(input: &str) -> aoc::Result> { Ok(groups) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let groups = get_groups(input)?; Ok(groups @@ -45,7 +47,7 @@ fn part1(input: &str) -> aoc::Result { .sum()) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let groups = get_groups(input)?; Ok(groups diff --git a/aoc2020/src/day07.rs b/aoc2020/src/day07.rs index 37fd9d4..bc13f81 100644 --- a/aoc2020/src/day07.rs +++ b/aoc2020/src/day07.rs @@ -2,11 +2,11 @@ use std::collections::HashMap; use std::fmt::Write; use std::str::FromStr; -use aoc::err; +use anyhow::{Context, Result}; const INPUT: &str = include_str!("../input/day07.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -15,11 +15,11 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let bag_rules = input .lines() .map(|line| line.parse()) - .collect::>>() + .collect::>>() .unwrap(); // create map with Key = color, Value = BagRule @@ -39,11 +39,11 @@ fn part1(input: &str) -> aoc::Result { .count()) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let bag_rules = input .lines() .map(|line| line.parse()) - .collect::>>() + .collect::>>() .unwrap(); // create map with Key = color, Value = BagRule @@ -102,9 +102,9 @@ impl BagRule { } impl FromStr for BagRule { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { let words: Vec<&str> = s.split(' ').collect(); // let's assume our input is always valid for now @@ -130,7 +130,7 @@ impl FromStr for BagRule { number => { let n = number .parse() - .map_err(|e| err!("couldn't parse number `{}` in bag rule", e))?; + .context("couldn't parse number in bag rule")?; let adjective = words[1]; let color = words[2]; @@ -169,7 +169,7 @@ mod tests { let bag_rules = PROVIDED1 .lines() .map(|line| line.parse()) - .collect::>>() + .collect::>>() .unwrap(); let expected = vec![ diff --git a/aoc2020/src/day08.rs b/aoc2020/src/day08.rs index e1c2c96..6e057b9 100644 --- a/aoc2020/src/day08.rs +++ b/aoc2020/src/day08.rs @@ -1,11 +1,11 @@ use std::collections::HashSet; use std::fmt::Write; -use aoc::err; +use anyhow::{anyhow, bail, Context, Result}; const INPUT: &str = include_str!("../input/day08.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -14,25 +14,25 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let instructions = input .lines() .map(|line| line.parse()) - .collect::>>()?; + .collect::>>()?; let mut interpreter = Interpreter::new(instructions); Ok(match interpreter.run() { ExitStatus::InfiniteLoop(value) => value, - ExitStatus::End(_) => return Err(err!("interpreter doesn't have an infinite loop")), + ExitStatus::End(_) => bail!("interpreter doesn't have an infinite loop"), }) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let instructions = input .lines() .map(|line| line.parse()) - .collect::>>()?; + .collect::>>()?; for idx in 0..instructions.len() { let mut instructions = instructions.clone(); @@ -51,7 +51,7 @@ fn part2(input: &str) -> aoc::Result { } } - Err(err!( + Err(anyhow!( "interpreter always had an infinite loop, no solution found" )) } @@ -110,21 +110,21 @@ enum Instruction { } impl std::str::FromStr for Instruction { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { - let space = s.find(' ').ok_or_else(|| err!("couldn't split on space"))?; + fn from_str(s: &str) -> Result { + let space = s.find(' ').context("couldn't split on space")?; let inst = &s[..space]; let arg = s[(space + 1)..] .parse() - .map_err(|e| err!("couldn't parse argument for instruction: {}", e))?; + .context("couldn't parse argument for instruction")?; Ok(match inst { "acc" => Self::Acc(arg), "jmp" => Self::Jmp(arg), "nop" => Self::Nop(arg), - _ => return Err(err!("unrecognized instruction `{}`", inst)), + _ => bail!("unrecognized instruction `{}`", inst), }) } } diff --git a/aoc2020/src/day09.rs b/aoc2020/src/day09.rs index e203d42..f3dafc8 100644 --- a/aoc2020/src/day09.rs +++ b/aoc2020/src/day09.rs @@ -1,10 +1,10 @@ use std::fmt::Write; -use aoc::err; +use anyhow::{anyhow, Result}; const INPUT: &str = include_str!("../input/day09.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -27,7 +27,7 @@ fn find_pair_sum(data: &[u64], total: u64) -> Option<(u64, u64)> { None } -fn find_outlier(numbers: &[u64], preamble_size: usize) -> aoc::Result<(u64, usize)> { +fn find_outlier(numbers: &[u64], preamble_size: usize) -> Result<(u64, usize)> { // start checking numbers after the preamble only for i in preamble_size..numbers.len() { let preamble = &numbers[(i - preamble_size)..i]; @@ -39,22 +39,21 @@ fn find_outlier(numbers: &[u64], preamble_size: usize) -> aoc::Result<(u64, usiz } } - Err(err!("couldn't find number with that property")) + Err(anyhow!("couldn't find number with that property")) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let numbers = input .lines() - .map(|line| line.parse::()) - .collect::, _>>() - .map_err(|e| err!("couldn't parse number: {}", e))?; + .map(|line| line.parse::().map_err(anyhow::Error::new)) + .collect::, _>>()?; let (solution, _) = find_outlier(&numbers, 25)?; Ok(solution) } -fn find_contiguous_range(numbers: &[u64], total: u64) -> aoc::Result<(u64, u64)> { +fn find_contiguous_range(numbers: &[u64], total: u64) -> Result<(u64, u64)> { // compute cumulated sums for the whole range let (sums, _) = numbers.iter().fold((vec![0], 0), |(mut vec, acc), n| { let acc = acc + n; @@ -74,15 +73,14 @@ fn find_contiguous_range(numbers: &[u64], total: u64) -> aoc::Result<(u64, u64)> } } - Err(err!("couldn't find number with that property")) + Err(anyhow!("couldn't find number with that property")) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let numbers = input .lines() - .map(|line| line.parse::()) - .collect::, _>>() - .map_err(|e| err!("couldn't parse number: {}", e))?; + .map(|line| line.parse::().map_err(anyhow::Error::new)) + .collect::, _>>()?; let (outlier, idx) = find_outlier(&numbers, 25)?; diff --git a/aoc2020/src/day10.rs b/aoc2020/src/day10.rs index 95eae68..9336a02 100644 --- a/aoc2020/src/day10.rs +++ b/aoc2020/src/day10.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; use std::fmt::Write; -use aoc::err; +use anyhow::{bail, Result}; const INPUT: &str = include_str!("../input/day10.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -14,17 +14,14 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let mut jolts = input .lines() - .map(|line| { - line.parse() - .map_err(|e| err!("couldn't parse joltage: {}", e)) - }) - .collect::>>()?; + .map(|line| line.parse().map_err(anyhow::Error::new)) + .collect::>>()?; if jolts.is_empty() { - return Err(err!("input was empty!")); + bail!("input was empty!"); } // charging outlet can be added @@ -80,17 +77,14 @@ fn find_possibilities(jolts: &[u64], possibilities: &mut HashMap) -> possibilities_from_here } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let mut jolts = input .lines() - .map(|line| { - line.parse() - .map_err(|e| err!("couldn't parse joltage: {}", e)) - }) - .collect::>>()?; + .map(|line| line.parse().map_err(anyhow::Error::new)) + .collect::>>()?; if jolts.is_empty() { - return Err(err!("input was empty!")); + bail!("input was empty!"); } // charging outlet can be added diff --git a/aoc2020/src/day11.rs b/aoc2020/src/day11.rs index af8a480..5f5c9dd 100644 --- a/aoc2020/src/day11.rs +++ b/aoc2020/src/day11.rs @@ -1,10 +1,10 @@ use std::fmt::Write; -use aoc::err; +use anyhow::{anyhow, Result}; const INPUT: &str = include_str!("../input/day11.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -13,7 +13,7 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let mut layout: Layout = input.parse()?; let occupied_threshold = 4; @@ -22,7 +22,7 @@ fn part1(input: &str) -> aoc::Result { Ok(layout.occupied_seats()) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let mut layout: Layout = input.parse()?; let occupied_threshold = 5; @@ -177,9 +177,9 @@ impl std::ops::IndexMut for Layout { } impl std::str::FromStr for Layout { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { let grid = s .lines() .map(|line| { @@ -188,11 +188,11 @@ impl std::str::FromStr for Layout { '.' => Ok(Cell::Floor), 'L' => Ok(Cell::EmptySeat), '#' => Ok(Cell::OccupiedSeat), - _ => Err(err!("unknown char `{}`", c)), + _ => Err(anyhow!("unknown char `{}`", c)), }) .collect() }) - .collect::>()?; + .collect::>()?; let height = grid.len(); let width = grid[0].len(); diff --git a/aoc2020/src/day12.rs b/aoc2020/src/day12.rs index ee1aa46..5470292 100644 --- a/aoc2020/src/day12.rs +++ b/aoc2020/src/day12.rs @@ -1,10 +1,10 @@ use std::fmt::Write; -use aoc::err; +use anyhow::{bail, Context, Result}; const INPUT: &str = include_str!("../input/day12.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -13,11 +13,11 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let actions: Vec = input .lines() .map(|line| line.parse()) - .collect::>()?; + .collect::>()?; let mut ship = Ship::new(); @@ -28,11 +28,11 @@ fn part1(input: &str) -> aoc::Result { Ok(ship.manhattan_distance()) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let actions: Vec = input .lines() .map(|line| line.parse()) - .collect::>()?; + .collect::>()?; let mut ship = Ship::new(); @@ -118,9 +118,9 @@ struct Action { } impl std::str::FromStr for Action { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { debug_assert!( s.len() >= 2, "tried to parse action but it is too short: `{}`", @@ -129,7 +129,7 @@ impl std::str::FromStr for Action { let letter = s .chars() .next() - .ok_or_else(|| err!("couldn't parse action: empty string"))?; + .context("couldn't parse action: empty string")?; let kind = match letter { 'N' => ActionKind::Move(Direction::North), @@ -142,12 +142,10 @@ impl std::str::FromStr for Action { 'F' => ActionKind::Forward, - _ => return Err(err!("couldn't parse action with letter `{}`", letter)), + _ => bail!("couldn't parse action with letter `{}`", letter), }; - let arg = s[1..] - .parse() - .map_err(|e| err!("couldn't parse action arg: {}", e))?; + let arg = s[1..].parse().context("couldn't parse action arg")?; Ok(Self { kind, arg }) } diff --git a/aoc2020/src/day13.rs b/aoc2020/src/day13.rs index 0175df9..5fe9974 100644 --- a/aoc2020/src/day13.rs +++ b/aoc2020/src/day13.rs @@ -1,10 +1,10 @@ use std::fmt::Write; -use aoc::err; +use anyhow::{Context, Result}; const INPUT: &str = include_str!("../input/day13.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -13,27 +13,27 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let mut lines = input.lines(); let earliest_timestamp = lines .next() - .ok_or_else(|| err!("input was empty"))? + .context("input was empty")? .parse::() - .map_err(|e| err!("couldn't parse first line: {}", e))?; + .context("couldn't parse first line")?; let bus_ids = lines .next() - .ok_or_else(|| err!("no second line"))? + .context("no second line")? .split(',') .filter_map(|num| { if num == "x" { None } else { - Some(num.parse::().map_err(|e| err!("{}", e))) + Some(num.parse::().map_err(anyhow::Error::new)) } }) - .collect::>>()?; + .collect::>>()?; let (bus_id, earliest_departure) = bus_ids .iter() @@ -47,16 +47,16 @@ fn part1(input: &str) -> aoc::Result { Ok(bus_id * (earliest_departure - earliest_timestamp)) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let mut lines = input.lines(); // we don't need the first line anymore, skip it - lines.next().ok_or_else(|| err!("input was empty"))?; + lines.next().context("input was empty")?; - find_timestamp(lines.next().ok_or_else(|| err!("no second line"))?) + find_timestamp(lines.next().context("no second line")?) } -fn find_timestamp(input: &str) -> aoc::Result { +fn find_timestamp(input: &str) -> Result { let bus_ids: Vec<(u64, u64)> = input .split(',') .enumerate() @@ -64,14 +64,14 @@ fn find_timestamp(input: &str) -> aoc::Result { if num == "x" { None } else { - Some((idx as u64, num.parse::().map_err(|e| err!("{}", e)))) + Some((idx as u64, num.parse::().map_err(anyhow::Error::new))) } }) .map(|(idx, res)| match res { Ok(num) => Ok((idx, num)), Err(e) => Err(e), }) - .collect::>()?; + .collect::>()?; // previous constraints is empty for now let mut current_solution = 0; diff --git a/aoc2020/src/day14.rs b/aoc2020/src/day14.rs index 8fe24f4..a2ef9b4 100644 --- a/aoc2020/src/day14.rs +++ b/aoc2020/src/day14.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; use std::fmt::Write; -use aoc::err; +use anyhow::{anyhow, bail, Context, Result}; const INPUT: &str = include_str!("../input/day14.txt"); -pub fn run() -> aoc::Result { +pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; @@ -14,7 +14,7 @@ pub fn run() -> aoc::Result { Ok(res) } -fn part1(input: &str) -> aoc::Result { +fn part1(input: &str) -> Result { let mut program: Program = input.parse()?; program.run_part1()?; @@ -22,7 +22,7 @@ fn part1(input: &str) -> aoc::Result { Ok(program.memory_sum()) } -fn part2(input: &str) -> aoc::Result { +fn part2(input: &str) -> Result { let mut program: Program = input.parse()?; program.run_part2()?; @@ -175,9 +175,9 @@ impl BitMask { } impl std::str::FromStr for BitMask { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { let masks = s .chars() .rev() @@ -187,10 +187,10 @@ impl std::str::FromStr for BitMask { '1' => Ok(Mask::One), '0' => Ok(Mask::Zero), 'X' => Ok(Mask::Floating), - _ => Err(err!("unknown character in mask: `{}`", c)), + _ => Err(anyhow!("unknown character in mask: `{}`", c)), } }) - .collect::>()?; + .collect::>()?; Ok(BitMask { masks }) } @@ -203,23 +203,17 @@ enum Instruction { } impl std::str::FromStr for Instruction { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { + fn from_str(s: &str) -> Result { let mut words = s.split(' '); - let first = words - .next() - .ok_or_else(|| err!("missing first word in instruction"))?; - let second = words - .next() - .ok_or_else(|| err!("missing second word in instruction"))?; - let third = words - .next() - .ok_or_else(|| err!("missing third word in instruction"))?; + let first = words.next().context("missing first word in instruction")?; + let second = words.next().context("missing second word in instruction")?; + let third = words.next().context("missing third word in instruction")?; if second != "=" { - return Err(err!("expected `=` as second word in instruction: `{}`", s)); + bail!("expected `=` as second word in instruction: `{}`", s); } if first == "mask" { @@ -227,18 +221,16 @@ impl std::str::FromStr for Instruction { } else { let left_bracket = first .find('[') - .ok_or_else(|| err!("couldn't find bracket in memory instruction"))?; + .context("couldn't find bracket in memory instruction")?; let right_bracket = first .find(']') - .ok_or_else(|| err!("couldn't find bracket in memory instruction"))?; + .context("couldn't find bracket in memory instruction")?; let offset = first[(left_bracket + 1)..right_bracket] .parse() - .map_err(|e| err!("couldn't parse memory offset: `{}`", e))?; + .context("couldn't parse memory offset")?; - let value = third - .parse() - .map_err(|e| err!("couldn't parse memory offset: `{}`", e))?; + let value = third.parse().context("couldn't parse memory offset")?; Ok(Self::MemWrite { offset, value }) } @@ -252,7 +244,7 @@ struct Program { } impl Program { - fn run_part1(&mut self) -> aoc::Result<()> { + fn run_part1(&mut self) -> Result<()> { for inst in &self.instructions { match inst { Instruction::ChangeMask(bitmask) => self.current_mask = Some(bitmask.clone()), @@ -263,7 +255,7 @@ impl Program { .insert(*offset, bitmask.apply_no_floating(*value)); } None => { - return Err(err!("tried to execute MemWrite but mask isn't initialized")) + bail!("tried to execute MemWrite but mask isn't initialized") } }, } @@ -272,7 +264,7 @@ impl Program { Ok(()) } - fn run_part2(&mut self) -> aoc::Result<()> { + fn run_part2(&mut self) -> Result<()> { for inst in &self.instructions { match inst { Instruction::ChangeMask(bitmask) => self.current_mask = Some(bitmask.clone()), @@ -284,7 +276,7 @@ impl Program { } } None => { - return Err(err!("tried to execute MemWrite but mask isn't initialized")) + bail!("tried to execute MemWrite but mask isn't initialized") } }, } @@ -299,13 +291,10 @@ impl Program { } impl std::str::FromStr for Program { - type Err = aoc::Error; + type Err = anyhow::Error; - fn from_str(s: &str) -> aoc::Result { - let instructions = s - .lines() - .map(|line| line.parse()) - .collect::>()?; + fn from_str(s: &str) -> Result { + let instructions = s.lines().map(|line| line.parse()).collect::>()?; Ok(Program { instructions, diff --git a/aoc2020/src/main.rs b/aoc2020/src/main.rs index 9255013..104f8af 100644 --- a/aoc2020/src/main.rs +++ b/aoc2020/src/main.rs @@ -1,5 +1,6 @@ +use anyhow::Result; + use aoc::DayFunc; -use aoc::Result; use aoc2020::day01; use aoc2020::day02;