1#[cfg(any(feature = "std", test))]
4use alloc::string::ToString;
5use alloc::{boxed::Box, string::String};
6use core::fmt;
7
8#[cfg(feature = "std")]
9use serde::ser;
10
11#[derive(Clone, Debug, PartialEq)]
13pub struct SourcePosition {
14 pub line: usize,
15 pub column: usize,
16}
17
18impl SourcePosition {
19 pub fn new(line: usize, column: usize) -> Self {
20 Self {
21 line,
22 column,
23 }
24 }
25}
26
27#[derive(Debug)]
28enum ErrorKind {
29 Parse {
30 message: String,
31 },
32 Syntax {
33 message: String,
34 position: SourcePosition,
35 },
36 UndefinedVariable {
37 name: String,
38 position: SourcePosition,
39 },
40 UndefinedFilter {
41 name: String,
42 position: SourcePosition,
43 },
44 UndefinedTemplate {
45 name: String,
46 },
47 Render {
48 message: String,
49 },
50 Type {
51 message: String,
52 },
53 #[cfg(feature = "std")]
54 Io(std::io::Error),
55}
56
57#[derive(Debug)]
59pub struct Error {
60 inner: Box<ErrorInner>,
61}
62
63#[derive(Debug)]
64struct ErrorInner {
65 kind: ErrorKind,
66 source: Option<String>,
67}
68
69impl Error {
70 fn new(kind: ErrorKind) -> Self {
71 Self {
72 inner: Box::new(ErrorInner {
73 kind,
74 source: None,
75 }),
76 }
77 }
78
79 pub fn parse(message: impl Into<String>) -> Self {
81 Self::new(ErrorKind::Parse {
82 message: message.into(),
83 })
84 }
85
86 pub fn syntax(message: impl Into<String>, line: usize, column: usize) -> Self {
88 Self::new(ErrorKind::Syntax {
89 message: message.into(),
90 position: SourcePosition::new(line, column),
91 })
92 }
93
94 pub fn undefined_variable(name: impl Into<String>, line: usize, column: usize) -> Self {
96 Self::new(ErrorKind::UndefinedVariable {
97 name: name.into(),
98 position: SourcePosition::new(line, column),
99 })
100 }
101
102 pub fn undefined_filter(name: impl Into<String>, line: usize, column: usize) -> Self {
104 Self::new(ErrorKind::UndefinedFilter {
105 name: name.into(),
106 position: SourcePosition::new(line, column),
107 })
108 }
109
110 pub fn undefined_template(name: impl Into<String>) -> Self {
112 Self::new(ErrorKind::UndefinedTemplate {
113 name: name.into(),
114 })
115 }
116
117 pub fn render(message: impl Into<String>) -> Self {
119 Self::new(ErrorKind::Render {
120 message: message.into(),
121 })
122 }
123
124 pub fn r#type(message: impl Into<String>) -> Self {
126 Self::new(ErrorKind::Type {
127 message: message.into(),
128 })
129 }
130
131 pub fn with_source(mut self, source: impl Into<String>) -> Self {
133 self.inner.source = Some(source.into());
134 self
135 }
136}
137
138#[cfg(feature = "std")]
139impl From<std::io::Error> for Error {
140 fn from(err: std::io::Error) -> Self {
141 Self::new(ErrorKind::Io(err))
142 }
143}
144
145impl fmt::Display for Error {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match &self.inner.kind {
148 ErrorKind::Parse {
149 message,
150 } => {
151 write!(f, "parse error: {message}")
152 }
153 ErrorKind::Syntax {
154 message,
155 position,
156 } => {
157 write!(f, "syntax error at {}:{}: {message}", position.line, position.column)
158 }
159 ErrorKind::UndefinedVariable {
160 name,
161 position,
162 } => {
163 write!(f, "undefined variable `{name}` at {}:{}", position.line, position.column)
164 }
165 ErrorKind::UndefinedFilter {
166 name,
167 position,
168 } => {
169 write!(f, "undefined filter `{name}` at {}:{}", position.line, position.column)
170 }
171 ErrorKind::UndefinedTemplate {
172 name,
173 } => {
174 write!(f, "undefined template `{name}`")
175 }
176 ErrorKind::Render {
177 message,
178 } => {
179 write!(f, "render error: {message}")
180 }
181 ErrorKind::Type {
182 message,
183 } => {
184 write!(f, "type error: {message}")
185 }
186 #[cfg(feature = "std")]
187 ErrorKind::Io(err) => {
188 write!(f, "I/O error: {err}")
189 }
190 }
191 }
192}
193
194#[cfg(feature = "std")]
195impl std::error::Error for Error {
196 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
197 match &self.inner.kind {
198 ErrorKind::Io(err) => Some(err),
199 _ => None,
200 }
201 }
202}
203
204#[derive(Debug)]
206pub struct SerdeError(pub String);
207
208impl fmt::Display for SerdeError {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 write!(f, "{}", self.0)
211 }
212}
213
214#[cfg(feature = "std")]
215impl std::error::Error for SerdeError {}
216
217#[cfg(feature = "std")]
218impl ser::Error for SerdeError {
219 fn custom<T: fmt::Display>(msg: T) -> Self {
220 SerdeError(msg.to_string())
221 }
222}