opening_hours_syntax/
error.rs1use alloc::boxed::Box;
2use core::fmt;
3use core::ops::RangeInclusive;
4
5use crate::parser::Rule;
6use crate::rules::day::{WeekNum, Year};
7
8pub type Result<T> = core::result::Result<T, Error>;
9
10const REPORT_ISSUE_LINK: &str = "https://github.com/remi-dupre/opening-hours-rs/issues";
11
12#[derive(Clone, Debug)]
13pub enum Error {
14 Syntax(Box<pest::error::Error<Rule>>),
17 Unsupported(&'static str),
19 Overflow {
21 value: i16,
22 expected_bounds: RangeInclusive<i16>,
23 },
24 InvalidExtendedTime { hour: u8, minutes: u8 },
26 InvertedYearRange { start: Year, end: Year, step: u16 },
28 InvertedWeekRange {
30 start: WeekNum,
31 end: WeekNum,
32 step: u8,
33 },
34 GrammarUnexpectedToken { rule: Rule, unexpected: Rule },
36 GrammarLogic { rule: Rule, invariant: &'static str },
38}
39
40impl Error {
41 pub fn is_implementation_error(&self) -> bool {
45 matches!(
46 self,
47 Self::GrammarUnexpectedToken { .. } | Self::GrammarLogic { .. }
48 )
49 }
50}
51
52impl From<pest::error::Error<Rule>> for Error {
53 fn from(pest_err: pest::error::Error<Rule>) -> Self {
54 Self::Syntax(pest_err.into())
55 }
56}
57
58impl fmt::Display for Error {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 Self::Syntax(pest_err) => write!(f, "{pest_err}"),
62 Self::Unsupported(desc) => write!(f, "using an unsupported feature: {desc}"),
63 Self::InvalidExtendedTime { hour, minutes: minute } => {
64 write!(f, "invalid extended time for {hour:02}:{minute:02}")
65 }
66 Self::Overflow { value, expected_bounds } => {
67 write!(
68 f,
69 "{value} is too large: expected a value between {} and {}",
70 expected_bounds.start(),
71 expected_bounds.end(),
72 )
73 }
74 &Self::InvertedYearRange { start, end, .. } => {
75 write!(
76 f,
77 "Inverted year ranges are ambiguous, do you mean '{}-{}'?",
78 *end, *start
79 )
80 }
81 &Self::InvertedWeekRange { start, end, .. } => {
82 write!(
83 f,
84 "Inverted week ranges are ambiguous, do you mean '{}-{}'?",
85 *end, *start
86 )
87 }
88 Error::GrammarUnexpectedToken { rule, unexpected } => {
89 write!(
90 f,
91 "Library implementation error in {rule:?}: found unexpected child {unexpected:?}. "
92 )?;
93
94 write!(f, "Please report an issue at {REPORT_ISSUE_LINK}.")
95 }
96 Self::GrammarLogic { rule, invariant: detail } => {
97 write!(f, "Library implementation error in {rule:?}: {detail}. ")?;
98 write!(f, "Please report an issue at {REPORT_ISSUE_LINK}.")
99 }
100 }
101 }
102}
103
104#[cfg(feature = "std")]
105impl std::error::Error for Error {
106 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
107 match self {
108 Self::Syntax(err) => Some(err as _),
109 _ => None,
110 }
111 }
112}
113
114pub(crate) fn err_empty(rule: Rule) -> Error {
120 Error::GrammarLogic { rule, invariant: "cannot be empty" }
121}