diff options
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/api/mod.rs | 55 | ||||
-rw-r--r-- | src/bt.rs | 43 | ||||
-rw-r--r-- | src/cache.rs | 41 | ||||
-rw-r--r-- | src/main.rs | 14 | ||||
-rw-r--r-- | src/output.rs | 6 | ||||
-rw-r--r-- | src/render.rs | 42 |
7 files changed, 131 insertions, 71 deletions
@@ -15,7 +15,6 @@ serde = "1.0" serde_json = "1.0" clap = "2.33" xdg = "2.2.0" -quick-error = "1.2.0" itertools = "0.8.0" md5 = "0.7" base64 = "0.11" diff --git a/src/api/mod.rs b/src/api/mod.rs index c33e6ba..27f0da1 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -18,32 +18,49 @@ use image::DynamicImage; use itertools::Itertools; use reqwest::{Client, StatusCode, Url}; use serde::{de::DeserializeOwned, Serialize}; -use std::path::Path; +use std::{error::Error, fmt, path::Path}; use super::cache::{Cache, CacheError}; /// The base URL of the official Guild Wars 2 API. const BASE_URL: &str = "https://api.guildwars2.com/v2/"; -quick_error! { - #[derive(Debug)] - pub enum ApiError { - ItemNotFound {} - SerializationError(err: serde_json::Error) { - cause(err) - from() - } - CacheError(err: CacheError) { - cause(err) - from() - } - HttpError(err: reqwest::Error) { - cause(err) - from() +#[derive(Debug)] +pub enum ApiError { + ItemNotFound, + SerializationError(serde_json::Error), + CacheError(CacheError), + HttpError(reqwest::Error), + ImageError(image::ImageError), +} + +error_froms! { ApiError, + err: serde_json::Error => ApiError::SerializationError(err), + err: CacheError => ApiError::CacheError(err), + err: reqwest::Error => ApiError::HttpError(err), + err: image::ImageError => ApiError::ImageError(err), +} + +impl fmt::Display for ApiError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ApiError::ItemNotFound => write!(f, "the requested item was not found in the API"), + ApiError::SerializationError(_) => write!(f, "error deserializing the returned value"), + ApiError::CacheError(_) => write!(f, "error accessing the cache"), + ApiError::HttpError(_) => write!(f, "HTTP error"), + ApiError::ImageError(_) => write!(f, "image processing error"), } - ImageError(err: image::ImageError) { - cause(err) - from() + } +} + +impl Error for ApiError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match *self { + ApiError::SerializationError(ref err) => Some(err), + ApiError::CacheError(ref err) => Some(err), + ApiError::HttpError(ref err) => Some(err), + ApiError::ImageError(ref err) => Some(err), + _ => None, } } } @@ -1,20 +1,35 @@ use super::api::{Api, ApiError, Skill, Specialization}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use std::{convert::TryFrom, fmt, str::FromStr}; - -quick_error! { - #[derive(Debug)] - pub enum ChatlinkError { - ApiError(err: ApiError) { - cause(err) - from() +use std::{convert::TryFrom, error::Error, fmt, str::FromStr}; + +#[derive(Debug)] +pub enum ChatlinkError { + ApiError(ApiError), + MalformedInput, +} + +error_froms! { ChatlinkError, + err: ApiError => ChatlinkError::ApiError(err), + _err: base64::DecodeError => ChatlinkError::MalformedInput, + _err: num_enum::TryFromPrimitiveError<Profession> => ChatlinkError::MalformedInput, + _err: num_enum::TryFromPrimitiveError<TraitChoice> => ChatlinkError::MalformedInput, + _err: num_enum::TryFromPrimitiveError<Legend> => ChatlinkError::MalformedInput, +} + +impl fmt::Display for ChatlinkError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ChatlinkError::ApiError(_) => write!(f, "error accessing the API"), + ChatlinkError::MalformedInput => write!(f, "the input link is malformed"), } - MalformedInput { - description("The input link is malformed") - from(base64::DecodeError) - from(num_enum::TryFromPrimitiveError<Profession>) - from(num_enum::TryFromPrimitiveError<TraitChoice>) - from(num_enum::TryFromPrimitiveError<Legend>) + } +} + +impl Error for ChatlinkError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match *self { + ChatlinkError::ApiError(ref err) => Some(err), + _ => None, } } } diff --git a/src/cache.rs b/src/cache.rs index f64b45a..2b490ec 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,18 +1,31 @@ //! Caching support to prevent hitting the API a lot. -use std::fs::File; -use std::io::prelude::*; -use std::path::Path; +use std::{error::Error, fmt, fs, path::Path}; use xdg::BaseDirectories; use super::APP_NAME; -quick_error! { - #[derive(Debug)] - pub enum CacheError { - Io(err: std::io::Error) { - cause(err) - from() +#[derive(Debug)] +pub enum CacheError { + Io(std::io::Error), +} + +error_froms! { CacheError, + err: std::io::Error => CacheError::Io(err), +} + +impl fmt::Display for CacheError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CacheError::Io(_) => write!(f, "cache input/output error"), + } + } +} + +impl Error for CacheError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match *self { + CacheError::Io(ref err) => Some(err), } } } @@ -39,20 +52,14 @@ impl FileCache { impl Cache for FileCache { fn store(&mut self, path: &Path, data: &[u8]) -> Result<(), CacheError> { let cache_path = self.dirs.place_cache_file(path).unwrap(); - let mut f = File::create(cache_path)?; - f.write_all(data)?; + fs::write(cache_path, data)?; Ok(()) } fn get(&mut self, path: &Path) -> Result<Option<Vec<u8>>, CacheError> { let cache_path = self.dirs.find_cache_file(path); match cache_path { - Some(p) => { - let mut f = File::open(p)?; - let mut buffer = Vec::new(); - f.read_to_end(&mut buffer)?; - Ok(Some(buffer)) - } + Some(path) => Ok(Some(fs::read(path)?)), None => Ok(None), } } diff --git a/src/main.rs b/src/main.rs index 181d64a..55afb00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,13 +11,23 @@ extern crate rusttype; extern crate termcolor; extern crate xdg; #[macro_use] -extern crate quick_error; -#[macro_use] extern crate lazy_static; use std::error::Error as StdError; use std::fmt; +macro_rules! error_froms { + ($tname:ty, $($ename:ident : $fty:ty => $res:expr,)*) => { + $( + impl From<$fty> for $tname { + fn from($ename: $fty) -> Self { + $res + } + } + )* + } +} + mod api; mod bt; mod cache; diff --git a/src/output.rs b/src/output.rs index f6e9bc4..9406571 100644 --- a/src/output.rs +++ b/src/output.rs @@ -78,9 +78,6 @@ pub fn show_error<E: Error + ?Sized>(error: &E) -> io::Result<()> { writeln!(stderr, " {}", error)?; let mut source = error.source(); - if source.is_none() { - source = error.cause(); - } while let Some(s) = source { stderr.set_color(&error_color)?; write!(stderr, " [caused by]")?; @@ -88,9 +85,6 @@ pub fn show_error<E: Error + ?Sized>(error: &E) -> io::Result<()> { writeln!(stderr, " {}", s)?; source = s.source(); - if source.is_none() { - source = s.cause(); - } } Ok(()) } diff --git a/src/render.rs b/src/render.rs index 90eff14..9b71e18 100644 --- a/src/render.rs +++ b/src/render.rs @@ -7,20 +7,38 @@ use image::{ use imageproc::{drawing, rect::Rect}; use num_traits::NumCast; use rusttype::{Font, Scale, SharedBytes}; +use std::{error::Error, fmt}; -quick_error! { - #[derive(Debug)] - pub enum RenderError { - ApiError(err: ApiError) { - cause(err) - from() - } - ImageError(err: image::ImageError) { - cause(err) - from() +#[derive(Debug)] +pub enum RenderError { + ApiError(ApiError), + ImageError(image::ImageError), + EmptyBuild, +} + +error_froms! { RenderError, + err: ApiError => RenderError::ApiError(err), + err: image::ImageError => RenderError::ImageError(err), +} + +impl fmt::Display for RenderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + RenderError::ApiError(_) => write!(f, "error accessing the API"), + RenderError::ImageError(_) => write!(f, "image processing error"), + RenderError::EmptyBuild => { + write!(f, "the build template contains nothing worth rendering") + } } - EmptyBuild { - description("The build template contains nothing worth rendering") + } +} + +impl Error for RenderError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match *self { + RenderError::ApiError(ref err) => Some(err), + RenderError::ImageError(ref err) => Some(err), + _ => None, } } } |