1use std::borrow;
2use std::error;
3use std::fmt;
4use std::result;
5
6use super::ErrorClone;
7use super::Trace;
8
9pub type Result<T> = result::Result<T, Error>;
11
12type BoxedError = Box<ErrorClone>;
13
14#[derive(Debug, Clone)]
16pub struct Error {
17 inner: Box<InnerError>,
18}
19
20#[derive(Debug, Clone)]
25struct InnerError {
26 msg: borrow::Cow<'static, str>,
27 user_backtrace: Vec<Trace>,
28 cause: Option<BoxedError>,
29}
30
31impl Error {
32 pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
34 Self::with_msg_cow(msg.into())
35 }
36
37 fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
38 let error = InnerError {
39 msg,
40 user_backtrace: vec![Trace::empty()],
41 cause: None,
42 };
43 Self {
44 inner: Box::new(error),
45 }
46 }
47
48 pub fn trace<T>(self, trace: T) -> Self
50 where
51 T: Into<borrow::Cow<'static, str>>,
52 {
53 self.trace_trace(trace.into())
54 }
55
56 fn trace_trace(mut self, trace: borrow::Cow<'static, str>) -> Self {
57 let trace = Trace::new(trace);
58 self.inner.user_backtrace.push(trace);
59 self
60 }
61
62 pub fn context<K, V>(self, key: K, value: V) -> Self
66 where
67 K: Into<borrow::Cow<'static, str>>,
68 V: Into<borrow::Cow<'static, str>>,
69 {
70 self.context_cow_string(key.into(), value.into())
71 }
72
73 fn context_cow_string(
74 mut self,
75 key: borrow::Cow<'static, str>,
76 value: borrow::Cow<'static, str>,
77 ) -> Self {
78 self.inner
79 .user_backtrace
80 .last_mut()
81 .expect("always a trace available")
82 .append_context(key, value);
83 self
84 }
85
86 pub fn cause<E: ErrorClone>(self, cause: E) -> Self {
88 let cause = Box::new(cause);
89 self.cause_error(cause)
90 }
91
92 fn cause_error(mut self, cause: BoxedError) -> Self {
93 let cause = Some(cause);
94 self.inner.cause = cause;
95 self
96 }
97
98 pub fn into_err<T, E>(self) -> ::std::result::Result<T, E>
100 where
101 Self: Into<E>,
102 {
103 let err = self.into();
104 Err(err)
105 }
106}
107
108const ERROR_DESCRIPTION: &str = "liquid";
109
110impl fmt::Display for Error {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
113 for trace in &self.inner.user_backtrace {
114 if let Some(trace) = trace.get_trace() {
115 writeln!(f, "from: {}", trace)?;
116 }
117 if !trace.get_context().is_empty() {
118 writeln!(f, " with:")?;
119 }
120 for &(ref key, ref value) in trace.get_context() {
121 writeln!(f, " {}={}", key, value)?;
122 }
123 }
124 Ok(())
125 }
126}
127
128impl error::Error for Error {
129 fn description(&self) -> &str {
130 ERROR_DESCRIPTION
131 }
132
133 fn cause(&self) -> Option<&error::Error> {
134 self.inner.cause.as_ref().and_then(|e| e.cause())
135 }
136}