const_format_proc_macros/format_str/
errors.rs

1use proc_macro2::Span;
2
3use std::{
4    fmt::{self, Display},
5    ops::Range,
6};
7
8#[derive(Debug, PartialEq)]
9pub(crate) struct ParseError {
10    pub(crate) pos: usize,
11    pub(crate) kind: ParseErrorKind,
12}
13
14#[derive(Debug, PartialEq)]
15pub(crate) enum ParseErrorKind {
16    /// A `{` that wasn't closed.
17    UnclosedArg,
18    /// A `}` that doesn't close an argument.
19    InvalidClosedArg,
20    /// When parsing the number of a positional arguments
21    NotANumber {
22        what: String,
23    },
24    /// When parsing the identifier of a named argument
25    NotAnIdent {
26        what: String,
27    },
28    UnknownFormatting {
29        what: String,
30    },
31}
32
33#[allow(dead_code)]
34impl ParseErrorKind {
35    pub fn not_a_number(what: &str) -> Self {
36        Self::NotANumber {
37            what: what.to_string(),
38        }
39    }
40    pub fn not_an_ident(what: &str) -> Self {
41        Self::NotAnIdent {
42            what: what.to_string(),
43        }
44    }
45    pub fn unknown_formatting(what: &str) -> Self {
46        Self::UnknownFormatting {
47            what: what.to_string(),
48        }
49    }
50}
51
52////////////////////////////////////////////////////////////////////////////////
53
54#[derive(Debug, PartialEq)]
55pub(crate) struct DisplayParseError<'a> {
56    pub(crate) str: &'a str,
57    pub(crate) error_span: Range<usize>,
58    pub(crate) kind: ParseErrorKind,
59}
60impl ParseError {
61    fn error_span(&self) -> Range<usize> {
62        let len = match &self.kind {
63            ParseErrorKind::UnclosedArg => 0,
64            ParseErrorKind::InvalidClosedArg => 0,
65            ParseErrorKind::NotANumber { what } => what.len(),
66            ParseErrorKind::NotAnIdent { what } => what.len(),
67            ParseErrorKind::UnknownFormatting { what } => what.len(),
68        };
69
70        self.pos..self.pos + len
71    }
72
73    pub(crate) fn into_crate_err(self, span: Span, original_str: &str) -> crate::Error {
74        let display = DisplayParseError {
75            str: original_str,
76            error_span: self.error_span(),
77            kind: self.kind,
78        };
79
80        crate::Error::new(span, display)
81    }
82}
83
84impl Display for ParseErrorKind {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        match self {
87            ParseErrorKind::UnclosedArg => f.write_str("unclosed argument"),
88            ParseErrorKind::InvalidClosedArg => f.write_str("`}` closing a nonexistent argument"),
89            ParseErrorKind::NotANumber { what } => writeln!(f, "not a number: \"{}\"", what),
90            ParseErrorKind::NotAnIdent { what } => {
91                writeln!(f, "not a valid identifier: \"{}\"", what)
92            }
93            ParseErrorKind::UnknownFormatting { what } => {
94                writeln!(f, "unknown formatting: \"{}\"", what)
95            }
96        }
97    }
98}
99
100impl Display for DisplayParseError<'_> {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        f.write_str("failed to parse the format string ")?;
103
104        // Gets the amount of chars up to the error,
105        // this is good enough for most cases,
106        // but doesn't acount for multi-char characters.
107        let chars = self.str[..self.error_span.start].chars().count();
108        writeln!(f, "at the character number {}, ", chars)?;
109
110        Display::fmt(&self.kind, f)?;
111
112        Ok(())
113    }
114}