diff --git a/Cargo.toml b/Cargo.toml index a13f589..c0fae99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,9 +16,9 @@ version = "2.0.0-rc3" all-features = true [dependencies] -failure = "0.1.1" serde = "1" tempfile = "3" +thiserror = "1.0.20" [dependencies.ron] optional = true @@ -40,6 +40,10 @@ version = "0.8.5" optional = true version = "0.7" +[dependencies.anyhow] +optional = true +version = "1.0.32" + [dev-dependencies] lazy_static = "1" serde_derive = "1" @@ -49,5 +53,6 @@ default = [] ron_enc = ["ron"] bin_enc = ["bincode", "base64"] yaml_enc = ["serde_yaml"] +other_errors = ["anyhow"] mmap = ["memmap"] diff --git a/README.md b/README.md index 7d5a343..eaeb6c3 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,11 @@ features = ["ron_enc"] # You can also use "yaml_enc" or "bin_enc" ``` ```rust -extern crate failure; extern crate rustbreak; use std::collections::HashMap; use rustbreak::{MemoryDatabase, deser::Ron}; -fn main() -> Result<(), failure::Error> { +fn main() -> rustbreak::Result<()> { let db = MemoryDatabase::, Ron>::memory(HashMap::new())?; println!("Writing to Database"); diff --git a/examples/full.rs b/examples/full.rs index 320b2f7..62eb894 100644 --- a/examples/full.rs +++ b/examples/full.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate serde_derive; -use failure; use rustbreak::deser::Ron; use rustbreak::FileDatabase; @@ -17,7 +16,7 @@ struct Person { country: Country, } -fn do_main() -> Result<(), failure::Error> { +fn do_main() -> Result<(), rustbreak::RustbreakError> { use std::collections::HashMap; let db = FileDatabase::, Ron>::load_from_path_or_default("test.ron")?; @@ -58,7 +57,7 @@ fn do_main() -> Result<(), failure::Error> { fn main() { if let Err(e) = do_main() { - eprintln!("An error has occurred at: \n{}", e.backtrace()); + eprintln!("An error has occurred at: \n{}", e); std::process::exit(1); } } diff --git a/examples/switching.rs b/examples/switching.rs index 2717bdb..514ec0f 100644 --- a/examples/switching.rs +++ b/examples/switching.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate serde_derive; -use failure; use rustbreak::deser::{Ron, Yaml}; use rustbreak::{backend::FileBackend, FileDatabase}; @@ -17,7 +16,7 @@ struct Person { country: Country, } -fn do_main() -> Result<(), failure::Error> { +fn do_main() -> Result<(), rustbreak::RustbreakError> { use std::collections::HashMap; let db = FileDatabase::, Ron>::load_from_path_or_default("test.ron")?; @@ -56,7 +55,7 @@ fn do_main() -> Result<(), failure::Error> { fn main() { if let Err(e) = do_main() { - eprintln!("An error has occurred at: \n{}", e.backtrace()); + eprintln!("An error has occurred at: \n{}", e); std::process::exit(1); } } diff --git a/src/backend/mmap.rs b/src/backend/mmap.rs index 49f1c75..c917550 100644 --- a/src/backend/mmap.rs +++ b/src/backend/mmap.rs @@ -1,5 +1,3 @@ -use failure::ResultExt; - use super::Backend; use crate::error; @@ -32,11 +30,11 @@ impl Mmap { } /// Copies data to mmap and modifies data's end cursor. - fn write(&mut self, data: &[u8]) -> Result<(), failure::Error> { + fn write(&mut self, data: &[u8]) -> error::BackendResult<()> { if data.len() > self.len { - return Err(failure::err_msg( - "Unexpected write beyond mmap's backend capacity. This is a rustbreak's bug", - )); + return Err(error::BackendError::Internal(format!( + "Unexpected write beyond mmap's backend capacity." + ))); } self.end = data.len(); self.as_mut_slice().copy_from_slice(data); @@ -59,7 +57,7 @@ impl Mmap { } } -/// A backend that uses anonymous mmap. +/// A backend that uses an nonymous mmap. /// /// The `Backend` automatically creates bigger map /// on demand using following strategy: @@ -77,38 +75,32 @@ pub struct MmapStorage { impl MmapStorage { /// Creates new storage with 1024 bytes. - pub fn new() -> error::Result { + pub fn new() -> error::BackendResult { Self::with_size(1024) } /// Creates new storage with custom size. - pub fn with_size(len: usize) -> error::Result { - let mmap = Mmap::new(len).context(error::RustbreakErrorKind::Backend)?; + pub fn with_size(len: usize) -> error::BackendResult { + let mmap = Mmap::new(len)?; Ok(Self { mmap }) } } impl Backend for MmapStorage { - fn get_data(&mut self) -> error::Result> { + fn get_data(&mut self) -> error::BackendResult> { let mmap = self.mmap.as_slice(); let mut buffer = Vec::with_capacity(mmap.len()); buffer.extend_from_slice(mmap); Ok(buffer) } - fn put_data(&mut self, data: &[u8]) -> error::Result<()> { + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()> { if self.mmap.len < data.len() { - self.mmap - .resize_no_copy(data.len()) - .context(error::RustbreakErrorKind::Backend)?; + self.mmap.resize_no_copy(data.len())?; } - self.mmap - .write(data) - .context(error::RustbreakErrorKind::Backend)?; - self.mmap - .flush() - .context(error::RustbreakErrorKind::Backend)?; + self.mmap.write(data)?; + self.mmap.flush()?; Ok(()) } } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index dee19f3..af8ac87 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -10,9 +10,7 @@ //! Implementing your own Backend should be straightforward. Check the `Backend` //! documentation for details. -use failure::ResultExt; - -use crate::error::{self, RustbreakErrorKind as ErrorKind}; +use crate::error; /// The Backend Trait. /// @@ -21,31 +19,31 @@ use crate::error::{self, RustbreakErrorKind as ErrorKind}; /// same dataset. pub trait Backend { /// Read the all data from the backend. - fn get_data(&mut self) -> error::Result>; + fn get_data(&mut self) -> error::BackendResult>; /// Write the whole slice to the backend. - fn put_data(&mut self, data: &[u8]) -> error::Result<()>; + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()>; } impl Backend for Box { - fn get_data(&mut self) -> error::Result> { + fn get_data(&mut self) -> error::BackendResult> { use std::ops::DerefMut; self.deref_mut().get_data() } - fn put_data(&mut self, data: &[u8]) -> error::Result<()> { + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()> { use std::ops::DerefMut; self.deref_mut().put_data(data) } } impl Backend for Box { - fn get_data(&mut self) -> error::Result> { + fn get_data(&mut self) -> error::BackendResult> { use std::ops::DerefMut; self.deref_mut().get_data() } - fn put_data(&mut self, data: &[u8]) -> error::Result<()> { + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()> { use std::ops::DerefMut; self.deref_mut().put_data(data) } @@ -64,28 +62,22 @@ pub use path::PathBackend; pub struct FileBackend(std::fs::File); impl Backend for FileBackend { - fn get_data(&mut self) -> error::Result> { + fn get_data(&mut self) -> error::BackendResult> { use std::io::{Read, Seek, SeekFrom}; let mut buffer = vec![]; - self.0 - .seek(SeekFrom::Start(0)) - .context(ErrorKind::Backend)?; - self.0 - .read_to_end(&mut buffer) - .context(ErrorKind::Backend)?; + self.0.seek(SeekFrom::Start(0))?; + self.0.read_to_end(&mut buffer)?; Ok(buffer) } - fn put_data(&mut self, data: &[u8]) -> error::Result<()> { + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()> { use std::io::{Seek, SeekFrom, Write}; - self.0 - .seek(SeekFrom::Start(0)) - .context(ErrorKind::Backend)?; - self.0.set_len(0).context(ErrorKind::Backend)?; - self.0.write_all(data).context(ErrorKind::Backend)?; - self.0.sync_all().context(ErrorKind::Backend)?; + self.0.seek(SeekFrom::Start(0))?; + self.0.set_len(0)?; + self.0.write_all(data)?; + self.0.sync_all()?; Ok(()) } } @@ -107,23 +99,19 @@ impl FileBackend { impl FileBackend { /// Opens a new [`FileBackend`] for a given path. /// Errors when the file doesn't yet exist. - pub fn from_path_or_fail>(path: P) -> error::Result { + pub fn from_path_or_fail>(path: P) -> error::BackendResult { use std::fs::OpenOptions; - Ok(Self( - OpenOptions::new() - .read(true) - .write(true) - .open(path) - .context(ErrorKind::Backend)?, - )) + Ok(Self(OpenOptions::new().read(true).write(true).open(path)?)) } /// Opens a new [`FileBackend`] for a given path. /// Creates a file if it doesn't yet exist. /// /// Returns the [`FileBackend`] and whether the file already existed. - pub fn from_path_or_create>(path: P) -> error::Result<(Self, bool)> { + pub fn from_path_or_create>( + path: P, + ) -> error::BackendResult<(Self, bool)> { use std::fs::OpenOptions; let exists = path.as_ref().is_file(); @@ -133,8 +121,7 @@ impl FileBackend { .read(true) .write(true) .create(true) - .open(path) - .context(ErrorKind::Backend)?, + .open(path)?, ), exists, )) @@ -142,7 +129,7 @@ impl FileBackend { /// Opens a new [`FileBackend`] for a given path. /// Creates a file if it doesn't yet exist, and calls `closure` with it. - pub fn from_path_or_create_and(path: P, closure: C) -> error::Result + pub fn from_path_or_create_and(path: P, closure: C) -> error::BackendResult where C: FnOnce(&mut std::fs::File), P: AsRef, @@ -171,12 +158,12 @@ impl MemoryBackend { } impl Backend for MemoryBackend { - fn get_data(&mut self) -> error::Result> { + fn get_data(&mut self) -> error::BackendResult> { println!("Returning data: {:?}", &self.0); Ok(self.0.clone()) } - fn put_data(&mut self, data: &[u8]) -> error::Result<()> { + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()> { println!("Writing data: {:?}", data); self.0 = data.to_owned(); Ok(()) @@ -186,7 +173,6 @@ impl Backend for MemoryBackend { #[cfg(test)] mod tests { use super::{Backend, FileBackend, MemoryBackend}; - use failure::Fail; use std::io::{Read, Seek, SeekFrom, Write}; use tempfile::NamedTempFile; @@ -263,13 +249,11 @@ mod tests { file_path.push("rustbreak_path_db.db"); let err = FileBackend::from_path_or_fail(file_path).expect_err("should fail with file not found"); - assert_eq!(crate::error::RustbreakErrorKind::Backend, err.kind()); - let io_err = err - .cause() - .expect("error has no cause") - .downcast_ref::() - .expect("error is not an io error"); - assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + if let crate::error::BackendError::Io(io_err) = &err { + assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + } else { + panic!("Wrong kind of error returned: {}", err); + }; dir.close().expect("Error while deleting temp directory!"); } diff --git a/src/backend/path.rs b/src/backend/path.rs index 1e3fd7d..234a235 100644 --- a/src/backend/path.rs +++ b/src/backend/path.rs @@ -7,8 +7,6 @@ use super::Backend; use crate::error; -use crate::error::RustbreakErrorKind as ErrorKind; -use failure::ResultExt; use std::fs::OpenOptions; use std::path::{Path, PathBuf}; use tempfile::NamedTempFile; @@ -25,11 +23,8 @@ pub struct PathBackend { impl PathBackend { /// Opens a new [`PathBackend`] for a given path. /// Errors when the file doesn't yet exist. - pub fn from_path_or_fail(path: PathBuf) -> error::Result { - OpenOptions::new() - .read(true) - .open(path.as_path()) - .context(ErrorKind::Backend)?; + pub fn from_path_or_fail(path: PathBuf) -> error::BackendResult { + OpenOptions::new().read(true).open(path.as_path())?; Ok(Self { path }) } @@ -37,19 +32,18 @@ impl PathBackend { /// Creates a file if it doesn't yet exist. /// /// Returns the [`PathBackend`] and whether the file already existed. - pub fn from_path_or_create(path: PathBuf) -> error::Result<(Self, bool)> { + pub fn from_path_or_create(path: PathBuf) -> error::BackendResult<(Self, bool)> { let exists = path.as_path().is_file(); OpenOptions::new() .write(true) .create(true) - .open(path.as_path()) - .context(ErrorKind::Backend)?; + .open(path.as_path())?; Ok((Self { path }, exists)) } /// Opens a new [`PathBackend`] for a given path. /// Creates a file if it doesn't yet exist, and calls `closure` with it. - pub fn from_path_or_create_and(path: PathBuf, closure: C) -> error::Result + pub fn from_path_or_create_and(path: PathBuf, closure: C) -> error::BackendResult where C: FnOnce(&mut std::fs::File), { @@ -58,8 +52,7 @@ impl PathBackend { .read(true) .write(true) .create(true) - .open(path.as_path()) - .context(ErrorKind::Backend)?; + .open(path.as_path())?; if !exists { closure(&mut file) } @@ -68,15 +61,12 @@ impl PathBackend { } impl Backend for PathBackend { - fn get_data(&mut self) -> error::Result> { + fn get_data(&mut self) -> error::BackendResult> { use std::io::Read; - let mut file = OpenOptions::new() - .read(true) - .open(self.path.as_path()) - .context(ErrorKind::Backend)?; + let mut file = OpenOptions::new().read(true).open(self.path.as_path())?; let mut buffer = vec![]; - file.read_to_end(&mut buffer).context(ErrorKind::Backend)?; + file.read_to_end(&mut buffer)?; Ok(buffer) } @@ -84,17 +74,14 @@ impl Backend for PathBackend { /// /// This won't corrupt the existing database file if the program panics /// during the save. - fn put_data(&mut self, data: &[u8]) -> error::Result<()> { + fn put_data(&mut self, data: &[u8]) -> error::BackendResult<()> { use std::io::Write; #[allow(clippy::or_fun_call)] // `Path::new` is a zero cost conversion - let mut tempf = NamedTempFile::new_in(self.path.parent().unwrap_or(Path::new("."))) - .context(ErrorKind::Backend)?; - tempf.write_all(data).context(ErrorKind::Backend)?; - tempf.as_file().sync_all().context(ErrorKind::Backend)?; - tempf - .persist(self.path.as_path()) - .context(ErrorKind::Backend)?; + let mut tempf = NamedTempFile::new_in(self.path.parent().unwrap_or(Path::new(".")))?; + tempf.write_all(data)?; + tempf.as_file().sync_all()?; + tempf.persist(self.path.as_path())?; Ok(()) } } @@ -102,7 +89,6 @@ impl Backend for PathBackend { #[cfg(test)] mod tests { use super::{Backend, PathBackend}; - use failure::Fail; use std::io::Write; use tempfile::NamedTempFile; @@ -155,13 +141,11 @@ mod tests { file_path.push("rustbreak_path_db.db"); let err = PathBackend::from_path_or_fail(file_path).expect_err("should fail with file not found"); - assert_eq!(crate::error::RustbreakErrorKind::Backend, err.kind()); - let io_err = err - .cause() - .expect("error has no cause") - .downcast_ref::() - .expect("error is not an io error"); - assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + if let crate::error::BackendError::Io(io_err) = &err { + assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + } else { + panic!("Wrong kind of error returned: {}", err); + }; dir.close().expect("Error while deleting temp directory!"); } diff --git a/src/deser.rs b/src/deser.rs index e0bee7e..1693e63 100644 --- a/src/deser.rs +++ b/src/deser.rs @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use crate::error; use std::io::Read; use serde::de::DeserializeOwned; @@ -26,11 +27,10 @@ pub use self::bincode::Bincode; /// /// ```rust /// extern crate rustbreak; +/// extern crate thiserror; /// extern crate serde; /// #[macro_use] -/// extern crate failure; /// -/// use failure::{Backtrace, Context, Fail}; /// use serde::de::Deserialize; /// use serde::Serialize; /// use std::io::Read; @@ -38,8 +38,8 @@ pub use self::bincode::Bincode; /// use rustbreak::deser::DeSerializer; /// use rustbreak::error; /// -/// #[derive(Fail, Debug)] -/// #[fail(display = "A FrobnarError ocurred")] +/// #[derive(Clone, Debug, thiserror::Error)] +/// #[error("A frobnarizer could not splagrle.")] /// struct FrobnarError; /// /// fn to_frobnar(input: &T) -> Vec { @@ -57,12 +57,12 @@ pub use self::bincode::Bincode; /// where /// for<'de> T: Deserialize<'de>, /// { -/// fn serialize(&self, val: &T) -> Result, failure::Error> { +/// fn serialize(&self, val: &T) -> rustbreak::DeSerResult> { /// Ok(to_frobnar(val)) /// } /// -/// fn deserialize(&self, s: R) -> Result { -/// Ok(from_frobnar(&s)?) +/// fn deserialize(&self, s: R) -> rustbreak::DeSerResult { +/// Ok(from_frobnar(&s).map_err(|e| error::DeSerError::Other(e.into()))?) /// } /// } /// @@ -72,9 +72,9 @@ pub trait DeSerializer: std::default::Default + Send + Sync + Clone { /// Serializes a given value to a [`String`]. - fn serialize(&self, val: &T) -> Result, failure::Error>; + fn serialize(&self, val: &T) -> error::DeSerResult>; /// Deserializes a [`String`] to a value. - fn deserialize(&self, s: R) -> Result; + fn deserialize(&self, s: R) -> error::DeSerResult; } #[cfg(feature = "ron_enc")] @@ -89,16 +89,17 @@ mod ron { use ron::ser::PrettyConfig; use crate::deser::DeSerializer; + use crate::error; /// The Struct that allows you to use `ron` the Rusty Object Notation. #[derive(Debug, Default, Clone)] pub struct Ron; impl DeSerializer for Ron { - fn serialize(&self, val: &T) -> Result, failure::Error> { + fn serialize(&self, val: &T) -> error::DeSerResult> { Ok(to_ron_string(val, PrettyConfig::default()).map(String::into_bytes)?) } - fn deserialize(&self, s: R) -> Result { + fn deserialize(&self, s: R) -> error::DeSerResult { Ok(from_ron_string(s)?) } } @@ -113,16 +114,17 @@ mod yaml { use serde_yaml::{from_reader as from_yaml_string, to_string as to_yaml_string}; use crate::deser::DeSerializer; + use crate::error; /// The struct that allows you to use yaml. #[derive(Debug, Default, Clone)] pub struct Yaml; impl DeSerializer for Yaml { - fn serialize(&self, val: &T) -> Result, failure::Error> { + fn serialize(&self, val: &T) -> error::DeSerResult> { Ok(to_yaml_string(val).map(String::into_bytes)?) } - fn deserialize(&self, s: R) -> Result { + fn deserialize(&self, s: R) -> error::DeSerResult { Ok(from_yaml_string(s)?) } } @@ -137,16 +139,17 @@ mod bincode { use serde::Serialize; use crate::deser::DeSerializer; + use crate::error; /// The struct that allows you to use bincode #[derive(Debug, Default, Clone)] pub struct Bincode; impl DeSerializer for Bincode { - fn serialize(&self, val: &T) -> Result, failure::Error> { + fn serialize(&self, val: &T) -> error::DeSerResult> { Ok(serialize(val)?) } - fn deserialize(&self, s: R) -> Result { + fn deserialize(&self, s: R) -> error::DeSerResult { Ok(deserialize_from(s)?) } } diff --git a/src/error.rs b/src/error.rs index a188a43..610af3d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,97 +2,66 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use failure::{Backtrace, Context, Fail}; -use std::fmt::{self, Display}; +/// An error returned by a DeSer implementor +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum DeSerError { + #[cfg(feature = "yaml_enc")] + /// An error occured with Yaml + #[error("An error with yaml occured")] + Yaml(#[from] serde_yaml::Error), + #[cfg(feature = "ron_enc")] + /// An error occured with Ron + #[error("An error with Ron occured")] + Ron(#[from] ron::Error), + #[cfg(feature = "bin_enc")] + /// An error occured with Bincode + #[error("An error with Bincode occured")] + Bincode(#[from] std::boxed::Box), + #[cfg(feature = "other_errors")] + /// An error occured with Bincode + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +/// An error returned by a Backend implementor +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum BackendError { + /// An error occured from the tempfile + #[error("An error while persisting the file occured")] + TempFile(#[from] tempfile::PersistError), + /// An I/O Error occured + #[error("An I/O Error occured")] + Io(#[from] std::io::Error), + /// An internal error to Rustbreak occured + #[error("An internal error to rustbreak occured, please report it to the maintainers")] + Internal(String), +} /// The different kinds of errors that can be returned -#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] +#[derive(Debug, thiserror::Error)] #[non_exhaustive] -pub enum RustbreakErrorKind { - /// A context error when a serialization failed - #[fail(display = "Could not serialize the value")] - Serialization, - /// A context error when a deserialization failed - #[fail(display = "Could not deserialize the value")] - Deserialization, +pub enum RustbreakError { + /// A context error when a DeSerialization failed + #[error("Could not deserialize the value")] + DeSerialization(#[from] DeSerError), /// This error is returned if the `Database` is poisoned. See /// `Database::write` for details - #[fail(display = "The database has been poisoned")] + #[error("The database has been poisoned")] Poison, /// An error in the backend happened - #[fail(display = "The backend has encountered an error")] - Backend, + #[error("The backend has encountered an error")] + Backend(#[from] BackendError), /// If `Database::write_safe` is used and the closure panics, this error is /// returned - #[fail(display = "The write operation paniced but got caught")] + #[error("The write operation paniced but got caught")] WritePanic, } -/// The main error type that gets returned for errors that happen while -/// interacting with a `Database`. -#[derive(Debug)] -pub struct RustbreakError { - inner: Context, -} - -impl Fail for RustbreakError { - fn cause(&self) -> Option<&dyn Fail> { - self.inner.cause() - } - - fn backtrace(&self) -> Option<&Backtrace> { - self.inner.backtrace() - } -} - -impl Display for RustbreakError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.inner, f) - } -} - -impl RustbreakError { - /// Get the kind of this error - pub fn kind(&self) -> RustbreakErrorKind { - *self.inner.get_context() - } -} - -impl From for RustbreakError { - fn from(kind: RustbreakErrorKind) -> Self { - Self { - inner: Context::new(kind), - } - } -} - -impl From> for RustbreakError { - fn from(inner: Context) -> Self { - Self { inner } - } -} - /// A simple type alias for errors pub type Result = std::result::Result; - -#[cfg(test)] -mod tests { - use super::{RustbreakError, RustbreakErrorKind}; - use failure::Context; - use std::any::Any; - - #[test] - fn static_errorkind_impl_any() { - let err = RustbreakErrorKind::Backend; - let boxed: Box = Box::new(err); - assert!(boxed.is::()); - } - - #[test] - fn static_error_impl_any() { - let context = RustbreakErrorKind::Serialization; - let err: RustbreakError = Context::new(context).into(); - let boxed: Box = Box::new(err); - assert!(boxed.is::()); - } -} +/// The type alias used for backends +pub type BackendResult = std::result::Result; +/// The type alias used for DeSers +pub type DeSerResult = std::result::Result; diff --git a/src/lib.rs b/src/lib.rs index 72399c9..3a3b467 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,13 +81,12 @@ //! ``` //! //! ```rust -//! # extern crate failure; //! # extern crate rustbreak; //! # use std::collections::HashMap; //! use rustbreak::{deser::Ron, MemoryDatabase}; //! //! # fn main() { -//! # let func = || -> Result<(), failure::Error> { +//! # let func = || -> Result<(), Box> { //! let db = MemoryDatabase::, Ron>::memory(HashMap::new())?; //! //! println!("Writing to Database"); @@ -108,13 +107,12 @@ //! //! Or alternatively: //! ```rust -//! # extern crate failure; //! # extern crate rustbreak; //! # use std::collections::HashMap; //! use rustbreak::{deser::Ron, MemoryDatabase}; //! //! # fn main() { -//! # let func = || -> Result<(), failure::Error> { +//! # let func = || -> Result<(), Box> { //! let db = MemoryDatabase::, Ron>::memory(HashMap::new())?; //! //! println!("Writing to Database"); @@ -137,9 +135,6 @@ //! fail case as [`error::RustbreakError`]. This means that you can now either //! continue bubbling up said error case, or handle it yourself. //! -//! You can simply call its `.kind()` method, giving you all the information you -//! need to continue. -//! //! ```rust //! use rustbreak::{deser::Ron, error::RustbreakError, MemoryDatabase}; //! let db = match MemoryDatabase::::memory(0) { @@ -194,7 +189,6 @@ //! [daybreak]: https://propublica.github.io/daybreak //! [examples]: https://github.com/TheNeikos/rustbreak/tree/master/examples //! [ron]: https://github.com/ron-rs/ron -//! [failure]: https://boats.gitlab.io/failure/intro.html //! [features]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#choosing-features pub mod backend; @@ -206,14 +200,11 @@ pub mod error; /// The `DeSerializer` trait used by serialization structs pub use crate::deser::DeSerializer; /// The general error used by the Rustbreak Module -pub use crate::error::RustbreakError; - use std::fmt::Debug; use std::ops::Deref; use std::path::PathBuf; use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use failure::ResultExt; use serde::de::DeserializeOwned; use serde::Serialize; @@ -221,7 +212,7 @@ use serde::Serialize; use crate::backend::MmapStorage; use crate::backend::{Backend, FileBackend, MemoryBackend, PathBackend}; -use crate::error::RustbreakErrorKind as ErrorKind; +pub use crate::error::*; /// The Central Database to Rustbreak. /// @@ -236,7 +227,7 @@ use crate::error::RustbreakErrorKind as ErrorKind; /// /// If the backend or the de/serialization panics, the database is poisoned. /// This means that any subsequent writes/reads will fail with an -/// [`error::RustbreakErrorKind::Poison`]. You can only recover from this by +/// [`error::RustbreakError::Poison`]. You can only recover from this by /// re-creating the Database Object. #[derive(Debug)] pub struct Database { @@ -261,7 +252,7 @@ where /// /// If you panic in the closure, the database is poisoned. This means that /// any subsequent writes/reads will fail with an - /// [`error::RustbreakErrorKind::Poison`]. You can only recover from + /// [`error::RustbreakError::Poison`]. You can only recover from /// this by re-creating the Database Object. /// /// If you do not have full control over the code being written, and cannot @@ -275,7 +266,6 @@ where /// # extern crate rustbreak; /// # extern crate serde; /// # extern crate tempfile; - /// # extern crate failure; /// use rustbreak::{deser::Ron, FileDatabase}; /// /// #[derive(Debug, Serialize, Deserialize, Clone)] @@ -284,7 +274,7 @@ where /// } /// /// # fn main() { - /// # let func = || -> Result<(), failure::Error> { + /// # let func = || -> Result<(), Box> { /// # let file = tempfile::tempfile()?; /// let db = FileDatabase::::from_file(file, Data { level: 0 })?; /// @@ -305,7 +295,7 @@ where where T: FnOnce(&mut Data) -> R, { - let mut lock = self.data.write().map_err(|_| ErrorKind::Poison)?; + let mut lock = self.data.write().map_err(|_| RustbreakError::Poison)?; Ok(task(&mut lock)) } @@ -329,7 +319,7 @@ where /// # Panics /// /// When the closure panics, it is caught and a - /// [`error::RustbreakErrorKind::WritePanic`] will be returned. + /// [`error::RustbreakError::WritePanic`] will be returned. /// /// # Examples /// @@ -338,10 +328,9 @@ where /// # extern crate rustbreak; /// # extern crate serde; /// # extern crate tempfile; - /// # extern crate failure; /// use rustbreak::{ /// deser::Ron, - /// error::{RustbreakError, RustbreakErrorKind}, + /// error::RustbreakError, /// FileDatabase, /// }; /// @@ -351,7 +340,7 @@ where /// } /// /// # fn main() { - /// # let func = || -> Result<(), failure::Error> { + /// # let func = || -> Result<(), Box> { /// # let file = tempfile::tempfile()?; /// let db = FileDatabase::::from_file(file, Data { level: 0 })?; /// @@ -362,8 +351,8 @@ where /// }) /// .expect_err("This should have been caught"); /// - /// match result.kind() { - /// RustbreakErrorKind::WritePanic => { + /// match result { + /// RustbreakError::WritePanic => { /// // We can now handle this, in this example we will just ignore it /// } /// e => { @@ -388,12 +377,12 @@ where where T: FnOnce(&mut Data) + std::panic::UnwindSafe, { - let mut lock = self.data.write().map_err(|_| ErrorKind::Poison)?; + let mut lock = self.data.write().map_err(|_| RustbreakError::Poison)?; let mut data = lock.clone(); std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| { task(&mut data); })) - .map_err(|_| ErrorKind::WritePanic)?; + .map_err(|_| RustbreakError::WritePanic)?; *lock = data; Ok(()) } @@ -407,19 +396,19 @@ where /// /// May return: /// - /// - [`error::RustbreakErrorKind::Backend`] + /// - [`error::RustbreakError::Backend`] /// /// # Panics /// /// If you panic in the closure, the database is poisoned. This means that /// any subsequent writes/reads will fail with an - /// [`error::RustbreakErrorKind::Poison`]. You can only recover from + /// [`error::RustbreakError::Poison`]. You can only recover from /// this by re-creating the Database Object. pub fn read(&self, task: T) -> error::Result where T: FnOnce(&Data) -> R, { - let mut lock = self.data.read().map_err(|_| ErrorKind::Poison)?; + let mut lock = self.data.read().map_err(|_| RustbreakError::Poison)?; Ok(task(&mut lock)) } @@ -435,7 +424,6 @@ where /// # extern crate rustbreak; /// # extern crate serde; /// # extern crate tempfile; - /// # extern crate failure; /// use rustbreak::{deser::Ron, FileDatabase}; /// /// #[derive(Debug, Serialize, Deserialize, Clone)] @@ -444,7 +432,7 @@ where /// } /// /// # fn main() { - /// # let func = || -> Result<(), failure::Error> { + /// # let func = || -> Result<(), Box> { /// # let file = tempfile::tempfile()?; /// let db = FileDatabase::::from_file(file, Data { level: 0 })?; /// @@ -461,7 +449,7 @@ where /// # } /// ``` pub fn borrow_data<'a>(&'a self) -> error::Result> { - self.data.read().map_err(|_| ErrorKind::Poison.into()) + self.data.read().map_err(|_| RustbreakError::Poison.into()) } /// Write lock the database and get access to the underlying struct. @@ -473,7 +461,7 @@ where /// /// If you panic while holding this reference, the database is poisoned. /// This means that any subsequent writes/reads will fail with an - /// [`error::RustbreakErrorKind::Poison`]. You can only recover from + /// [`error::RustbreakError::Poison`]. You can only recover from /// this by re-creating the Database Object. /// /// If you do not have full control over the code being written, and cannot @@ -487,7 +475,6 @@ where /// # extern crate rustbreak; /// # extern crate serde; /// # extern crate tempfile; - /// # extern crate failure; /// use rustbreak::{deser::Ron, FileDatabase}; /// /// #[derive(Debug, Serialize, Deserialize, Clone)] @@ -496,7 +483,7 @@ where /// } /// /// # fn main() { - /// # let func = || -> Result<(), failure::Error> { + /// # let func = || -> Result<(), Box> { /// # let file = tempfile::tempfile()?; /// let db = FileDatabase::::from_file(file, Data { level: 0 })?; /// @@ -514,26 +501,24 @@ where /// # } /// ``` pub fn borrow_data_mut<'a>(&'a self) -> error::Result> { - self.data.write().map_err(|_| ErrorKind::Poison.into()) + self.data.write().map_err(|_| RustbreakError::Poison.into()) } /// Load data from backend and return this data. fn load_from_backend(backend: &mut Back, deser: &DeSer) -> error::Result { - let new_data = deser - .deserialize(&backend.get_data()?[..]) - .context(ErrorKind::Deserialization)?; + let new_data = deser.deserialize(&backend.get_data()?[..])?; Ok(new_data) } /// Like [`Self::load`] but returns the write lock to data it used. fn load_get_data_lock(&self) -> error::Result> { - let mut backend_lock = self.backend.lock().map_err(|_| ErrorKind::Poison)?; + let mut backend_lock = self.backend.lock().map_err(|_| RustbreakError::Poison)?; let fresh_data = Self::load_from_backend(&mut backend_lock, &self.deser)?; drop(backend_lock); - let mut data_write_lock = self.data.write().map_err(|_| ErrorKind::Poison)?; + let mut data_write_lock = self.data.write().map_err(|_| RustbreakError::Poison)?; *data_write_lock = fresh_data; Ok(data_write_lock) } @@ -545,20 +530,17 @@ where /// Like [`Self::save`] but with explicit read (or write) lock to data. fn save_data_locked>(&self, lock: L) -> error::Result<()> { - let ser = self - .deser - .serialize(lock.deref()) - .context(ErrorKind::Serialization)?; + let ser = self.deser.serialize(lock.deref())?; drop(lock); - let mut backend = self.backend.lock().map_err(|_| ErrorKind::Poison)?; + let mut backend = self.backend.lock().map_err(|_| RustbreakError::Poison)?; backend.put_data(&ser)?; Ok(()) } /// Flush the data structure to the backend. pub fn save(&self) -> error::Result<()> { - let data = self.data.read().map_err(|_| ErrorKind::Poison)?; + let data = self.data.read().map_err(|_| RustbreakError::Poison)?; self.save_data_locked(data) } @@ -570,7 +552,7 @@ where let data = if load { self.load_get_data_lock()? } else { - self.data.write().map_err(|_| ErrorKind::Poison)? + self.data.write().map_err(|_| RustbreakError::Poison)? }; Ok(data.clone()) } @@ -579,7 +561,7 @@ where /// /// To save the data afterwards, call with `save` true. pub fn put_data(&self, new_data: Data, save: bool) -> error::Result<()> { - let mut data = self.data.write().map_err(|_| ErrorKind::Poison)?; + let mut data = self.data.write().map_err(|_| RustbreakError::Poison)?; *data = new_data; if save { self.save_data_locked(data) @@ -600,8 +582,10 @@ where /// Break a database into its individual parts. pub fn into_inner(self) -> error::Result<(Data, Back, DeSer)> { Ok(( - self.data.into_inner().map_err(|_| ErrorKind::Poison)?, - self.backend.into_inner().map_err(|_| ErrorKind::Poison)?, + self.data.into_inner().map_err(|_| RustbreakError::Poison)?, + self.backend + .into_inner() + .map_err(|_| RustbreakError::Poison)?, self.deser, )) } @@ -619,7 +603,6 @@ where /// # extern crate rustbreak; /// # extern crate serde; /// # extern crate tempfile; - /// # extern crate failure; /// use rustbreak::{deser::Ron, FileDatabase}; /// /// #[derive(Debug, Serialize, Deserialize, Clone)] @@ -628,7 +611,7 @@ where /// } /// /// # fn main() { - /// # let func = || -> Result<(), failure::Error> { + /// # let func = || -> Result<(), Box> { /// # let file = tempfile::tempfile()?; /// let db = FileDatabase::::from_file(file, Data { level: 0 })?; /// @@ -650,7 +633,7 @@ where /// # } /// ``` pub fn try_clone(&self) -> error::Result> { - let lock = self.data.read().map_err(|_| ErrorKind::Poison)?; + let lock = self.data.read().map_err(|_| RustbreakError::Poison)?; Ok(Database { data: RwLock::new(lock.clone()), @@ -698,7 +681,7 @@ where let (mut backend, exists) = FileBackend::from_path_or_create(path)?; let deser = DeSer::default(); if !exists { - let ser = deser.serialize(&data).context(ErrorKind::Serialization)?; + let ser = deser.serialize(&data)?; backend.put_data(&ser)?; } @@ -732,7 +715,7 @@ where } else { let data = closure(); - let ser = deser.serialize(&data).context(ErrorKind::Serialization)?; + let ser = deser.serialize(&data)?; backend.put_data(&ser)?; data @@ -759,7 +742,7 @@ where let (mut backend, exists) = FileBackend::from_path_or_create(path)?; let deser = DeSer::default(); if !exists { - let ser = deser.serialize(&data).context(ErrorKind::Serialization)?; + let ser = deser.serialize(&data)?; backend.put_data(&ser)?; } @@ -833,7 +816,7 @@ where let (mut backend, exists) = PathBackend::from_path_or_create(path)?; let deser = DeSer::default(); if !exists { - let ser = deser.serialize(&data).context(ErrorKind::Serialization)?; + let ser = deser.serialize(&data)?; backend.put_data(&ser)?; } @@ -866,7 +849,7 @@ where } else { let data = closure(); - let ser = deser.serialize(&data).context(ErrorKind::Serialization)?; + let ser = deser.serialize(&data)?; backend.put_data(&ser)?; data @@ -890,7 +873,7 @@ where let (mut backend, exists) = PathBackend::from_path_or_create(path)?; let deser = DeSer::default(); if !exists { - let ser = deser.serialize(&data).context(ErrorKind::Serialization)?; + let ser = deser.serialize(&data)?; backend.put_data(&ser)?; } @@ -1026,7 +1009,6 @@ where #[cfg(test)] mod tests { use super::*; - use failure::Fail; use std::collections::HashMap; use tempfile::NamedTempFile; @@ -1154,7 +1136,7 @@ mod tests { panic!("Panic should be catched") }) .expect_err("Did not error on panic in safe write!"); - assert_eq!(ErrorKind::WritePanic, err.kind()); + assert!(matches!(err, RustbreakError::WritePanic)); assert_eq!( "Hello World", @@ -1436,13 +1418,11 @@ mod tests { file_path.push("rustbreak_path_db.db"); let err = TestDb::::load_from_path(file_path) .expect_err("should fail with file not found"); - assert_eq!(ErrorKind::Backend, err.kind()); - let io_err = err - .cause() - .expect("error has no cause") - .downcast_ref::() - .expect("error is not an io error"); - assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + if let RustbreakError::Backend(BackendError::Io(io_err)) = &err { + assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + } else { + panic!("Wrong error: {}", err) + }; dir.close().expect("Error while deleting temp directory!"); } @@ -1455,13 +1435,11 @@ mod tests { file_path.push("rustbreak_path_db.db"); let err = TestDb::::load_from_path(file_path) .expect_err("should fail with file not found"); - assert_eq!(ErrorKind::Backend, err.kind()); - let io_err = err - .cause() - .expect("error has no cause") - .downcast_ref::() - .expect("error is not an io error"); - assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + if let RustbreakError::Backend(BackendError::Io(io_err)) = &err { + assert_eq!(std::io::ErrorKind::NotFound, io_err.kind()); + } else { + panic!("Wrong error: {}", err) + }; dir.close().expect("Error while deleting temp directory!"); }