1use std::fmt;
3use std::sync::{Arc, Mutex};
4
5use deser_core::de::DeserializeDriver;
6use deser_core::{Error, ErrorKind, State};
7use deser_path::{Path, PathLayer};
8
9use crate::Violation;
10
11#[derive(Debug, Clone, PartialEq)]
17pub struct Issue {
18 kind: ErrorKind,
19 message: String,
20 path: Option<String>,
21 offset: Option<usize>,
22 line_column: Option<(usize, usize)>,
23 violation: Option<Violation>,
24}
25
26impl Issue {
27 pub fn from_error(err: &Error) -> Issue {
33 Issue {
34 kind: err.kind(),
35 message: err.message().to_string(),
36 path: err.attachment::<Path>().map(|path| path.to_string()),
37 offset: err.offset(),
38 line_column: err.line().zip(err.column()),
39 violation: err.attachment::<Violation>().cloned(),
40 }
41 }
42
43 pub fn kind(&self) -> ErrorKind {
45 self.kind
46 }
47
48 pub fn message(&self) -> &str {
50 &self.message
51 }
52
53 pub fn path(&self) -> Option<&str> {
57 self.path.as_deref()
58 }
59
60 pub fn offset(&self) -> Option<usize> {
62 self.offset
63 }
64
65 pub fn line(&self) -> Option<usize> {
67 self.line_column.map(|x| x.0)
68 }
69
70 pub fn column(&self) -> Option<usize> {
72 self.line_column.map(|x| x.1)
73 }
74
75 pub fn violation(&self) -> Option<&Violation> {
77 self.violation.as_ref()
78 }
79}
80
81impl fmt::Display for Issue {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self.path {
84 Some(ref path) if !path.is_empty() => write!(f, "{}: {}", path, self.message)?,
85 _ => f.write_str(&self.message)?,
86 }
87 match (self.line_column, self.offset) {
88 (Some((line, column)), _) => write!(f, " (at line {} column {})", line, column),
89 (None, Some(offset)) => write!(f, " (at offset {})", offset),
90 (None, None) => Ok(()),
91 }
92 }
93}
94
95#[derive(Debug, Clone, Default, PartialEq)]
101pub struct Report {
102 issues: Vec<Issue>,
103}
104
105impl Report {
106 pub fn new() -> Report {
108 Report::default()
109 }
110
111 pub fn from_error(err: &Error) -> Report {
113 Report {
114 issues: err.errors().map(Issue::from_error).collect(),
115 }
116 }
117
118 pub fn is_empty(&self) -> bool {
120 self.issues.is_empty()
121 }
122
123 pub fn len(&self) -> usize {
125 self.issues.len()
126 }
127
128 pub fn issues(&self) -> &[Issue] {
130 &self.issues
131 }
132
133 pub fn iter(&self) -> std::slice::Iter<'_, Issue> {
135 self.issues.iter()
136 }
137
138 pub fn push(&mut self, issue: Issue) {
140 self.issues.push(issue);
141 }
142
143 pub fn resolve_positions(&mut self, source: &[u8]) {
150 for issue in self.issues.iter_mut() {
151 if let (Some(offset), None) = (issue.offset, issue.line_column) {
152 let pos = deser_core::Position::of(source, offset);
153 issue.line_column = Some((pos.line, pos.column));
154 }
155 }
156 }
157}
158
159impl<'a> IntoIterator for &'a Report {
160 type Item = &'a Issue;
161 type IntoIter = std::slice::Iter<'a, Issue>;
162
163 fn into_iter(self) -> Self::IntoIter {
164 self.issues.iter()
165 }
166}
167
168impl fmt::Display for Report {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 for (idx, issue) in self.issues.iter().enumerate() {
171 if idx > 0 {
172 writeln!(f)?;
173 }
174 fmt::Display::fmt(issue, f)?;
175 }
176 Ok(())
177 }
178}
179
180impl std::error::Error for Report {}
181
182#[derive(Debug, Default)]
184pub(crate) struct ReportHandle(Option<Arc<Mutex<Vec<Issue>>>>);
185
186impl ReportHandle {
187 pub(crate) fn report(err: &Error, state: &State) {
189 if let Some(ReportHandle(Some(issues))) = state.get::<ReportHandle>() {
190 let mut issues = issues.lock().unwrap_or_else(|err| err.into_inner());
191 issues.extend(err.errors().map(Issue::from_error));
192 }
193 }
194}
195
196#[derive(Debug, Default)]
232pub struct Validation {
233 issues: Arc<Mutex<Vec<Issue>>>,
234 max_errors: Option<usize>,
235}
236
237#[derive(Debug)]
239pub struct Outcome<T> {
240 pub value: Option<T>,
245 pub report: Report,
247}
248
249impl<T> Outcome<T> {
250 pub fn is_valid(&self) -> bool {
252 self.value.is_some() && self.report.is_empty()
253 }
254
255 pub fn into_result(self) -> Result<T, Report> {
258 match self.value {
259 Some(value) if self.report.is_empty() => Ok(value),
260 _ => Err(self.report),
261 }
262 }
263}
264
265impl Validation {
266 pub fn new() -> Validation {
268 Validation::default()
269 }
270
271 pub fn set_max_errors(&mut self, max: usize) {
276 self.max_errors = Some(max);
277 }
278
279 pub fn max_errors(&self) -> Option<usize> {
281 self.max_errors
282 }
283
284 pub fn setup(&self, driver: &mut DeserializeDriver<'_, '_>) {
286 driver.push_layer(PathLayer::new());
287 let state = driver.state_mut();
288 state.set_collect_errors(true);
289 if let Some(max) = self.max_errors {
290 state.set_max_errors(max);
291 }
292 state.get_mut::<ReportHandle>().0 = Some(self.issues.clone());
293 }
294
295 pub fn finish<T>(&self, rv: Result<T, Error>) -> Outcome<T> {
297 let issues = {
298 let mut issues = self.issues.lock().unwrap_or_else(|err| err.into_inner());
299 std::mem::take(&mut *issues)
300 };
301 let mut report = Report { issues };
302 let value = match rv {
303 Ok(value) => Some(value),
304 Err(err) => {
305 report.issues.extend(err.errors().map(Issue::from_error));
306 None
307 }
308 };
309 report
311 .issues
312 .sort_by_key(|issue| issue.offset.unwrap_or(usize::MAX));
313 Outcome { value, report }
314 }
315}