sokoban_elements/saved_game/
errors.rs1use std::error::Error;
2use std::fmt::{Display, Formatter};
3
4use peginator::ParseError;
5
6use super::Step;
7use crate::Tessellation;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11pub enum SavedGameSyntaxErrorKind {
12 RleDecodingFailed,
13 ParsingFailed,
14 InvalidStepCharacter {
15 input: char,
16 tessellation: Tessellation,
17 },
18 InvalidStepDirection {
19 input: Step,
20 tessellation: Tessellation,
21 position: usize,
22 },
23}
24
25#[derive(Debug)]
26struct ErrorPayload {
27 kind: SavedGameSyntaxErrorKind,
28 source: Option<Box<dyn Error>>,
29 parser_input: Option<String>,
30}
31
32#[derive(Debug)]
34pub struct SavedGameSyntaxError(Box<ErrorPayload>);
35
36impl SavedGameSyntaxError {
37 pub fn kind(&self) -> &SavedGameSyntaxErrorKind { &self.0.kind }
38
39 pub fn new(kind: SavedGameSyntaxErrorKind) -> Self {
40 Self(Box::new(ErrorPayload {
41 kind,
42 source: None,
43 parser_input: None,
44 }))
45 }
46
47 pub fn new_with_source<E>(
48 kind: SavedGameSyntaxErrorKind, source: Option<E>, input: Option<&str>,
49 ) -> Self
50 where
51 E: Into<Box<dyn Error + Send + Sync>>,
52 {
53 Self(Box::new(ErrorPayload {
54 kind,
55 source: match source {
56 Some(e) => Some(e.into()),
57 None => None,
58 },
59 parser_input: input.map(std::convert::Into::into),
60 }))
61 }
62}
63
64impl Display for SavedGameSyntaxError {
65 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
66 match &self.0.kind {
67 SavedGameSyntaxErrorKind::RleDecodingFailed => {
68 write!(f, "failed to expand run length encoded SavedGame string")
69 }
70
71 SavedGameSyntaxErrorKind::ParsingFailed => {
72 let at_str = match &self.0.source {
73 Some(ref_box_dyn) => {
74 match ref_box_dyn.downcast_ref::<ParseError>() {
75 Some(e) => format!("at {}", e.position),
76 None => String::new(),
77 }
78 }
79 None => String::new(),
80 };
81
82 let input_str = match &self.0.parser_input {
83 Some(s) => format!("\"{s}\""),
84 None => String::new(),
85 };
86
87 write!(
88 f,
89 "{}",
90 ["failed parsing SavedGame string", &input_str, &at_str].join(" ")
91 )
92 }
93
94 SavedGameSyntaxErrorKind::InvalidStepCharacter {
95 input,
96 tessellation,
97 } => {
98 write!(
99 f,
100 "{tessellation:?} tessellation doesn't recognize '{input}' as valid SavedGame step character"
101 )
102 }
103
104 SavedGameSyntaxErrorKind::InvalidStepDirection {
105 input,
106 tessellation,
107 position,
108 } => {
109 write!(
110 f,
111 "pusher Step at {} with direction {:?} is invalid in context of {:?} game tessellation",
112 position,
113 input.direction(),
114 tessellation
115 )
116 }
117 }
118 }
119}
120
121impl Error for SavedGameSyntaxError {
122 fn source(&self) -> Option<&(dyn Error + 'static)> {
123 match &self.0.source {
124 Some(ref_box_dyn) => Some(ref_box_dyn.as_ref()),
125 None => None,
126 }
127 }
128}