serde_hkx/errors/
readable.rs
1use crate::lib::*;
3use winnow::error::{ContextError, ErrMode, ParseError, StrContext};
4
5#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
7pub struct ReadableError {
8 title: String,
9 message: String,
10 span: Range<usize>,
11 input: String,
12}
13
14impl ReadableError {
15 pub fn from_parse(error: ParseError<&str, ContextError>, input: &str) -> Self {
17 let message = error.inner().to_string();
18 let input = input.to_string();
19 let start = error.offset();
20 let end = (start + 1..)
21 .find(|e| input.is_char_boundary(*e))
22 .unwrap_or(start);
23 Self {
24 title: "Parse error".to_string(),
25 message,
26 span: start..end,
27 input,
28 }
29 }
30
31 pub fn from_context<T>(error: ErrMode<ContextError>, input: T, err_pos: usize) -> Self
33 where
34 T: core::fmt::Display,
35 {
36 let (labels, message) = error
37 .map(|ctx_err| {
38 ctx_err.cause().map_or_else(
39 || {
40 let mut labels = String::new();
41 let mut msg = "expected ".to_string();
42
43 for ctx in ctx_err.context() {
44 match ctx {
45 StrContext::Label(label) => {
46 labels += " <- ";
47 labels += label;
48 }
49 StrContext::Expected(expected) => {
50 msg += &expected.to_string();
51 }
52 _ => (),
53 }
54 }
55 (labels, msg)
56 },
57 |cause| (String::new(), cause.to_string()),
58 )
59 })
60 .into_inner()
61 .unwrap_or_default();
62
63 let input = input.to_string();
64 let start = err_pos;
65 let end = (start + 1..)
66 .find(|e| input.is_char_boundary(*e))
67 .unwrap_or(start);
68
69 Self {
70 title: labels,
71 message,
72 span: start..end,
73 input,
74 }
75 }
76
77 pub fn from_display<T, U>(message: T, input: U, err_pos: usize) -> Self
78 where
79 T: core::fmt::Display,
80 U: core::fmt::Display,
81 {
82 let input = input.to_string();
83 let start = err_pos;
84 let end = (start + 1..)
85 .find(|e| input.is_char_boundary(*e))
86 .unwrap_or(start);
87
88 Self {
89 title: "Validation Error".to_string(),
90 message: message.to_string(),
91 span: start..end,
92 input,
93 }
94 }
95}
96
97impl fmt::Display for ReadableError {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 let message = annotate_snippets::Level::Error.title(&self.title).snippet(
100 annotate_snippets::Snippet::source(&self.input)
101 .fold(true)
102 .annotation(
103 annotate_snippets::Level::Error
104 .span(self.span.clone())
105 .label(&self.message),
106 ),
107 );
108 let renderer = annotate_snippets::Renderer::plain();
109 let rendered = renderer.render(message);
110 rendered.fmt(f)
111 }
112}
113
114impl std::error::Error for ReadableError {}