Coverage Report

Created: 2025-11-02 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}