diff --git a/Cargo.toml b/Cargo.toml index 0dc6ff3..bdab6d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" authors = ["Felix Döring ", "Felix Wittwer "] [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" diff --git a/src/error.rs b/src/error.rs index 88caabc..c1fc6b0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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 = Result; - -/// 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 = Result; -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 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 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."]; } } diff --git a/src/lib.rs b/src/lib.rs index 4fee2d6..5a8a700 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/list.rs b/src/list.rs index 3f91c4e..f79127f 100644 --- a/src/list.rs +++ b/src/list.rs @@ -52,7 +52,7 @@ impl TodoList { pub fn contains_id(&self, id:u32) -> TdoResult { 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. @@ -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()), } } @@ -73,7 +73,7 @@ impl TodoList { pub fn remove_id(&mut self, id: u32) -> TdoResult { match self.contains_id(id) { Ok(index) => Ok(self.list.remove(index)), - _ => Err(TodoError::NotInList.into()), + _ => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()), } } diff --git a/src/tdo.rs b/src/tdo.rs index 323119a..a7ad312 100644 --- a/src/tdo.rs +++ b/src/tdo.rs @@ -57,7 +57,7 @@ impl Tdo { Err(_) => update_json(path), } } - Err(_) => Err(StorageError::FileNotFound.into()), + Err(_) => Err(ErrorKind::StorageError(storage_error::ErrorKind::FileNotFound).into()), } } @@ -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(()) @@ -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()), } } } @@ -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 @@ -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()), } } @@ -196,7 +196,7 @@ fn update_json(path: &str) -> TdoResult { 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 = vec![]; @@ -206,15 +206,15 @@ fn update_json(path: &str) -> TdoResult { for inner in outer.1.entries_mut() { let tdo_id = match inner.0.parse::() { 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 {