Skip to content

Commit

Permalink
use error-chain for errors
Browse files Browse the repository at this point in the history
  • Loading branch information
h4llow3En committed Apr 12, 2017
1 parent cf110ba commit ae410ef
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 97 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ version = "0.1.0"
authors = ["Felix Döring <[email protected]>", "Felix Wittwer <[email protected]>"]

[dependencies]
json = "0.11.6"
serde = "0.9.5"
serde_json = "0.9.4"
serde_derive = "0.9.5"
json = "0.11.6"
error-chain = "0.10.0"
130 changes: 50 additions & 80 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,98 +1,68 @@
//! Custom Error Types for errors that may occur when handling todos (or lists).

use std::error::Error;
use std::fmt;
use std::convert::From;

/// Custom Result Type for tdo.
///
/// This abbreviation is introduced since many functions throughout the crate return
/// this type of result, which bundles all possible errors of the `tdo_core` crate.
pub type TdoResult<T> = Result<T, ErrorKind>;

/// Enum to collect all types of tdo errors.
///
/// This is simply a wrapper for all custom error classes the `tdo_crate` has.
#[derive(Clone, Copy, Debug)]
pub enum ErrorKind {
/// A storage-related error occured while interacting with the file system.
StorageError(StorageError),
/// An error within the tdo data structures occured.
TodoError(TodoError),
}

/// The Errors that may occur while interacting with the file system.
#[derive(Clone, Copy, Debug)]
pub enum StorageError {
/// The accessed file is corrupted. This is most likely
/// because someone edited the JSON file manually.
FileCorrupted,
/// The conversion of an older format failed.
UnableToConvert,
/// The data could not be written to the file.
SaveFailure,
/// The requested file could not be found.
FileNotFound,
}

impl fmt::Display for StorageError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
pub type TdoResult<T> = Result<T>;

impl Error for StorageError {
fn description(&self) -> &str {
match *self {
StorageError::FileCorrupted => "File is corrupted",
StorageError::SaveFailure => "File could not be saved",
StorageError::FileNotFound => "File was not found",
StorageError::UnableToConvert => "File could not be converted automatically",
}
}
}

impl From<StorageError> for ErrorKind {
fn from(e: StorageError) -> Self {
ErrorKind::StorageError(e)
}
}

/// Errors that can arise when working with todo lists.
#[derive(Clone, Copy, Debug)]
pub enum TodoError {
/// The requested item is not in the list.
NotInList,
/// The requested todo list does not exist.
NoSuchList,
/// The default list is tried to be removed.
CanNotRemoveDefault,
/// A list with the same name already exists.
NameAlreadyExists,
/// A todo with the same ID already exists.
IDAlreadyExists,
}

impl fmt::Display for TodoError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
pub mod todo_error {
error_chain! {
errors {
/// The requested item is not in the list.
NotInList {
description("Todo is not in this list")
}
/// The requested todo list does not exist.
NoSuchList {
description("No such list")
}
/// The default list is tried to be removed.
CanNotRemoveDefault {
description("The default list can no be removed")
}
/// A list with the same name already exists.
NameAlreadyExists {
description("There already exists a list with this name")
}
/// A todo with the same ID already exists.
IDAlreadyExists {
description("There already exists a todo with this ID")
}
}
}
}

