From 001a8cf0124bf06fcac703c323bb36563f488b1b Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Mon, 7 Dec 2020 20:35:03 -0800 Subject: [PATCH] Try using `thiserror` to remove some boilerplate. --- Cargo.toml | 1 + src/errors.rs | 175 +++++++++++++++----------------------------------- 2 files changed, 53 insertions(+), 123 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e9d34f..6b3ea9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2018" [dependencies] nom = "6.0.1" +thiserror = "1.0.22" \ No newline at end of file diff --git a/src/errors.rs b/src/errors.rs index b5d4b79..7962a18 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,162 +1,91 @@ -use std::fmt; use std::io; use std::num::ParseIntError; +use thiserror::Error; -macro_rules! convert_error { - ($type: ty, $super_type: ident, $pattern: ident) => { - impl From<$type> for $super_type { - fn from(x: $type) -> $super_type { - $super_type::$pattern(x) - } - } - }; -} - +#[derive(Error, Debug)] pub enum TopLevelError { - IOError(io::Error), + #[error("IO error encountered ({source})")] + IOError { + #[from] + source: io::Error, + }, + #[error("No input found")] NoInputFound, + #[error("No solution found")] NoSolutionFound, + #[error("Unknown error occurred")] UnknownError, - PassportParseError(PassportParseError), - SeatParseError(SeatParseError), - BaggageParseError(BaggageRuleParseError), + #[error("Failed to parse passport: {source}")] + PassportParseErrorPassport { + #[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 { - 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); - +#[derive(Error, Debug)] pub enum PasswordParseError { - StringToIntError(ParseIntError), - NomError(nom::Err<()>), + #[error("Failed to convert string to integer: {source}")] + StringToIntError { + #[from] + source: ParseIntError, + }, + #[error("Error nomnomnoming: {source}")] + NomError { + #[from] + source: nom::Err<()>, + }, } -impl fmt::Display for PasswordParseError { - 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); - +#[derive(Error, Debug)] pub enum MapParseError { + #[error("Unexpected character: {0}")] UnexpectedCharacter(char), + #[error("Uneven width at line {0}")] UnevenLines(usize), } -impl fmt::Display for MapParseError { - 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) - } - } - } -} - +#[derive(Error, Debug)] pub enum PassportParseError { + #[error("Invalid chunk in passport line: {0}")] InvalidChunk(String), + #[error("Invalid field in passport: {0}")] InvalidField(String), } -impl fmt::Display for PassportParseError { - 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)] +#[derive(Error, Debug, PartialEq)] pub enum SeatParseError { + #[error("Invalid seat identifier: {0}")] InvalidSeatIdentifier(String), + #[error("Bad row section size {0}")] BadSeatRowSectionSize(usize), + #[error("Bad column section size {0}")] BadSeatColumnSectionSize(usize), + #[error("Unexpected row character '{0}'")] UnexpectedRowCharacter(char), + #[error("Unexpected column character '{0}'")] UnexpectedColumnCharacter(char), + #[error("Wasn't able to resolve column for '{0}'")] DidNotResolveColumn(String), + #[error("Wasn't able to resolve row for '{0}'")] DidNotResolveRow(String), } -impl fmt::Display for SeatParseError { - 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); - +#[derive(Error, Debug)] pub enum BaggageRuleParseError { + #[error("Error parsing rule: {0}")] 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>> for BaggageRuleParseError { fn from(x: nom::Err>) -> BaggageRuleParseError { match x {