/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sfv-0.14.0/src/error.rs
Line | Count | Source |
1 | | use std::fmt; |
2 | | |
3 | | #[derive(Debug)] |
4 | | #[cfg_attr(test, derive(PartialEq))] |
5 | | pub(crate) enum Repr { |
6 | | Visit(Box<str>), |
7 | | |
8 | | OutOfRange, |
9 | | NaN, |
10 | | |
11 | | Empty, |
12 | | InvalidCharacter(usize), |
13 | | |
14 | | TrailingCharactersAfterMember(usize), |
15 | | TrailingComma(usize), |
16 | | TrailingCharactersAfterParsedValue(usize), |
17 | | |
18 | | ExpectedStartOfInnerList(usize), |
19 | | ExpectedInnerListDelimiter(usize), |
20 | | UnterminatedInnerList(usize), |
21 | | |
22 | | ExpectedStartOfBareItem(usize), |
23 | | |
24 | | ExpectedStartOfBoolean(usize), |
25 | | ExpectedBoolean(usize), |
26 | | |
27 | | ExpectedStartOfString(usize), |
28 | | InvalidStringCharacter(usize), |
29 | | UnterminatedString(usize), |
30 | | |
31 | | UnterminatedEscapeSequence(usize), |
32 | | InvalidEscapeSequence(usize), |
33 | | |
34 | | ExpectedStartOfToken(usize), |
35 | | |
36 | | ExpectedStartOfByteSequence(usize), |
37 | | UnterminatedByteSequence(usize), |
38 | | InvalidByteSequence(usize), |
39 | | |
40 | | ExpectedDigit(usize), |
41 | | TooManyDigits(usize), |
42 | | TooManyDigitsBeforeDecimalPoint(usize), |
43 | | TooManyDigitsAfterDecimalPoint(usize), |
44 | | TrailingDecimalPoint(usize), |
45 | | |
46 | | ExpectedStartOfDate(usize), |
47 | | Rfc8941Date(usize), |
48 | | NonIntegerDate(usize), |
49 | | |
50 | | ExpectedStartOfDisplayString(usize), |
51 | | Rfc8941DisplayString(usize), |
52 | | ExpectedQuote(usize), |
53 | | InvalidUtf8InDisplayString(usize), |
54 | | InvalidDisplayStringCharacter(usize), |
55 | | UnterminatedDisplayString(usize), |
56 | | |
57 | | ExpectedStartOfKey(usize), |
58 | | } |
59 | | |
60 | | impl<E: std::error::Error> From<E> for Repr { |
61 | 0 | fn from(err: E) -> Self { |
62 | 0 | Self::Visit(err.to_string().into()) |
63 | 0 | } |
64 | | } |
65 | | |
66 | | impl Repr { |
67 | 0 | fn parts(&self) -> (&str, Option<usize>) { |
68 | 0 | match *self { |
69 | 0 | Self::Visit(ref msg) => (msg, None), |
70 | | |
71 | 0 | Self::NaN => ("NaN", None), |
72 | 0 | Self::OutOfRange => ("out of range", None), |
73 | | |
74 | 0 | Self::Empty => ("cannot be empty", None), |
75 | 0 | Self::InvalidCharacter(i) => ("invalid character", Some(i)), |
76 | | |
77 | 0 | Self::TrailingCharactersAfterMember(i) => ("trailing characters after member", Some(i)), |
78 | 0 | Self::TrailingComma(i) => ("trailing comma", Some(i)), |
79 | 0 | Self::TrailingCharactersAfterParsedValue(i) => { |
80 | 0 | ("trailing characters after parsed value", Some(i)) |
81 | | } |
82 | | |
83 | 0 | Self::ExpectedStartOfInnerList(i) => ("expected start of inner list", Some(i)), |
84 | 0 | Self::ExpectedInnerListDelimiter(i) => { |
85 | 0 | ("expected inner list delimiter (' ' or ')')", Some(i)) |
86 | | } |
87 | 0 | Self::UnterminatedInnerList(i) => ("unterminated inner list", Some(i)), |
88 | | |
89 | 0 | Self::ExpectedStartOfBareItem(i) => ("expected start of bare item", Some(i)), |
90 | | |
91 | 0 | Self::ExpectedStartOfBoolean(i) => ("expected start of boolean ('?')", Some(i)), |
92 | 0 | Self::ExpectedBoolean(i) => ("expected boolean ('0' or '1')", Some(i)), |
93 | | |
94 | 0 | Self::ExpectedStartOfString(i) => (r#"expected start of string ('"')"#, Some(i)), |
95 | 0 | Self::InvalidStringCharacter(i) => ("invalid string character", Some(i)), |
96 | 0 | Self::UnterminatedString(i) => ("unterminated string", Some(i)), |
97 | | |
98 | 0 | Self::UnterminatedEscapeSequence(i) => ("unterminated escape sequence", Some(i)), |
99 | 0 | Self::InvalidEscapeSequence(i) => ("invalid escape sequence", Some(i)), |
100 | | |
101 | 0 | Self::ExpectedStartOfToken(i) => ("expected start of token", Some(i)), |
102 | | |
103 | 0 | Self::ExpectedStartOfByteSequence(i) => { |
104 | 0 | ("expected start of byte sequence (':')", Some(i)) |
105 | | } |
106 | 0 | Self::UnterminatedByteSequence(i) => ("unterminated byte sequence", Some(i)), |
107 | 0 | Self::InvalidByteSequence(i) => ("invalid byte sequence", Some(i)), |
108 | | |
109 | 0 | Self::ExpectedDigit(i) => ("expected digit", Some(i)), |
110 | 0 | Self::TooManyDigits(i) => ("too many digits", Some(i)), |
111 | 0 | Self::TooManyDigitsBeforeDecimalPoint(i) => { |
112 | 0 | ("too many digits before decimal point", Some(i)) |
113 | | } |
114 | 0 | Self::TooManyDigitsAfterDecimalPoint(i) => { |
115 | 0 | ("too many digits after decimal point", Some(i)) |
116 | | } |
117 | 0 | Self::TrailingDecimalPoint(i) => ("trailing decimal point", Some(i)), |
118 | | |
119 | 0 | Self::ExpectedStartOfDate(i) => ("expected start of date ('@')", Some(i)), |
120 | 0 | Self::Rfc8941Date(i) => ("RFC 8941 does not support dates", Some(i)), |
121 | 0 | Self::NonIntegerDate(i) => ("date must be an integer number of seconds", Some(i)), |
122 | | |
123 | 0 | Self::ExpectedStartOfDisplayString(i) => { |
124 | 0 | ("expected start of display string ('%')", Some(i)) |
125 | | } |
126 | 0 | Self::Rfc8941DisplayString(i) => ("RFC 8941 does not support display strings", Some(i)), |
127 | 0 | Self::ExpectedQuote(i) => (r#"expected '"'"#, Some(i)), |
128 | 0 | Self::InvalidUtf8InDisplayString(i) => ("invalid UTF-8 in display string", Some(i)), |
129 | 0 | Self::InvalidDisplayStringCharacter(i) => ("invalid display string character", Some(i)), |
130 | 0 | Self::UnterminatedDisplayString(i) => ("unterminated display string", Some(i)), |
131 | | |
132 | 0 | Self::ExpectedStartOfKey(i) => ("expected start of key ('a'-'z' or '*')", Some(i)), |
133 | | } |
134 | 0 | } |
135 | | } |
136 | | |
137 | | impl fmt::Display for Repr { |
138 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
139 | 0 | let (msg, index) = self.parts(); |
140 | 0 | match (f.alternate(), index) { |
141 | 0 | (true, _) | (false, None) => f.write_str(msg), |
142 | 0 | (false, Some(index)) => write!(f, "{msg} at index {index}"), |
143 | | } |
144 | 0 | } |
145 | | } |
146 | | |
147 | | /// An error that can occur in this crate. |
148 | | /// |
149 | | /// The most common type of error is invalid input during parsing, but others |
150 | | /// exist as well: |
151 | | /// |
152 | | /// - Conversion to or from bare-item types such as [`Integer`][crate::Integer] |
153 | | /// - Attempting to serialize an empty [list][crate::ListSerializer::finish] or |
154 | | /// [dictionary][crate::DictSerializer::finish] |
155 | | /// |
156 | | /// By default, the `std::fmt::Display` implementation for this type includes |
157 | | /// the index at which the error occurred, if any. To omit this, use the |
158 | | /// alternate form: |
159 | | /// |
160 | | /// ``` |
161 | | /// # use sfv::{visitor::Ignored, Parser}; |
162 | | /// let err = Parser::new("abc;0").parse_item_with_visitor(Ignored).unwrap_err(); |
163 | | /// |
164 | | /// assert_eq!(format!("{}", err), "expected start of key ('a'-'z' or '*') at index 4"); |
165 | | /// assert_eq!(format!("{:#}", err), "expected start of key ('a'-'z' or '*')"); |
166 | | /// assert_eq!(err.index(), Some(4)); |
167 | | /// ``` |
168 | | #[derive(Debug)] |
169 | | #[cfg_attr(test, derive(PartialEq))] |
170 | | pub struct Error { |
171 | | repr: Repr, |
172 | | } |
173 | | |
174 | | impl From<Repr> for Error { |
175 | 0 | fn from(repr: Repr) -> Self { |
176 | 0 | Self { repr } |
177 | 0 | } |
178 | | } |
179 | | |
180 | | impl fmt::Display for Error { |
181 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
182 | 0 | fmt::Display::fmt(&self.repr, f) |
183 | 0 | } |
184 | | } |
185 | | |
186 | | impl std::error::Error for Error {} |
187 | | |
188 | | impl Error { |
189 | | /// Returns the zero-based index in the input at which the error occurred, |
190 | | /// if any. |
191 | | #[must_use] |
192 | 0 | pub fn index(&self) -> Option<usize> { |
193 | 0 | self.repr.parts().1 |
194 | 0 | } |
195 | | } |
196 | | |
197 | | pub(crate) struct NonEmptyStringError { |
198 | | byte_index: Option<usize>, |
199 | | } |
200 | | |
201 | | impl NonEmptyStringError { |
202 | 0 | pub(crate) const fn empty() -> Self { |
203 | 0 | Self { byte_index: None } |
204 | 0 | } |
205 | | |
206 | 0 | pub(crate) const fn invalid_character(byte_index: usize) -> Self { |
207 | 0 | Self { |
208 | 0 | byte_index: Some(byte_index), |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | 0 | pub(crate) const fn msg(&self) -> &'static str { |
213 | 0 | match self.byte_index { |
214 | 0 | None => "cannot be empty", |
215 | 0 | Some(_) => "invalid character", |
216 | | } |
217 | 0 | } |
218 | | } |
219 | | |
220 | | impl From<NonEmptyStringError> for Error { |
221 | 0 | fn from(err: NonEmptyStringError) -> Self { |
222 | 0 | match err.byte_index { |
223 | 0 | None => Repr::Empty, |
224 | 0 | Some(index) => Repr::InvalidCharacter(index), |
225 | | } |
226 | 0 | .into() |
227 | 0 | } |
228 | | } |