]> git.proxmox.com Git - cargo.git/blob - vendor/failure/src/context.rs
New upstream version 0.33.0
[cargo.git] / vendor / failure / src / context.rs
1 use core::fmt::{self, Debug, Display};
2
3 use Fail;
4
5 without_std! {
6 /// An error with context around it.
7 ///
8 /// The context is intended to be a human-readable, user-facing explanation for the
9 /// error that has occurred. The underlying error is not assumed to be end-user-relevant
10 /// information.
11 ///
12 /// The `Display` impl for `Context` only prints the human-readable context, while the
13 /// `Debug` impl also prints the underlying error.
14 pub struct Context<D: Display + Send + Sync + 'static> {
15 context: D,
16 }
17
18 impl<D: Display + Send + Sync + 'static> Context<D> {
19 /// Creates a new context without an underlying error message.
20 pub fn new(context: D) -> Context<D> {
21 Context { context }
22 }
23
24 /// Returns a reference to the context provided with this error.
25 pub fn get_context(&self) -> &D {
26 &self.context
27 }
28
29 /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context.
30 pub fn map<F, T>(self, op: F) -> Context<T>
31 where F: FnOnce(D) -> T,
32 T: Display + Send + Sync + 'static
33 {
34 Context {
35 context: op(self.context),
36 }
37 }
38
39 pub(crate) fn with_err<E: Fail>(context: D, _: E) -> Context<D> {
40 Context { context }
41 }
42 }
43
44 impl<D: Display + Send + Sync + 'static> Fail for Context<D> { }
45
46 impl<D: Display + Send + Sync + 'static> Debug for Context<D> {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 write!(f, "{}", self.context)
49 }
50 }
51
52 impl<D: Display + Send + Sync + 'static> Display for Context<D> {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 write!(f, "{}", self.context)
55 }
56 }
57
58 #[test]
59 fn test_map() {
60 let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s));
61 assert_eq!(ctx.context, String::from("a string with some more stuff"));
62 }
63 }
64
65 with_std! {
66 use {Error, Backtrace};
67
68 /// An error with context around it.
69 ///
70 /// The context is intended to be a human-readable, user-facing explanation for the
71 /// error that has occurred. The underlying error is not assumed to be end-user-relevant
72 /// information.
73 ///
74 /// The `Display` impl for `Context` only prints the human-readable context, while the
75 /// `Debug` impl also prints the underlying error.
76 pub struct Context<D: Display + Send + Sync + 'static> {
77 context: D,
78 failure: Either<Backtrace, Error>,
79 }
80
81 impl<D: Display + Send + Sync + 'static> Context<D> {
82 /// Creates a new context without an underlying error message.
83 pub fn new(context: D) -> Context<D> {
84 let failure = Either::This(Backtrace::new());
85 Context { context, failure }
86 }
87
88 /// Returns a reference to the context provided with this error.
89 pub fn get_context(&self) -> &D {
90 &self.context
91 }
92
93 /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context.
94 pub fn map<F, T>(self, op: F) -> Context<T>
95 where F: FnOnce(D) -> T,
96 T: Display + Send + Sync + 'static
97 {
98 Context {
99 context: op(self.context),
100 failure: self.failure,
101 }
102 }
103
104 pub(crate) fn with_err<E: Into<Error>>(context: D, error: E) -> Context<D> {
105 let failure = Either::That(error.into());
106 Context { context, failure }
107 }
108 }
109
110 impl<D: Display + Send + Sync + 'static> Fail for Context<D> {
111 fn name(&self) -> Option<&str> {
112 self.failure.as_cause().and_then(|x| x.name())
113 }
114
115 fn cause(&self) -> Option<&Fail> {
116 self.failure.as_cause()
117 }
118
119 fn backtrace(&self) -> Option<&Backtrace> {
120 Some(self.failure.backtrace())
121 }
122 }
123
124 impl<D: Display + Send + Sync + 'static> Debug for Context<D> {
125 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126 write!(f, "{:?}\n\n{}", self.failure, self.context)
127 }
128 }
129
130 impl<D: Display + Send + Sync + 'static> Display for Context<D> {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(f, "{}", self.context)
133 }
134 }
135
136 enum Either<A, B> {
137 This(A),
138 That(B),
139 }
140
141 impl Either<Backtrace, Error> {
142 fn backtrace(&self) -> &Backtrace {
143 match *self {
144 Either::This(ref backtrace) => backtrace,
145 Either::That(ref error) => error.backtrace(),
146 }
147 }
148
149 fn as_cause(&self) -> Option<&Fail> {
150 match *self {
151 Either::This(_) => None,
152 Either::That(ref error) => Some(error.as_fail())
153 }
154 }
155 }
156
157 impl Debug for Either<Backtrace, Error> {
158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159 match *self {
160 Either::This(ref backtrace) => write!(f, "{:?}", backtrace),
161 Either::That(ref error) => write!(f, "{:?}", error),
162 }
163 }
164 }
165
166 #[test]
167 fn test_map() {
168 let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s));
169 assert_eq!(ctx.context, String::from("a string with some more stuff"));
170 }
171 }
172
173 impl<D> From<D> for Context<D>
174 where
175 D: Display + Send + Sync + 'static,
176 {
177 fn from(display: D) -> Context<D> {
178 Context::new(display)
179 }
180 }