use std::error::Error;
use std::fmt::{Display, Formatter};
use peginator::ParseError;
use super::Step;
use crate::Tessellation;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum SavedGameSyntaxErrorKind {
RleDecodingFailed,
ParsingFailed,
InvalidStepCharacter {
input: char,
tessellation: Tessellation,
},
InvalidStepDirection {
input: Step,
tessellation: Tessellation,
position: usize,
},
}
#[derive(Debug)]
struct ErrorPayload {
kind: SavedGameSyntaxErrorKind,
source: Option<Box<dyn Error>>,
parser_input: Option<String>,
}
#[derive(Debug)]
pub struct SavedGameSyntaxError(Box<ErrorPayload>);
impl SavedGameSyntaxError {
pub fn kind(&self) -> &SavedGameSyntaxErrorKind { &self.0.kind }
pub fn new(kind: SavedGameSyntaxErrorKind) -> Self {
Self(Box::new(ErrorPayload {
kind,
source: None,
parser_input: None,
}))
}
pub fn new_with_source<E>(
kind: SavedGameSyntaxErrorKind, source: Option<E>, input: Option<&str>,
) -> Self
where
E: Into<Box<dyn Error + Send + Sync>>,
{
Self(Box::new(ErrorPayload {
kind,
source: match source {
Some(e) => Some(e.into()),
None => None,
},
parser_input: input.map(std::convert::Into::into),
}))
}
}
impl Display for SavedGameSyntaxError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.0.kind {
SavedGameSyntaxErrorKind::RleDecodingFailed => {
write!(f, "failed to expand run length encoded SavedGame string")
}
SavedGameSyntaxErrorKind::ParsingFailed => {
let at_str = match &self.0.source {
Some(ref_box_dyn) => {
match ref_box_dyn.downcast_ref::<ParseError>() {
Some(e) => format!("at {}", e.position),
None => String::new(),
}
}
None => String::new(),
};
let input_str = match &self.0.parser_input {
Some(s) => format!("\"{s}\""),
None => String::new(),
};
write!(
f,
"{}",
["failed parsing SavedGame string", &input_str, &at_str].join(" ")
)
}
SavedGameSyntaxErrorKind::InvalidStepCharacter {
input,
tessellation,
} => {
write!(
f,
"{tessellation:?} tessellation doesn't recognize '{input}' as valid SavedGame step character"
)
}
SavedGameSyntaxErrorKind::InvalidStepDirection {
input,
tessellation,
position,
} => {
write!(
f,
"pusher Step at {} with direction {:?} is invalid in context of {:?} game tessellation",
position,
input.direction(),
tessellation
)
}
}
}
}
impl Error for SavedGameSyntaxError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.0.source {
Some(ref_box_dyn) => Some(ref_box_dyn.as_ref()),
None => None,
}
}
}