loose_liquid_core/error/
error.rs1use std::error;
2use std::fmt;
3use std::result;
4
5use super::ErrorClone;
6use super::Trace;
7
8pub type Result<T, E = Error> = result::Result<T, E>;
10
11type BoxedError = Box<dyn ErrorClone>;
12
13#[derive(Debug, Clone)]
15pub struct Error {
16 inner: Box<InnerError>,
17}
18
19impl Error {
20 pub fn kind(&self) -> &ErrorKind {
22 &self.inner.kind
23 }
24}
25
26#[derive(Debug, Clone)]
31struct InnerError {
32 kind: ErrorKind,
33 user_backtrace: Vec<Trace>,
34 cause: Option<BoxedError>,
35}
36
37impl Error {
38 pub fn unknown_variable<S: Into<crate::model::KString>>(name: S) -> Self {
40 Self::with_kind(ErrorKind::UnknownVariable).context("requested variable", name)
41 }
42
43 pub fn with_kind(kind: ErrorKind) -> Self {
45 let error = InnerError {
46 kind,
47 user_backtrace: vec![Trace::empty()],
48 cause: None,
49 };
50 Self {
51 inner: Box::new(error),
52 }
53 }
54
55 pub fn with_msg<S: Into<crate::model::KString>>(msg: S) -> Self {
57 Self::with_msg_cow(msg.into())
58 }
59
60 fn with_msg_cow(msg: crate::model::KString) -> Self {
61 let error = InnerError {
62 kind: ErrorKind::Custom(msg),
63 user_backtrace: vec![Trace::empty()],
64 cause: None,
65 };
66 Self {
67 inner: Box::new(error),
68 }
69 }
70
71 pub fn trace<T>(self, trace: T) -> Self
73 where
74 T: Into<crate::model::KString>,
75 {
76 self.trace_trace(trace.into())
77 }
78
79 fn trace_trace(mut self, trace: crate::model::KString) -> Self {
80 let trace = Trace::new(trace);
81 self.inner.user_backtrace.push(trace);
82 self
83 }
84
85 pub fn context<K, V>(self, key: K, value: V) -> Self
89 where
90 K: Into<crate::model::KString>,
91 V: Into<crate::model::KString>,
92 {
93 self.context_cow_string(key.into(), value.into())
94 }
95
96 fn context_cow_string(
97 mut self,
98 key: crate::model::KString,
99 value: crate::model::KString,
100 ) -> Self {
101 self.inner
102 .user_backtrace
103 .last_mut()
104 .expect("always a trace available")
105 .append_context(key, value);
106 self
107 }
108
109 pub fn cause<E: ErrorClone>(self, cause: E) -> Self {
111 let cause = Box::new(cause);
112 self.cause_error(cause)
113 }
114
115 fn cause_error(mut self, cause: BoxedError) -> Self {
116 let cause = Some(cause);
117 self.inner.cause = cause;
118 self
119 }
120
121 pub fn into_err<T, E>(self) -> ::std::result::Result<T, E>
123 where
124 Self: Into<E>,
125 {
126 let err = self.into();
127 Err(err)
128 }
129}
130
131const ERROR_DESCRIPTION: &str = "liquid";
132
133impl fmt::Display for Error {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.kind)?;
136 for trace in &self.inner.user_backtrace {
137 if let Some(trace) = trace.get_trace() {
138 writeln!(f, "from: {}", trace)?;
139 }
140 if !trace.get_context().is_empty() {
141 writeln!(f, " with:")?;
142 }
143 for (key, value) in trace.get_context() {
144 writeln!(f, " {}={}", key, value)?;
145 }
146 }
147 Ok(())
148 }
149}
150
151impl error::Error for Error {
152 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
153 self.inner.cause.as_ref().and_then(|e| e.source())
154 }
155}
156
157#[derive(Debug, Clone)]
159pub enum ErrorKind {
160 UnknownIndex,
162 UnknownVariable,
164 Custom(crate::model::KString),
166}
167
168impl std::fmt::Display for ErrorKind {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 match self {
171 ErrorKind::UnknownIndex => f.write_str("Unknown index"),
172 ErrorKind::UnknownVariable => f.write_str("Unknown variable"),
173 ErrorKind::Custom(s) => s.fmt(f),
174 }
175 }
176}