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
//! # How to create opaque error types for public APIs
//!
//! While creating error types on top of Rust enums allows for great
//! flexibility inside your code, that same flexibility may not be
//! desired in a public API. Public enums also expose their variants
//! and the variant's fields, allowing consumers to rely on those
//! details.
//!
//! The most conservative approach is to create an *opaque* error type
//! that only implements a handful of traits. This can be done by
//! deriving `Snafu` for a newtype struct that contains another SNAFU
//! error:
//!
//! ```rust
//! # use snafu::Snafu;
//! #[derive(Debug, Snafu)]
//! pub struct Error(InnerError);
//!
//! // That's all it takes! The rest is demonstration of how to use it.
//!
//! pub fn login(id: i32) -> Result<(), Error> {
//!     validate_user(id)?;
//!     is_user_locked(id)?;
//!     Ok(())
//! }
//!
//! #[derive(Debug, Snafu)]
//! enum InnerError {
//!     #[snafu(display("User ID {} is invalid", user_id))]
//!     InvalidUser { user_id: i32 },
//!     #[snafu(display("User ID {} is locked", user_id))]
//!     UserLocked { user_id: i32 },
//! }
//!
//! fn validate_user(user_id: i32) -> Result<(), InnerError> {
//!     InvalidUser { user_id }.fail()
//! }
//!
//! fn is_user_locked(user_id: i32) -> Result<(), InnerError> {
//!     UserLocked { user_id }.fail()
//! }
//! ```
//!
//! ## Delegated traits
//!
//! - [`Error`][]
//! - [`Display`][]
//! - [`ErrorCompat`][]
//!
//! [`Error`]: std::error::Error
//! [`Display`]: std::fmt::Display
//! [`ErrorCompat`]: crate::ErrorCompat
//!
//! ## `From`
//!
//! The `From` trait is also implemented to convert the inner type into
//! the opaque type. This makes converting from internal errors to public
//! errors very easy.