impl Error for TodoError {
fn description(&self) -> &str {
match *self {
TodoError::NotInList => "Todo is not in this list",
TodoError::NoSuchList => "No such list",
TodoError::CanNotRemoveDefault => "The default list can no be removed",
TodoError::NameAlreadyExists => "There already exists a list with this name",
TodoError::IDAlreadyExists => "There already exists a todo with this ID",
/// The Errors that may occur while interacting with the file system.
pub mod storage_error {
error_chain! {
errors {
/// The accessed file is corrupted. This is most likely
/// because someone edited the JSON file manually.
FileCorrupted {
description("File is corrupted")
}
/// The data could not be written to the file.
SaveFailure {
description("File could not be saved")
}
/// The requested file could not be found.
FileNotFound {
description("File was not found")
}
/// The conversion of an older format failed.
UnableToConvert {
description("File could not be converted automatically")
}
}
}
}

impl From<TodoError> for ErrorKind {
fn from(e: TodoError) -> Self {
ErrorKind::TodoError(e)
error_chain! {
links {
TodoError(todo_error::Error, todo_error::ErrorKind) #[doc = "An error within the tdo data structures occured."];
StorageError(storage_error::Error, storage_error::ErrorKind) #[doc = "A storage-related error occured while interacting with the file system."];
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
trivial_casts, trivial_numeric_casts,
unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
#[macro_use]
extern crate serde_derive;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
extern crate serde_json;
extern crate json;

Expand Down
6 changes: 3 additions & 3 deletions src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl TodoList {
pub fn contains_id(&self, id:u32) -> TdoResult<usize> {
match self.list.iter().position(|x| x.id == id) {
Some(index) => Ok(index),
None => Err(TodoError::NotInList.into()),
None => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()),
}
}
/// Mark a todo from the list with the given ID as done.
Expand All @@ -62,7 +62,7 @@ impl TodoList {
pub fn done_id(&mut self, id: u32) -> TdoResult<()> {
match self.contains_id(id) {
Ok(index) => Ok(self.list[index].set_done()),
_ => Err(TodoError::NotInList.into()),
_ => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()),
}
}

Expand All @@ -73,7 +73,7 @@ impl TodoList {
pub fn remove_id(&mut self, id: u32) -> TdoResult<Todo> {
match self.contains_id(id) {
Ok(index) => Ok(self.list.remove(index)),
_ => Err(TodoError::NotInList.into()),
_ => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()),
}
}

Expand Down
22 changes: 11 additions & 11 deletions src/tdo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Tdo {
Err(_) => update_json(path),
}
}
Err(_) => Err(StorageError::FileNotFound.into()),
Err(_) => Err(ErrorKind::StorageError(storage_error::ErrorKind::FileNotFound).into()),
}

}
Expand All @@ -84,14 +84,14 @@ impl Tdo {
let _ = super::serde_json::to_writer_pretty(&mut f, self);
Ok(())
}
Err(_) => Err(StorageError::SaveFailure.into()),
Err(_) => Err(ErrorKind::StorageError(storage_error::ErrorKind::SaveFailure).into()),
}
}

/// Add a todo list to the container.
pub fn add_list(&mut self, list: TodoList) -> TdoResult<()> {
match self.get_list_index(&list.name) {
Ok(_) => Err(TodoError::NameAlreadyExists.into()),
Ok(_) => Err(ErrorKind::TodoError(todo_error::ErrorKind::NameAlreadyExists).into()),
Err(_) => {
self.lists.push(list);
Ok(())
Expand All @@ -102,14 +102,14 @@ impl Tdo {
/// Removes a list from the container.
pub fn remove_list(&mut self, list_name: &str) -> TdoResult<()> {
if list_name == "default" {
Err(TodoError::CanNotRemoveDefault.into())
Err(ErrorKind::TodoError(todo_error::ErrorKind::CanNotRemoveDefault).into())
} else {
match self.get_list_index(list_name) {
Ok(index) => {
self.lists.remove(index);
Ok(())
}
Err(_) => Err(TodoError::NoSuchList.into()),
Err(_) => Err(ErrorKind::TodoError(todo_error::ErrorKind::NoSuchList).into()),
}
}
}
Expand Down Expand Up @@ -138,7 +138,7 @@ impl Tdo {
return Ok(list);
}
}
Err(TodoError::NotInList.into())
Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into())
}
/// Cycle through all todo lists and mark a todo with the given ID as done.
/// This function has no return value and thus won't indicate whether
Expand Down Expand Up @@ -177,7 +177,7 @@ impl Tdo {
.iter()
.position(|x| x.name.to_lowercase() == name.to_string().to_lowercase()) {
Some(index) => Ok(index),
None => Err(TodoError::NoSuchList.into()),
None => Err(ErrorKind::TodoError(todo_error::ErrorKind::NoSuchList).into()),
}
}

Expand All @@ -196,7 +196,7 @@ fn update_json(path: &str) -> TdoResult<Tdo> {
file.read_to_string(&mut data).unwrap();
let mut json = match parse(&data) {
Ok(content) => content,
Err(_) => return Err(StorageError::FileCorrupted.into()),
Err(_) => return Err(ErrorKind::StorageError(storage_error::ErrorKind::FileCorrupted).into()),
};

let mut lists: Vec<TodoList> = vec![];
Expand All @@ -206,15 +206,15 @@ fn update_json(path: &str) -> TdoResult<Tdo> {
for inner in outer.1.entries_mut() {
let tdo_id = match inner.0.parse::<u32>() {
Ok(id) => id,
Err(_) => return Err(StorageError::UnableToConvert.into()),
Err(_) => return Err(ErrorKind::StorageError(storage_error::ErrorKind::UnableToConvert).into()),
};
let done = match inner.1.pop().as_bool() {
Some(x) => x,
None => return Err(StorageError::UnableToConvert.into()),
None => return Err(ErrorKind::StorageError(storage_error::ErrorKind::UnableToConvert).into()),
};
let tdo_name = match inner.1.pop().as_str() {
Some(x) => String::from(x),
None => return Err(StorageError::UnableToConvert.into()),
None => return Err(ErrorKind::StorageError(storage_error::ErrorKind::UnableToConvert).into()),
};
let mut todo = Todo::new(tdo_id, &tdo_name);
if done {
Expand Down

0 comments on commit ae410ef

Please sign in to comment.