Try using thiserror to remove some boilerplate.

This commit is contained in:
2020-12-07 20:35:03 -08:00
parent b06c528c4c
commit 001a8cf012
2 changed files with 53 additions and 123 deletions

View File

@@ -6,3 +6,4 @@ edition = "2018"
[dependencies] [dependencies]
nom = "6.0.1" nom = "6.0.1"
thiserror = "1.0.22"

View File

@@ -1,162 +1,91 @@
use std::fmt;
use std::io; use std::io;
use std::num::ParseIntError; use std::num::ParseIntError;
use thiserror::Error;
macro_rules! convert_error { #[derive(Error, Debug)]
($type: ty, $super_type: ident, $pattern: ident) => {
impl From<$type> for $super_type {
fn from(x: $type) -> $super_type {
$super_type::$pattern(x)
}
}
};
}
pub enum TopLevelError { pub enum TopLevelError {
IOError(io::Error), #[error("IO error encountered ({source})")]
IOError {
#[from]
source: io::Error,
},
#[error("No input found")]
NoInputFound, NoInputFound,
#[error("No solution found")]
NoSolutionFound, NoSolutionFound,
#[error("Unknown error occurred")]
UnknownError, UnknownError,
PassportParseError(PassportParseError), #[error("Failed to parse passport: {source}")]
SeatParseError(SeatParseError), PassportParseErrorPassport {
BaggageParseError(BaggageRuleParseError), #[from]
source: PassportParseError,
},
#[error("Failed to parse seat: {source}")]
SeatParseError {
#[from]
source: SeatParseError,
},
#[error("Failed to parse baggage rule: {source}")]
BaggageParseError {
#[from]
source: BaggageRuleParseError,
},
} }
impl fmt::Display for TopLevelError { #[derive(Error, Debug)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TopLevelError::IOError(e) => write!(f, "IO error: {}", e),
TopLevelError::NoInputFound => write!(f, "No valid inputs found"),
TopLevelError::NoSolutionFound => write!(f, "No solution found."),
TopLevelError::PassportParseError(p) => write!(f, "Error parsing passport: {}", p),
TopLevelError::SeatParseError(s) => write!(f, "Error parsing seat: {}", s),
TopLevelError::BaggageParseError(e) => write!(f, "Error parsing baggage rule: {}", e),
TopLevelError::UnknownError => {
write!(f, "Unknown error occurred; this shouldn't be possible.")
}
}
}
}
convert_error!(io::Error, TopLevelError, IOError);
pub enum PasswordParseError { pub enum PasswordParseError {
StringToIntError(ParseIntError), #[error("Failed to convert string to integer: {source}")]
NomError(nom::Err<()>), StringToIntError {
#[from]
source: ParseIntError,
},
#[error("Error nomnomnoming: {source}")]
NomError {
#[from]
source: nom::Err<()>,
},
} }
impl fmt::Display for PasswordParseError { #[derive(Error, Debug)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PasswordParseError::NomError(e) => write!(f, "Parse error: {}", e),
PasswordParseError::StringToIntError(e) => {
write!(f, "Error converting string to integer: {}", e)
}
}
}
}
convert_error!(ParseIntError, PasswordParseError, StringToIntError);
convert_error!(nom::Err<()>, PasswordParseError, NomError);
pub enum MapParseError { pub enum MapParseError {
#[error("Unexpected character: {0}")]
UnexpectedCharacter(char), UnexpectedCharacter(char),
#[error("Uneven width at line {0}")]
UnevenLines(usize), UnevenLines(usize),
} }
impl fmt::Display for MapParseError { #[derive(Error, Debug)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MapParseError::UnevenLines(l) => write!(f, "Map has uneven width at line {}", l),
MapParseError::UnexpectedCharacter(c) => {
write!(f, "Unexpected character parsing map: {}", c)
}
}
}
}
pub enum PassportParseError { pub enum PassportParseError {
#[error("Invalid chunk in passport line: {0}")]
InvalidChunk(String), InvalidChunk(String),
#[error("Invalid field in passport: {0}")]
InvalidField(String), InvalidField(String),
} }
impl fmt::Display for PassportParseError { #[derive(Error, Debug, PartialEq)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PassportParseError::InvalidChunk(s) => {
write!(f, "Invalid chunk in passport line: {}", s)
}
PassportParseError::InvalidField(s) => write!(f, "Invalid field in passport: {}", s),
}
}
}
convert_error!(PassportParseError, TopLevelError, PassportParseError);
#[derive(Debug, PartialEq)]
pub enum SeatParseError { pub enum SeatParseError {
#[error("Invalid seat identifier: {0}")]
InvalidSeatIdentifier(String), InvalidSeatIdentifier(String),
#[error("Bad row section size {0}")]
BadSeatRowSectionSize(usize), BadSeatRowSectionSize(usize),
#[error("Bad column section size {0}")]
BadSeatColumnSectionSize(usize), BadSeatColumnSectionSize(usize),
#[error("Unexpected row character '{0}'")]
UnexpectedRowCharacter(char), UnexpectedRowCharacter(char),
#[error("Unexpected column character '{0}'")]
UnexpectedColumnCharacter(char), UnexpectedColumnCharacter(char),
#[error("Wasn't able to resolve column for '{0}'")]
DidNotResolveColumn(String), DidNotResolveColumn(String),
#[error("Wasn't able to resolve row for '{0}'")]
DidNotResolveRow(String), DidNotResolveRow(String),
} }
impl fmt::Display for SeatParseError { #[derive(Error, Debug)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SeatParseError::InvalidSeatIdentifier(s) => {
write!(f, "Invalid seat identifier: {:?}", s)
}
SeatParseError::BadSeatRowSectionSize(x) => write!(
f,
"Bad identifiers for rows; expected 7 characters, got {}",
x
),
SeatParseError::BadSeatColumnSectionSize(x) => write!(
f,
"Bad identifiers for columns; expected 3 characters, got {}",
x
),
SeatParseError::UnexpectedRowCharacter(c) => {
write!(f, "Unexpected character when parsing rows: {:?}", c)
}
SeatParseError::UnexpectedColumnCharacter(c) => {
write!(f, "Unexpected character when parsing columns: {:?}", c)
}
SeatParseError::DidNotResolveRow(s) => {
write!(f, "Could not resolve row with {:?}", s)
}
SeatParseError::DidNotResolveColumn(s) => {
write!(f, "Could not resolve row with {:?}", s)
}
}
}
}
convert_error!(SeatParseError, TopLevelError, SeatParseError);
pub enum BaggageRuleParseError { pub enum BaggageRuleParseError {
#[error("Error parsing rule: {0}")]
NomError(String), NomError(String),
NumericConversionError(ParseIntError),
} }
impl fmt::Display for BaggageRuleParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BaggageRuleParseError::NomError(e) => write!(f, "General parsing error: {}", e),
BaggageRuleParseError::NumericConversionError(e) => {
write!(f, "Error converting number to value: {}", e)
}
}
}
}
convert_error!(BaggageRuleParseError, TopLevelError, BaggageParseError);
convert_error!(ParseIntError, BaggageRuleParseError, NumericConversionError);
impl<'a> From<nom::Err<nom::error::Error<&'a str>>> for BaggageRuleParseError { impl<'a> From<nom::Err<nom::error::Error<&'a str>>> for BaggageRuleParseError {
fn from(x: nom::Err<nom::error::Error<&'a str>>) -> BaggageRuleParseError { fn from(x: nom::Err<nom::error::Error<&'a str>>) -> BaggageRuleParseError {
match x { match x {