1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#![deny(warnings)]
#![deny(missing_docs)]
#![deny(unsafe_code)]
#![allow(clippy::collapsible_else_if)]
//! OneErr to rule them all.
//!
//! There are some great error helper crates out there.
//! My favorites are [thiserror](https://crates.io/crates/thiserror) and
//! [anyhow](https://crates.io/crates/anyhow).
//!
//! But sometimes you just need something different. The `thiserror` crate can
//! over time lead to giant trees of nested error enums, while `anyhow` is
//! difficult to match on.
//!
//! Sometimes you need to interoperate with std::io::Error, but that type is
//! awkward to construct, not `Clone`, and cannot be serialized.
//!
//! `OneErr` is a newtype over std::io::Error, but makes it clonable,
//! serializable, and hopefully more ergonomic.
//!
//! ### std::io::ErrorKind Matching
//!
//! ```rust
//! use one_err::*;
//!
//! for res in [
//!     Ok("not-error"),
//!     Err(OneErr::from(std::io::ErrorKind::InvalidInput)),
//!     Err(OneErr::from(std::io::ErrorKind::ConnectionRefused)),
//! ] {
//!     match res.map_err(|e| e.kind()) {
//!         Ok(ok) => assert_eq!("not-error", ok),
//!         Err(std::io::ErrorKind::InvalidInput) => (),
//!         Err(std::io::ErrorKind::ConnectionRefused) => (),
//!         oth => panic!("unexpected: {:?}", oth),
//!     }
//! }
//! ```
//!
//! ### ErrNo Matching
//!
//! ```rust
//! use one_err::*;
//!
//! for res in [
//!     Ok("not-error"),
//!     Err(OneErr::from(ErrNo::NoData)),
//!     Err(OneErr::from(ErrNo::Proto)),
//! ] {
//!     match res.map_err(|e| e.errno()) {
//!         Ok(ok) => assert_eq!("not-error", ok),
//!         Err(ErrNo::NoData) => (),
//!         Err(ErrNo::Proto) => (),
//!         oth => panic!("unexpected: {:?}", oth),
//!     }
//! }
//! ```
//!
//! ### Custom Matching
//!
//! ```rust
//! use one_err::*;
//!
//! const ERR_FOO: &str = "FOO";
//! const ERR_BAR: &str = "BAR";
//!
//! for res in [
//!     Ok("not-error"),
//!     Err(OneErr::with_message(ERR_FOO, "foo test")),
//!     Err(OneErr::with_message(ERR_BAR, "bar test")),
//! ] {
//!     match res.as_ref().map_err(|e| (e.str_kind(), e)) {
//!         Ok(ok) => assert_eq!("not-error", *ok),
//!         Err((ERR_FOO, e)) => assert_eq!("foo test", e.get_message().unwrap()),
//!         Err((ERR_BAR, e)) => assert_eq!("bar test", e.get_message().unwrap()),
//!         oth => panic!("unexpected: {:?}", oth),
//!     }
//! }
//! ```
//!
//! ### std::io Interoperability
//!
//! ```rust
//! use one_err::*;
//! use std::io::Read;
//!
//! const CUSTOM_ERR: &str = "CustomError";
//!
//! /// My custom Read that always errors.
//! pub struct ErrReader;
//!
//! impl Read for ErrReader {
//!     fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
//!         Err(OneErr::new(CUSTOM_ERR).into())
//!     }
//! }
//!
//! assert_eq!(
//!     r#"{"error":"CustomError"}"#,
//!     &ErrReader.read(&mut []).unwrap_err().to_string(),
//! );
//! ```
//!
//! ### Serialization and Parsing
//!
//! ```rust
//! use one_err::*;
//!
//! const CUSTOM_ERR: &str = "CustomError";
//!
//! let err = OneErr::new(CUSTOM_ERR);
//! let enc = err.to_string();
//!
//! assert_eq!(
//!     r#"{"error":"CustomError"}"#,
//!     &enc,
//! );
//!
//! let dec: OneErr = enc.parse().unwrap();
//! assert_eq!(err, dec);
//! ```

mod errno_;
pub use errno_::*;

pub mod io_error;

mod value;
pub use value::*;

mod inner;
use inner::*;

mod util;
use util::*;

mod one_err;
pub use crate::one_err::*;

#[cfg(test)]
mod test;