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 { message: String },
30 Syntax { message: String, position: SourcePosition },
31 UndefinedVariable { name: String, position: SourcePosition },
32 UndefinedFilter { name: String, position: SourcePosition },
33 UndefinedTemplate { name: String },
34 Render { message: String },
35 Type { message: String },
36}
37
38#[derive(Debug)]
40pub struct Error {
41 inner: Box<ErrorInner>,
42}
43
44#[derive(Debug)]
45struct ErrorInner {
46 kind: ErrorKind,
47 source: Option<String>,
48}
49
50impl Error {
51 fn new(kind: ErrorKind) -> Self {
52 Self {
53 inner: Box::new(ErrorInner {
54 kind,
55 source: None,
56 }),
57 }
58 }
59
60 pub fn parse(message: impl Into<String>) -> Self {
62 Self::new(ErrorKind::Parse {
63 message: message.into(),
64 })
65 }
66
67 pub fn syntax(message: impl Into<String>, line: usize, column: usize) -> Self {
69 Self::new(ErrorKind::Syntax {
70 message: message.into(),
71 position: SourcePosition::new(line, column),
72 })
73 }
74
75 pub fn undefined_variable(name: impl Into<String>, line: usize, column: usize) -> Self {
77 Self::new(ErrorKind::UndefinedVariable {
78 name: name.into(),
79 position: SourcePosition::new(line, column),
80 })
81 }
82
83 pub fn undefined_filter(name: impl Into<String>, line: usize, column: usize) -> Self {
85 Self::new(ErrorKind::UndefinedFilter {
86 name: name.into(),
87 position: SourcePosition::new(line, column),
88 })
89 }
90
91 pub fn undefined_template(name: impl Into<String>) -> Self {
93 Self::new(ErrorKind::UndefinedTemplate {
94 name: name.into(),
95 })
96 }
97
98 pub fn render(message: impl Into<String>) -> Self {
100 Self::new(ErrorKind::Render {
101 message: message.into(),
102 })
103 }
104
105 pub fn r#type(message: impl Into<String>) -> Self {
107 Self::new(ErrorKind::Type {
108 message: message.into(),
109 })
110 }
111
112 pub fn with_source(mut self, source: impl Into<String>) -> Self {
114 self.inner.source = Some(source.into());
115 self
116 }
117}
118
119#[cfg(feature = "std")]
120impl From<std::io::Error> for Error {
121 fn from(err: std::io::Error) -> Self {
122 Self::new(ErrorKind::Render {
123 message: err.to_string(),
124 })
125 }
126}
127
128impl fmt::Display for Error {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 match &self.inner.kind {
131 ErrorKind::Parse {
132 message,
133 } => {
134 write!(f, "parse error: {message}")
135 }
136 ErrorKind::Syntax {
137 message,
138 position,
139 } => {
140 write!(f, "syntax error at {}:{}: {message}", position.line, position.column)
141 }
142 ErrorKind::UndefinedVariable {
143 name,
144 position,
145 } => {
146 write!(f, "undefined variable `{name}` at {}:{}", position.line, position.column)
147 }
148 ErrorKind::UndefinedFilter {
149 name,
150 position,
151 } => {
152 write!(f, "undefined filter `{name}` at {}:{}", position.line, position.column)
153 }
154 ErrorKind::UndefinedTemplate {
155 name,
156 } => {
157 write!(f, "undefined template `{name}`")
158 }
159 ErrorKind::Render {
160 message,
161 } => {
162 write!(f, "render error: {message}")
163 }
164 ErrorKind::Type {
165 message,
166 } => {
167 write!(f, "type error: {message}")
168 }
169 }
170 }
171}
172
173impl core::error::Error for Error {
174 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
175 None
176 }
177}
178
179#[derive(Debug)]
181pub struct SerdeError(pub String);
182
183impl fmt::Display for SerdeError {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 write!(f, "{}", self.0)
186 }
187}
188
189impl core::error::Error for SerdeError {}
190
191#[cfg(feature = "std")]
192impl ser::Error for SerdeError {
193 fn custom<T: fmt::Display>(msg: T) -> Self {
194 SerdeError(msg.to_string())
195 }
196}