1use std::error::Error as StdError;
2use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
3use std::result::Result as StdResult;
4
5#[derive(Debug)]
6pub struct Error {
7 error_type: ErrorType,
8 pos: usize,
9}
10impl Error {
11 pub(crate) fn new(error_type: ErrorType, pos: usize) -> Self {
12 Self { error_type, pos }
13 }
14
15 pub(crate) fn empty_pattern() -> Self {
16 Self {
17 error_type: ErrorType::EmptyPattern,
18 pos: usize::MAX,
19 }
20 }
21
22 pub fn error_type(&self) -> &ErrorType {
23 &self.error_type
24 }
25
26 pub fn position(&self) -> usize {
27 self.pos
28 }
29}
30impl Display for Error {
31 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
32 self.error_type.fmt_with_pos(Some(self.pos), f)
33 }
34}
35impl StdError for Error {}
36
37#[derive(Copy, Clone)]
38pub enum ErrorType {
39 EmptyPattern,
40 IllegalEscape,
41 InvalidRangeValues(char, char),
42 UnclosedCharClass,
43 UnescapedChar(char),
44}
45impl ErrorType {
46 pub fn type_desc(&self) -> &'static str {
47 match self {
48 ErrorType::EmptyPattern => "empty pattern",
49 ErrorType::IllegalEscape => "illegal use of '\\': end of pattern",
50 ErrorType::InvalidRangeValues(_, _) => "invalid character range",
51 ErrorType::UnclosedCharClass => "character class opened with '[' isn't closed",
52 ErrorType::UnescapedChar(_) => "special character not escaped with '\\'",
53 }
54 }
55
56 pub fn full_desc(&self) -> String {
57 format!("{}", self)
58 }
59
60 pub fn fmt_with_pos(&self, pos: Option<usize>, f: &mut Formatter<'_>) -> FmtResult {
61 match (self, pos) {
62 (ErrorType::IllegalEscape, Some(pos)) => {
63 write!(f, "illegal use of '\\' at {pos}: end of pattern")
64 }
65 (ErrorType::InvalidRangeValues(start, end), Some(pos)) => {
66 write!(f, "invalid charater range at {pos}: {start}-{end}")
67 }
68 (ErrorType::InvalidRangeValues(start, end), None) => {
69 write!(f, "invalid charater range: {start}-{end}")
70 }
71 (ErrorType::UnclosedCharClass, Some(pos)) => {
72 write!(f, "character class opened with '[' at {pos} isn't closed")
73 }
74 (ErrorType::UnescapedChar(unescaped), Some(pos)) => {
75 write!(
76 f,
77 "special character {unescaped} at {pos} not escaped with '\\'"
78 )
79 }
80 (ErrorType::UnescapedChar(unescaped), None) => {
81 write!(f, "special character {unescaped} not escaped with '\\'")
82 }
83 (_, _) => f.write_str(self.type_desc()),
84 }
85 }
86}
87impl Debug for ErrorType {
88 #[inline]
89 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
90 self.fmt_with_pos(None, f)
91 }
92}
93impl Display for ErrorType {
94 #[inline]
95 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
96 self.fmt_with_pos(None, f)
97 }
98}
99
100pub type Result<T> = StdResult<T, Error>;