lexical_util/
error.rs

1//! Error type for numeric parsing functions.
2//!
3//! The error type is C-compatible, simplifying use external language
4//! bindings.
5
6use core::{fmt, mem};
7use static_assertions::const_assert;
8#[cfg(feature = "std")]
9use std::error;
10
11/// Error code during parsing, indicating failure type.
12#[non_exhaustive]
13#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
14pub enum Error {
15    // PARSE ERRORS
16    /// Integral overflow occurred during numeric parsing.
17    Overflow(usize),
18    /// Integral underflow occurred during numeric parsing.
19    Underflow(usize),
20    /// Invalid digit found before string termination.
21    InvalidDigit(usize),
22    /// Empty byte array found.
23    Empty(usize),
24    /// Empty mantissa found.
25    EmptyMantissa(usize),
26    /// Empty exponent found.
27    EmptyExponent(usize),
28    /// Empty integer found.
29    EmptyInteger(usize),
30    /// Empty fraction found.
31    EmptyFraction(usize),
32    /// Invalid positive mantissa sign was found.
33    InvalidPositiveMantissaSign(usize),
34    /// Mantissa sign was required(usize), but not found.
35    MissingMantissaSign(usize),
36    /// Exponent was present but not allowed.
37    InvalidExponent(usize),
38    /// Invalid positive exponent sign was found.
39    InvalidPositiveExponentSign(usize),
40    /// Exponent sign was required(usize), but not found.
41    MissingExponentSign(usize),
42    /// Exponent was present without fraction component.
43    ExponentWithoutFraction(usize),
44    /// Integer or integer component of float had invalid leading zeros.
45    InvalidLeadingZeros(usize),
46    /// No exponent with required exponent notation.
47    MissingExponent(usize),
48    /// Integral sign was required(usize), but not found.
49    MissingSign(usize),
50    /// Invalid positive sign for an integer was found.
51    InvalidPositiveSign(usize),
52    /// Invalid negative sign for an unsigned type was found.
53    InvalidNegativeSign(usize),
54
55    // NUMBER FORMAT ERRORS
56    /// Invalid radix for the mantissa (significant) digits.
57    InvalidMantissaRadix,
58    /// Invalid base for the exponent.
59    InvalidExponentBase,
60    /// Invalid radix for the exponent digits.
61    InvalidExponentRadix,
62    /// Invalid digit separator character.
63    InvalidDigitSeparator,
64    /// Invalid decimal point character.
65    InvalidDecimalPoint,
66    /// Invalid symbol to represent exponent notation.
67    InvalidExponentSymbol,
68    /// Invalid character for a base prefix.
69    InvalidBasePrefix,
70    /// Invalid character for a base suffix.
71    InvalidBaseSuffix,
72    /// Invalid punctuation characters: multiple symbols overlap.
73    InvalidPunctuation,
74    /// Optional exponent flags were set while disabling exponent notation.
75    InvalidExponentFlags,
76    /// Set no positive mantissa sign while requiring mantissa signs.
77    InvalidMantissaSign,
78    /// Set no positive exponent sign while requiring exponent signs.
79    InvalidExponentSign,
80    /// Set optional special float flags while disable special floats.
81    InvalidSpecial,
82    /// Invalid consecutive integer digit separator.
83    InvalidConsecutiveIntegerDigitSeparator,
84    /// Invalid consecutive fraction digit separator.
85    InvalidConsecutiveFractionDigitSeparator,
86    /// Invalid consecutive exponent digit separator.
87    InvalidConsecutiveExponentDigitSeparator,
88    /// Invalid flags were set without the format feature.
89    InvalidFlags,
90
91    // OPTION ERRORS
92    /// Invalid NaN string: must start with an `n` character.
93    InvalidNanString,
94    /// NaN string is too long.
95    NanStringTooLong,
96    /// Invalid short infinity string: must start with an `i` character.
97    InvalidInfString,
98    /// Short infinity string is too long.
99    InfStringTooLong,
100    /// Invalid long infinity string: must start with an `i` character.
101    InvalidInfinityString,
102    /// Long infinity string is too long.
103    InfinityStringTooLong,
104    /// Long infinity string is too short: it must be as long as short infinity.
105    InfinityStringTooShort,
106    /// Invalid float parsing algorithm.
107    InvalidFloatParseAlgorithm,
108    /// Invalid radix for the significant digits.
109    InvalidRadix,
110    /// Invalid precision flags for writing floats.
111    InvalidFloatPrecision,
112    /// Invalid negative exponent break: break is above 0.
113    InvalidNegativeExponentBreak,
114    /// Invalid positive exponent break: break is below 0.
115    InvalidPositiveExponentBreak,
116
117    // NOT AN ERROR
118    /// An error did not actually occur, and the result was successful.
119    Success,
120}
121
122// Ensure we don't have extra padding on the structure.
123const_assert!(mem::size_of::<Error>() <= 2 * mem::size_of::<usize>());
124
125macro_rules! is_error_type {
126    ($name:ident, $type:ident$($t:tt)*) => (
127        /// const fn check to see if an error is of a specific type.
128        pub const fn $name(&self) -> bool {
129            // Note: enum equality is not a const fn, so use a let expression.
130            if let Self::$type$($t)* = self {
131                true
132            } else {
133                false
134            }
135        }
136    );
137}
138
139impl Error {
140    /// Get the index for the parsing error.
141    pub fn index(&self) -> Option<&usize> {
142        match self {
143            // PARSE ERRORS
144            Self::Overflow(index) => Some(index),
145            Self::Underflow(index) => Some(index),
146            Self::InvalidDigit(index) => Some(index),
147            Self::Empty(index) => Some(index),
148            Self::EmptyMantissa(index) => Some(index),
149            Self::EmptyExponent(index) => Some(index),
150            Self::EmptyInteger(index) => Some(index),
151            Self::EmptyFraction(index) => Some(index),
152            Self::InvalidPositiveMantissaSign(index) => Some(index),
153            Self::MissingMantissaSign(index) => Some(index),
154            Self::InvalidExponent(index) => Some(index),
155            Self::InvalidPositiveExponentSign(index) => Some(index),
156            Self::MissingExponentSign(index) => Some(index),
157            Self::ExponentWithoutFraction(index) => Some(index),
158            Self::InvalidLeadingZeros(index) => Some(index),
159            Self::MissingExponent(index) => Some(index),
160            Self::MissingSign(index) => Some(index),
161            Self::InvalidPositiveSign(index) => Some(index),
162            Self::InvalidNegativeSign(index) => Some(index),
163
164            // NUMBER FORMAT ERRORS
165            Self::InvalidMantissaRadix => None,
166            Self::InvalidExponentBase => None,
167            Self::InvalidExponentRadix => None,
168            Self::InvalidDigitSeparator => None,
169            Self::InvalidDecimalPoint => None,
170            Self::InvalidExponentSymbol => None,
171            Self::InvalidBasePrefix => None,
172            Self::InvalidBaseSuffix => None,
173            Self::InvalidPunctuation => None,
174            Self::InvalidExponentFlags => None,
175            Self::InvalidMantissaSign => None,
176            Self::InvalidExponentSign => None,
177            Self::InvalidSpecial => None,
178            Self::InvalidConsecutiveIntegerDigitSeparator => None,
179            Self::InvalidConsecutiveFractionDigitSeparator => None,
180            Self::InvalidConsecutiveExponentDigitSeparator => None,
181            Self::InvalidFlags => None,
182
183            // OPTION ERRORS
184            Self::InvalidNanString => None,
185            Self::NanStringTooLong => None,
186            Self::InvalidInfString => None,
187            Self::InfStringTooLong => None,
188            Self::InvalidInfinityString => None,
189            Self::InfinityStringTooLong => None,
190            Self::InfinityStringTooShort => None,
191            Self::InvalidFloatParseAlgorithm => None,
192            Self::InvalidRadix => None,
193            Self::InvalidFloatPrecision => None,
194            Self::InvalidNegativeExponentBreak => None,
195            Self::InvalidPositiveExponentBreak => None,
196
197            // NOT AN ERROR
198            Self::Success => None,
199        }
200    }
201
202    is_error_type!(is_overflow, Overflow(_));
203    is_error_type!(is_underflow, Underflow(_));
204    is_error_type!(is_invalid_digit, InvalidDigit(_));
205    is_error_type!(is_empty, Empty(_));
206    is_error_type!(is_empty_mantissa, EmptyMantissa(_));
207    is_error_type!(is_empty_exponent, EmptyExponent(_));
208    is_error_type!(is_empty_integer, EmptyInteger(_));
209    is_error_type!(is_empty_fraction, EmptyFraction(_));
210    is_error_type!(is_invalid_positive_mantissa_sign, InvalidPositiveMantissaSign(_));
211    is_error_type!(is_missing_mantissa_sign, MissingMantissaSign(_));
212    is_error_type!(is_invalid_exponent, InvalidExponent(_));
213    is_error_type!(is_invalid_positive_exponent_sign, InvalidPositiveExponentSign(_));
214    is_error_type!(is_missing_exponent_sign, MissingExponentSign(_));
215    is_error_type!(is_exponent_without_fraction, ExponentWithoutFraction(_));
216    is_error_type!(is_invalid_leading_zeros, InvalidLeadingZeros(_));
217    is_error_type!(is_missing_exponent, MissingExponent(_));
218    is_error_type!(is_missing_sign, MissingSign(_));
219    is_error_type!(is_invalid_positive_sign, InvalidPositiveSign(_));
220    is_error_type!(is_invalid_negative_sign, InvalidNegativeSign(_));
221    is_error_type!(is_invalid_mantissa_radix, InvalidMantissaRadix);
222    is_error_type!(is_invalid_exponent_base, InvalidExponentBase);
223    is_error_type!(is_invalid_exponent_radix, InvalidExponentRadix);
224    is_error_type!(is_invalid_digit_separator, InvalidDigitSeparator);
225    is_error_type!(is_invalid_decimal_point, InvalidDecimalPoint);
226    is_error_type!(is_invalid_exponent_symbol, InvalidExponentSymbol);
227    is_error_type!(is_invalid_base_prefix, InvalidBasePrefix);
228    is_error_type!(is_invalid_base_suffix, InvalidBaseSuffix);
229    is_error_type!(is_invalid_punctuation, InvalidPunctuation);
230    is_error_type!(is_invalid_exponent_flags, InvalidExponentFlags);
231    is_error_type!(is_invalid_mantissa_sign, InvalidMantissaSign);
232    is_error_type!(is_invalid_exponent_sign, InvalidExponentSign);
233    is_error_type!(is_invalid_special, InvalidSpecial);
234    is_error_type!(
235        is_invalid_consecutive_integer_digit_separator,
236        InvalidConsecutiveIntegerDigitSeparator
237    );
238    is_error_type!(
239        is_invalid_consecutive_fraction_digit_separator,
240        InvalidConsecutiveFractionDigitSeparator
241    );
242    is_error_type!(
243        is_invalid_consecutive_exponent_digit_separator,
244        InvalidConsecutiveExponentDigitSeparator
245    );
246    is_error_type!(is_invalid_flags, InvalidFlags);
247    is_error_type!(is_invalid_nan_string, InvalidNanString);
248    is_error_type!(is_nan_string_too_long, NanStringTooLong);
249    is_error_type!(is_invalid_inf_string, InvalidInfString);
250    is_error_type!(is_inf_string_too_long, InfStringTooLong);
251    is_error_type!(is_invalid_infinity_string, InvalidInfinityString);
252    is_error_type!(is_infinity_string_too_long, InfinityStringTooLong);
253    is_error_type!(is_infinity_string_too_short, InfinityStringTooShort);
254    is_error_type!(is_invalid_float_parse_algorithm, InvalidFloatParseAlgorithm);
255    is_error_type!(is_invalid_radix, InvalidRadix);
256    is_error_type!(is_invalid_float_precision, InvalidFloatPrecision);
257    is_error_type!(is_invalid_negative_exponent_break, InvalidNegativeExponentBreak);
258    is_error_type!(is_invalid_positive_exponent_break, InvalidPositiveExponentBreak);
259    is_error_type!(is_success, Success);
260}
261
262/// Add an error message for parsing errors.
263macro_rules! write_parse_error {
264    ($formatter:ident, $message:literal, $index:ident) => {
265        write!($formatter, "lexical parse error: {} at index {}", $message, $index)
266    };
267}
268
269/// Add an error message for number format errors.
270macro_rules! format_message {
271    ($formatter:ident, $message:literal) => {
272        write!($formatter, "lexical number format error: {}", $message)
273    };
274}
275
276/// Add an error message for options errors.
277macro_rules! options_message {
278    ($formatter:ident, $message:literal) => {
279        write!($formatter, "lexical options error: {}", $message)
280    };
281}
282
283impl fmt::Display for Error {
284    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
285        match self {
286            // PARSE ERRORS
287            Self::Overflow(index) => write_parse_error!(formatter, "'numeric overflow occurred'", index),
288            Self::Underflow(index) => write_parse_error!(formatter, "'numeric underflow occurred'", index),
289            Self::InvalidDigit(index) => write_parse_error!(formatter, "'invalid digit found'", index),
290            Self::Empty(index) => write_parse_error!(formatter, "'the string to parse was empty'", index),
291            Self::EmptyMantissa(index) => write_parse_error!(formatter, "'no significant digits found'", index),
292            Self::EmptyExponent(index) => write_parse_error!(formatter, "'exponent notation found without an exponent'", index),
293            Self::EmptyInteger(index) => write_parse_error!(formatter, "'invalid float with no integer digits'", index),
294            Self::EmptyFraction(index) => write_parse_error!(formatter, "'invalid float with no fraction digits'", index),
295            Self::InvalidPositiveMantissaSign(index) => write_parse_error!(formatter, "'invalid `+` sign before significant digits'", index),
296            Self::MissingMantissaSign(index) => write_parse_error!(formatter, "'missing required `+/-` sign for significant digits'", index),
297            Self::InvalidExponent(index) => write_parse_error!(formatter, "'exponent found but not allowed'", index),
298            Self::InvalidPositiveExponentSign(index) => write_parse_error!(formatter, "'invalid `+` sign in exponent'", index),
299            Self::MissingExponentSign(index) => write_parse_error!(formatter, "'missing required `+/-` sign for exponent'", index),
300            Self::ExponentWithoutFraction(index) => write_parse_error!(formatter,  "'invalid float containing exponent without fraction'", index),
301            Self::InvalidLeadingZeros(index) => write_parse_error!(formatter, "'invalid number with leading zeros before digits'", index),
302            Self::MissingExponent(index) => write_parse_error!(formatter, "'missing required exponent'", index),
303            Self::MissingSign(index) => write_parse_error!(formatter, "'missing required `+/-` sign for integer'", index),
304            Self::InvalidPositiveSign(index) => write_parse_error!(formatter, "'invalid `+` sign for an integer was found'", index),
305            Self::InvalidNegativeSign(index) => write_parse_error!(formatter, "'invalid `-` sign for an unsigned type was found'", index),
306
307            // NUMBER FORMAT ERRORS
308            Self::InvalidMantissaRadix => format_message!(formatter, "'invalid radix for mantissa digits'"),
309            Self::InvalidExponentBase => format_message!(formatter, "'invalid exponent base'"),
310            Self::InvalidExponentRadix => format_message!(formatter, "'invalid radix for exponent digits'"),
311            Self::InvalidDigitSeparator => format_message!(formatter, "'invalid digit separator: must be ASCII and not a digit or a `+/-` sign'"),
312            Self::InvalidDecimalPoint => format_message!(formatter, "'invalid decimal point: must be ASCII and not a digit or a `+/-` sign'"),
313            Self::InvalidExponentSymbol => format_message!(formatter, "'invalid exponent symbol: must be ASCII and not a digit or a `+/-` sign'"),
314            Self::InvalidBasePrefix => format_message!(formatter, "'invalid base prefix character'"),
315            Self::InvalidBaseSuffix => format_message!(formatter, "'invalid base suffix character'"),
316            Self::InvalidPunctuation => format_message!(formatter, "'invalid punctuation: multiple characters overlap'"),
317            Self::InvalidExponentFlags => format_message!(formatter, "'exponent flags set while disabling exponent notation'"),
318            Self::InvalidMantissaSign => format_message!(formatter, "'disabled the `+` sign while requiring a sign for significant digits'"),
319            Self::InvalidExponentSign => format_message!(formatter, "'disabled the `+` sign while requiring a sign for exponent digits'"),
320            Self::InvalidSpecial => format_message!(formatter, "'special flags set while disabling special floats'"),
321            Self::InvalidConsecutiveIntegerDigitSeparator => format_message!(formatter, "'enabled consecutive digit separators in the integer without setting a valid location'"),
322            Self::InvalidConsecutiveFractionDigitSeparator => format_message!(formatter, "'enabled consecutive digit separators in the fraction without setting a valid location'"),
323            Self::InvalidConsecutiveExponentDigitSeparator => format_message!(formatter, "'enabled consecutive digit separators in the exponent without setting a valid location'"),
324            Self::InvalidFlags => format_message!(formatter, "'invalid flags enabled without the format feature'"),
325
326            // OPTION ERRORS
327            Self::InvalidNanString => options_message!(formatter, "'NaN string must started with `n`'"),
328            Self::NanStringTooLong => options_message!(formatter, "'NaN string is too long'"),
329            Self::InvalidInfString => options_message!(formatter, "'short infinity string must started with `i`'"),
330            Self::InfStringTooLong => options_message!(formatter, "'short infinity string is too long'"),
331            Self::InvalidInfinityString => options_message!(formatter, "'long infinity string must started with `i`'"),
332            Self::InfinityStringTooLong => options_message!(formatter, "'long infinity string is too long'"),
333            Self::InfinityStringTooShort => options_message!(formatter, "'long infinity string is too short'"),
334            Self::InvalidFloatParseAlgorithm => options_message!(formatter, "'invalid combination of float parse algorithms'"),
335            Self::InvalidRadix => options_message!(formatter, "'invalid radix for significant digits'"),
336            Self::InvalidFloatPrecision => options_message!(formatter, "'invalid float precision: min digits is larger than max digits'"),
337            Self::InvalidNegativeExponentBreak => options_message!(formatter, "'invalid negative exponent break: value is above 0'"),
338            Self::InvalidPositiveExponentBreak => options_message!(formatter, "'invalid positive exponent break: value is below 0'"),
339
340            // NOT AN ERROR
341            Self::Success => write!(formatter, "'not actually an error'"),
342        }
343    }
344}
345
346#[cfg(feature = "std")]
347impl error::Error for Error {
348}