1use core::fmt;
2
3use nom::error::{ContextError, Error, ErrorKind, ParseError};
4use nom_locate::LocatedSpan;
5
6#[derive(Debug, Clone)]
7pub struct VttError {
8 pub looking_for: String,
10 pub line: u32,
12 pub offset: usize,
13 pub fragment: String,
14 pub message: Option<String>,
16}
17
18impl std::fmt::Display for VttError {
19 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
20 let Self {
21 looking_for,
22 line,
23 offset,
24 fragment,
25 message,
26 } = self;
27 let message = match message.as_ref() {
28 Some(message) => format!("\n{message}"),
29 None => "".to_owned(),
30 };
31
32 write!(
33 formatter,
34 ".vtt parsing error at {line}:{offset}, looking for {looking_for}. Found: {fragment}{message}",
35 )
36 }
37}
38
39impl<'a> ParseError<LocatedSpan<&'a str>> for VttError {
40 fn from_error_kind(input: LocatedSpan<&'a str>, kind: ErrorKind) -> Self {
41 VttError {
42 message: None,
43 line: input.location_line(),
44 offset: input.location_offset(),
45 looking_for: format!("{kind:?}"),
46 fragment: input.fragment().to_string(),
47 }
48 }
49
50 fn append(input: LocatedSpan<&'a str>, kind: ErrorKind, _other: Self) -> Self {
51 VttError {
52 message: None,
53 line: input.location_line(),
54 offset: input.location_offset(),
55 looking_for: format!("{kind:?}"),
56 fragment: input.fragment().to_string(),
57 }
58 }
59
60 fn from_char(input: LocatedSpan<&'a str>, c: char) -> Self {
61 VttError {
62 message: None,
63 line: input.location_line(),
64 offset: input.location_offset(),
65 looking_for: c.to_string(),
66 fragment: input.fragment().to_string(),
67 }
68 }
69
70 fn or(self, other: Self) -> Self {
71 let message = format!(
72 "Failure. Looking for {} or {}\n",
73 self.looking_for, other.looking_for
74 );
75
76 VttError {
77 line: self.line,
78 offset: self.offset,
79 fragment: self.fragment,
80 looking_for: self.looking_for,
81 message: Some(message),
82 }
83 }
84}
85
86impl<'a> ContextError<LocatedSpan<&'a str>> for VttError {
87 fn add_context(input: LocatedSpan<&'a str>, ctx: &'static str, other: Self) -> Self {
88 VttError {
89 message: Some(ctx.to_string()),
90 line: input.location_line(),
91 offset: input.location_offset(),
92 looking_for: other.looking_for,
93 fragment: input.fragment().to_string(),
94 }
95 }
96}
97
98impl<'a> From<nom::Err<Error<LocatedSpan<&'a str>>>> for VttError {
99 fn from(error: nom::Err<Error<LocatedSpan<&'a str>>>) -> Self {
100 match error {
101 nom::Err::Error(Error { input, code }) => VttError::from_error_kind(input, code),
102 nom::Err::Failure(Error { input, code }) => VttError::from_error_kind(input, code),
103 nom::Err::Incomplete(_) => VttError {
104 line: 0,
105 offset: 0,
106 fragment: "".to_owned(),
107 looking_for: "".to_owned(),
108 message: Some("Incomplete data, giving up parsing.".to_owned()),
109 },
110 }
111 }
112}