Skip to main content

sokoban_elements/sokoban_plus/
errors.rs

1use std::error::Error;
2use std::fmt::{Display, Formatter};
3use std::num::ParseIntError;
4
5use crate::sokoban_plus::BoxID;
6
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub(super) enum SokobanPlusInputKind {
9    Boxorder,
10    Goalorder,
11}
12
13/// Variants of input for [`SokobanPlusSyntaxError`]
14#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
15pub enum SokobanPlusSyntaxErrorKind {
16    ParseIntError,
17    TooManyPlusIDs,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21struct ErrorPayload {
22    pos:        usize,
23    input_kind: SokobanPlusInputKind,
24    kind:       SokobanPlusSyntaxErrorKind,
25    source:     Option<ParseIntError>,
26}
27
28/// [`std::Error`](std::error::Error) when parsing [`SokobanPlus`](crate::SokobanPlus).
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct SokobanPlusSyntaxError(Box<ErrorPayload>);
31
32impl SokobanPlusSyntaxError {
33    pub(super) fn new(
34        pos: usize, input_kind: SokobanPlusInputKind, kind: SokobanPlusSyntaxErrorKind,
35        source: Option<ParseIntError>,
36    ) -> Self {
37        Self(Box::new(ErrorPayload {
38            pos,
39            input_kind,
40            kind,
41            source,
42        }))
43    }
44
45    pub fn kind(&self) -> SokobanPlusSyntaxErrorKind { self.0.kind }
46}
47
48impl Display for SokobanPlusSyntaxError {
49    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50        let input_kind_s = match self.0.input_kind {
51            SokobanPlusInputKind::Boxorder => "boxorder",
52            SokobanPlusInputKind::Goalorder => "goalorder",
53        };
54
55        match self.0.kind {
56            SokobanPlusSyntaxErrorKind::ParseIntError => {
57                write!(
58                    f,
59                    "failed parsing Sokoban+ IDs from {} at {}",
60                    input_kind_s, self.0.pos
61                )
62            }
63
64            SokobanPlusSyntaxErrorKind::TooManyPlusIDs => {
65                write!(
66                    f,
67                    "Sokoban+ {} can't assign more Sokoban+ IDs than maximum allowed number of {} ({})",
68                    input_kind_s,
69                    match self.0.input_kind {
70                        SokobanPlusInputKind::Boxorder => "boxes",
71                        SokobanPlusInputKind::Goalorder => "goals",
72                    },
73                    BoxID::MAX
74                )
75            }
76        }
77    }
78}
79
80impl Error for SokobanPlusSyntaxError {
81    fn source(&self) -> Option<&(dyn Error + 'static)> {
82        match &self.0.source {
83            Some(ref_box_dyn) => Some(ref_box_dyn),
84            None => None,
85        }
86    }
87}