2019: switch to anyhow

This commit is contained in:
Antoine Martin 2020-12-14 19:24:43 +01:00
parent d91165207f
commit deb808faf3
19 changed files with 84 additions and 114 deletions

1
Cargo.lock generated
View file

@ -34,6 +34,7 @@ dependencies = [
name = "aoc2019"
version = "0.1.0"
dependencies = [
"anyhow",
"aoc",
"criterion",
]

View file

@ -13,6 +13,7 @@ criterion = "0.3"
[dependencies]
aoc = { path = "../aoc" }
anyhow = "1.0"
[lib]
path = "src/lib.rs"

View file

@ -1,6 +1,6 @@
use std::fmt::Write;
use aoc::Result;
use anyhow::Result;
const INPUT: &str = include_str!("../input/day01.txt");
@ -21,10 +21,7 @@ fn part1(input: &str) -> Result<u64> {
input
.lines()
.map(|line| line.parse::<u64>())
.map(|w| match w {
Ok(w) => Ok(fuel_needed(w)),
Err(e) => Err(Box::from(e)),
})
.map(|w| w.map(fuel_needed).map_err(anyhow::Error::new))
.sum()
}
@ -44,10 +41,7 @@ fn part2(input: &str) -> Result<u64> {
input
.lines()
.map(|line| line.parse::<u64>())
.map(|w| match w {
Ok(w) => Ok(cumulated_fuel_needed(w)),
Err(e) => Err(Box::from(e)),
})
.map(|w| w.map(cumulated_fuel_needed).map_err(anyhow::Error::new))
.sum()
}

View file

@ -1,7 +1,6 @@
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{anyhow, bail, Context, Result};
use crate::intcode::{parse_memory, Intcode};
@ -28,7 +27,7 @@ fn part1(mut input: Vec<i64>) -> Result<i64> {
intcode
.get_day02_output()
.ok_or_else(|| err!("intcode memory was empty!"))
.context("intcode memory was empty!")
}
fn part2(input: &[i64], res: i64) -> Result<i64> {
@ -46,11 +45,11 @@ fn part2(input: &[i64], res: i64) -> Result<i64> {
return Ok(noun * 100 + verb);
}
}
None => return Err(err!("intcode memory was empty!")),
None => bail!("intcode memory was empty!"),
}
}
Err(err!(
Err(anyhow!(
"couldn't find noun/verb combination that produces {}",
res
))

View file

@ -1,10 +1,8 @@
use std::cmp::{max, min};
use std::error::Error;
use std::fmt::Write;
use std::str::FromStr;
use aoc::err;
use aoc::Result;
use anyhow::{bail, Context, Result};
const INPUT: &str = include_str!("../input/day03.txt");
@ -39,7 +37,7 @@ fn part1(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
})
.map(|inter| manhattan_distance(&inter, &Point { x: 0, y: 0 }))
.min()
.ok_or_else(|| err!("wire was empty"))
.context("wire was empty")
}
fn part2(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
@ -72,19 +70,13 @@ fn part2(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
first_length += manhattan_distance(&seg1.begin, &seg1.end);
}
min_dist.ok_or_else(|| err!("wire was empty"))
min_dist.context("wire was empty")
}
fn parse_wires(input: &str) -> Result<(Wire, Wire)> {
let mut lines = input.lines();
let first = lines
.next()
.ok_or_else(|| err!("input missing a line"))?
.parse()?;
let second = lines
.next()
.ok_or_else(|| err!("input missing a line"))?
.parse()?;
let first = lines.next().context("input missing a line")?.parse()?;
let second = lines.next().context("input missing a line")?.parse()?;
Ok((first, second))
}
@ -93,15 +85,14 @@ fn parse_wires(input: &str) -> Result<(Wire, Wire)> {
struct Wire(Vec<Segment>);
impl FromStr for Wire {
type Err = Box<dyn Error>;
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Wire> {
let moves = s
.trim_end()
.split(',')
.map(|m| m.parse())
.collect::<Result<Vec<Move>>>()
.map_err(|e| err!("failed to parse wire: {}", e))?;
.map(|m| m.parse().context("failed to parse wire"))
.collect::<Result<Vec<Move>>>()?;
let mut pos = Point { x: 0, y: 0 };
@ -194,17 +185,15 @@ struct Move {
}
impl FromStr for Move {
type Err = Box<dyn Error>;
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let direction = s
.chars()
.nth(0)
.ok_or_else(|| err!("couldn't get direction char in move: {}", s))?;
.context("couldn't get direction char in move")?;
let s = s
.get(1..)
.ok_or_else(|| err!("move missing length: {}", s))?;
let s = s.get(1..).context("move missing length")?;
let length = s.parse()?;
@ -213,7 +202,7 @@ impl FromStr for Move {
'D' => Direction::Down,
'L' => Direction::Left,
'R' => Direction::Right,
_ => return Err(err!("couldn't parse direction: {}", direction)),
_ => bail!("couldn't parse direction: {}", direction),
};
Ok(Move { direction, length })

View file

@ -1,7 +1,6 @@
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
const INPUT: &str = include_str!("../input/day04.txt");
@ -20,11 +19,11 @@ fn range(input: &str) -> Result<(usize, usize)> {
let mut range = input.trim_end().split('-');
let begin = range
.next()
.ok_or_else(|| err!("invalid input: {}", input))?
.with_context(|| format!("invalid input: {}", input))?
.parse()?;
let end = range
.next()
.ok_or_else(|| err!("invalid input: {}", input))?
.with_context(|| format!("invalid input: {}", input))?
.parse()?;
Ok((begin, end))

View file

@ -1,7 +1,6 @@
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
use crate::intcode::Intcode;
@ -20,18 +19,14 @@ fn part1(input: &str) -> Result<i64> {
let mut intcode = Intcode::new(input)?;
intcode.add_input(1);
intcode.run()?;
intcode
.get_last_output()
.ok_or_else(|| err!("intcode gave no output"))
intcode.get_last_output().context("intcode gave no output")
}
fn part2(input: &str) -> Result<i64> {
let mut intcode = Intcode::new(input)?;
intcode.add_input(5);
intcode.run()?;
intcode
.get_last_output()
.ok_or_else(|| err!("intcode gave no output"))
intcode.get_last_output().context("intcode gave no output")
}
#[cfg(test)]

View file

@ -3,8 +3,7 @@ use std::collections::HashSet;
use std::fmt::Write;
use std::iter;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
const INPUT: &str = include_str!("../input/day06.txt");
@ -42,7 +41,7 @@ fn part1(input: &str) -> Result<u64> {
.map(|line| {
let paren = line
.find(')')
.ok_or_else(|| err!("couldn't find `)` in line: {}", line))?;
.with_context(|| format!("couldn't find `)` in line: {}", line))?;
Ok((line[paren + 1..].to_string(), line[..paren].to_string()))
})
.collect::<Result<HashMap<String, String>>>()?;
@ -61,7 +60,7 @@ fn part2(input: &str) -> Result<usize> {
.map(|line| {
let paren = line
.find(')')
.ok_or_else(|| err!("couldn't find `)` in line: {}", line))?;
.with_context(|| format!("couldn't find `)` in line: {}", line))?;
Ok((line[paren + 1..].to_string(), line[..paren].to_string()))
})
.collect::<Result<HashMap<String, String>>>()?;

View file

@ -1,8 +1,7 @@
use std::collections::VecDeque;
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{bail, Context, Result};
use crate::intcode::{parse_memory, Intcode};
@ -59,7 +58,7 @@ fn part1(input: &str) -> Result<i64> {
output = intcode
.get_last_output()
.ok_or_else(|| err!("no output at end of pipeline!"))?;
.context("no output at end of pipeline!")?;
}
res = std::cmp::max(res, output);
@ -114,7 +113,7 @@ fn part2(input: &str) -> Result<i64> {
res = std::cmp::max(res, signal);
break;
}
None => return Err(err!("last amplifier halted without output")),
None => bail!("last amplifier halted without output"),
};
} else {
for out in last.output.iter() {

View file

@ -1,9 +1,7 @@
use std::error::Error;
use std::fmt::{self, Write};
use std::str::FromStr;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
const IMG_WIDTH: usize = 25;
const IMG_HEIGHT: usize = 6;
@ -27,7 +25,7 @@ fn part1(image: &Image) -> Result<usize> {
.layers
.iter()
.min_by_key(|l| l.pixels.iter().flatten().filter(|d| **d == 0).count())
.ok_or_else(|| err!("image had 0 layers..."))?;
.context("image had 0 layers...")?;
let one_count = most_zero_layer
.pixels
@ -74,7 +72,7 @@ impl fmt::Display for Image {
}
impl FromStr for Image {
type Err = Box<dyn Error>;
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let s = s.trim_end();

View file

@ -1,7 +1,6 @@
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
use crate::intcode::{parse_memory, Intcode};
@ -25,7 +24,7 @@ fn part1(memory: Vec<i64>) -> Result<i64> {
intcode.run()?;
intcode
.get_last_output()
.ok_or_else(|| err!("intcode output was empty!"))
.context("intcode output was empty!")
}
fn part2(memory: Vec<i64>) -> Result<i64> {
@ -35,7 +34,7 @@ fn part2(memory: Vec<i64>) -> Result<i64> {
intcode.run()?;
intcode
.get_last_output()
.ok_or_else(|| err!("intcode output was empty!"))
.context("intcode output was empty!")
}
#[cfg(test)]

View file

@ -1,8 +1,7 @@
use std::collections::HashSet;
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
const INPUT: &str = include_str!("../input/day10.txt");
@ -85,7 +84,7 @@ fn part1(input: &str) -> Result<usize> {
};
}
let best = best.ok_or_else(|| err!("zero asteroid provided"))?;
let best = best.context("zero asteroid provided")?;
Ok(best.len())
}

View file

@ -1,8 +1,7 @@
use std::collections::HashMap;
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{bail, Result};
use crate::intcode::Intcode;
@ -40,7 +39,7 @@ fn part2(input: &str, res: &mut String) -> Result<()> {
fn write_board(res: &mut String, board: HashMap<Position, bool>) -> Result<()> {
if board.is_empty() {
return Err(err!("board was empty"));
bail!("board was empty");
}
let min_x = board.keys().map(|p| p.x).min().unwrap();
@ -106,13 +105,13 @@ impl Robot {
match color {
0 => board.insert(self.pos, false),
1 => board.insert(self.pos, true),
_ => return Err(err!("robot brain output different from 0 or 1")),
_ => bail!("robot brain output different from 0 or 1"),
};
match direction {
0 => self.turn_left(),
1 => self.turn_right(),
_ => return Err(err!("robot brain output different from 0 or 1")),
_ => bail!("robot brain output different from 0 or 1"),
};
self.move_forward();
self.brain.output.clear();

View file

@ -1,9 +1,7 @@
use std::error::Error;
use std::fmt::Write;
use std::str::FromStr;
use aoc::err;
use aoc::Result;
use anyhow::{anyhow, Context, Result};
const INPUT: &str = include_str!("../input/day12.txt");
@ -178,7 +176,7 @@ fn part2(mut planets: Vec<Planet>) -> Result<usize> {
}
}
Err(err!("planets never reached the same state twice"))
Err(anyhow!("planets never reached the same state twice"))
}
#[derive(Clone)]
@ -224,38 +222,38 @@ impl Planet {
}
impl FromStr for Planet {
type Err = Box<dyn Error>;
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let x_equals = s
.find("x=")
.ok_or_else(|| err!("couldn't find x value for planet: {}", s))?;
.with_context(|| format!("couldn't find x value for planet: {}", s))?;
let comma = s
.find(',')
.ok_or_else(|| err!("couldn't find comma after x value: {}", s))?;
.with_context(|| format!("couldn't find comma after x value: {}", s))?;
let x = s[(x_equals + 2)..comma].parse()?;
let s = &s[(comma + 1)..];
let y_equals = s
.find("y=")
.ok_or_else(|| err!("couldn't find y value for planet: {}", s))?;
.with_context(|| format!("couldn't find y value for planet: {}", s))?;
let comma = s
.find(',')
.ok_or_else(|| err!("couldn't find comma after y value: {}", s))?;
.with_context(|| format!("couldn't find comma after y value: {}", s))?;
let y = s[(y_equals + 2)..comma].parse()?;
let s = &s[(comma + 1)..];
let z_equals = s
.find("z=")
.ok_or_else(|| err!("couldn't find z value for planet: {}", s))?;
.with_context(|| format!("couldn't find z value for planet: {}", s))?;
let bracket = s
.find('>')
.ok_or_else(|| err!("couldn't find bracket after z value: {}", s))?;
.with_context(|| format!("couldn't find bracket after z value: {}", s))?;
let z = s[(z_equals + 2)..bracket].parse()?;

View file

@ -1,8 +1,7 @@
use std::collections::HashMap;
use std::fmt::{self, Display, Write};
use aoc::err;
use aoc::Result;
use anyhow::{bail, Result};
use crate::intcode::{parse_memory, Intcode};
@ -119,7 +118,7 @@ impl Tile {
2 => Tile::Block,
3 => Tile::Paddle,
4 => Tile::Ball,
_ => return Err(err!("couldn't associate number with tile: {}", n)),
_ => bail!("couldn't associate number with tile: {}", n),
};
Ok(tile)

View file

@ -2,8 +2,7 @@ use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt::Write;
use aoc::err;
use aoc::Result;
use anyhow::{Context, Result};
const INPUT: &str = include_str!("../input/day14.txt");
@ -22,7 +21,7 @@ fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
for line in input.lines() {
let arrow = line
.find(" => ")
.ok_or_else(|| err!("couldn't find arrow in line: {}", line))?;
.with_context(|| format!("couldn't find arrow in line: {}", line))?;
let elems = &line[..arrow];
let elems = elems
@ -30,7 +29,7 @@ fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
.map(|elem| {
let space = elem
.find(' ')
.ok_or_else(|| err!("couldn't find separator for elem {}", elem))?;
.with_context(|| format!("couldn't find separator for elem {}", elem))?;
let amount = elem[..space].parse()?;
let name = &elem[(space + 1)..];
@ -44,7 +43,7 @@ fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
let result = &line[(arrow + 4)..].trim_end();
let space = result
.find(' ')
.ok_or_else(|| err!("couldn't find separator for result {}", result))?;
.with_context(|| format!("couldn't find separator for result {}", result))?;
let result_amount = result[..space].parse()?;
let result_name = &result[(space + 1)..];
@ -76,7 +75,7 @@ fn get_ore_cost(
if in_stock < quantity {
let recipe = recipes
.get(&material)
.ok_or_else(|| err!("couldn't find recipe for {}", material))?;
.with_context(|| format!("couldn't find recipe for {}", material))?;
let needed = quantity - in_stock;
let num_reactions = (needed + recipe.produced - 1) / recipe.produced;

View file

@ -1,5 +1,4 @@
use aoc::err;
use aoc::Result;
use anyhow::{anyhow, bail, Result};
mod parameter;
@ -8,7 +7,7 @@ use parameter::Parameter;
pub fn parse_memory(s: &str) -> Result<Vec<i64>> {
s.trim_end()
.split(',')
.map(|x| x.parse().map_err(|e| err!("couldn't parse int: {}", e)))
.map(|x| x.parse().map_err(anyhow::Error::new))
.collect()
}
@ -74,7 +73,7 @@ impl Intcode {
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("add: destination parameter can't be immediate"))
Err(anyhow!("add: destination parameter can't be immediate"))
} else {
Ok(Opcode::Add(op1, op2, dst))
}
@ -85,7 +84,9 @@ impl Intcode {
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("multiply: destination parameter can't be immediate"))
Err(anyhow!(
"multiply: destination parameter can't be immediate"
))
} else {
Ok(Opcode::Multiply(op1, op2, dst))
}
@ -94,7 +95,7 @@ impl Intcode {
let dst = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("input: destination parameter can't be immediate"))
Err(anyhow!("input: destination parameter can't be immediate"))
} else {
Ok(Opcode::Input(dst))
}
@ -122,7 +123,9 @@ impl Intcode {
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("less than: destination parameter can't be immediate"))
Err(anyhow!(
"less than: destination parameter can't be immediate"
))
} else {
Ok(Opcode::LessThan(op1, op2, dst))
}
@ -133,7 +136,7 @@ impl Intcode {
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("equals: destination parameter can't be immediate"))
Err(anyhow!("equals: destination parameter can't be immediate"))
} else {
Ok(Opcode::Equals(op1, op2, dst))
}
@ -144,14 +147,14 @@ impl Intcode {
Ok(Opcode::AdjustRelBase(offset))
}
99 => Ok(Opcode::Halt),
_ => Err(err!("unknown opcode: {}", opcode)),
_ => Err(anyhow!("unknown opcode: {}", opcode)),
}
}
fn exec(&mut self) -> Result<bool> {
loop {
if self.ip >= self.memory.len() {
return Err(err!("reached end of program without halting"));
bail!("reached end of program without halting");
}
let opcode = self.get_opcode()?;
@ -181,7 +184,7 @@ impl Intcode {
} else if self.wait_input {
break Ok(false);
} else {
break Err(err!("tried to read input but it was empty"));
break Err(anyhow!("tried to read input but it was empty"));
};
dst.set(input, &mut self.memory, self.relative_base)?;
@ -197,7 +200,7 @@ impl Intcode {
let val = test.get(&mut self.memory, self.relative_base)?;
let dst = dst.get(&mut self.memory, self.relative_base)?;
if dst < 0 {
return Err(err!("dst must be a valid address: {}", dst));
bail!("dst must be a valid address: {}", dst);
}
if val != 0 {
@ -210,7 +213,7 @@ impl Intcode {
let val = test.get(&mut self.memory, self.relative_base)?;
let dst = dst.get(&mut self.memory, self.relative_base)?;
if dst < 0 {
return Err(err!("dst must be a valid address: {}", dst));
bail!("dst must be a valid address: {}", dst);
}
if val == 0 {

View file

@ -1,5 +1,4 @@
use aoc::err;
use aoc::Result;
use anyhow::{anyhow, Context, Result};
#[derive(Debug)]
pub enum Parameter {
@ -10,13 +9,13 @@ pub enum Parameter {
impl Parameter {
pub fn new(mode: i64, val: Option<i64>) -> Result<Self> {
let val = val.ok_or_else(|| err!("parameter value out of bounds"))?;
let val = val.context("parameter value out of bounds")?;
let mode = mode % 10;
match mode {
0 => {
if val < 0 {
Err(err!("negative value for position parameter: {}", val))
Err(anyhow!("negative value for position parameter: {}", val))
} else {
let val = val as usize;
Ok(Parameter::Position(val))
@ -24,7 +23,7 @@ impl Parameter {
}
1 => Ok(Parameter::Immediate(val)),
2 => Ok(Parameter::Relative(val)),
_ => Err(err!("wrong mode for parameter: {}", mode)),
_ => Err(anyhow!("wrong mode for parameter: {}", mode)),
}
}
@ -75,7 +74,7 @@ impl Parameter {
}
Ok(())
}
Parameter::Immediate(_) => Err(err!("cannot write to immediate parameter")),
Parameter::Immediate(_) => Err(anyhow!("cannot write to immediate parameter")),
Parameter::Relative(offset) => {
let address = relative_base.wrapping_add(*offset as usize);
let cell = memory.get_mut(address);

View file

@ -1,5 +1,6 @@
use anyhow::Result;
use aoc::DayFunc;
use aoc::Result;
use aoc2019::day01;
use aoc2019::day02;