use std::{error::Error, fmt};
use crate::{
error::{runtime::internal::StackError, variable::VariableError, InternalError},
knot::{Address, AddressKind},
line::Variable,
story::Choice,
};
impl Error for InklingError {}
#[derive(Clone, Debug)]
pub enum InklingError {
Internal(InternalError),
InvalidAddress {
knot: String,
stitch: Option<String>,
},
InvalidChoice {
selection: usize,
presented_choices: Vec<Choice>,
},
InvalidVariable {
name: String,
},
MadeChoiceWithoutChoice,
OutOfChoices {
address: Address,
},
OutOfContent,
PrintInvalidVariable {
name: String,
value: Variable,
},
ResumeBeforeStart,
StartOnStoryInProgress,
VariableError(VariableError),
}
impl From<StackError> for InklingError {
fn from(err: StackError) -> Self {
InklingError::Internal(InternalError::BadKnotStack(err))
}
}
impl_from_error![
InklingError;
[Internal, InternalError],
[VariableError, VariableError]
];
impl fmt::Display for InklingError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use InklingError::*;
match self {
Internal(err) => write!(f, "INTERNAL ERROR: {}", err),
InvalidAddress { knot, stitch } => match stitch {
Some(stitch_name) => write!(
f,
"Invalid address: knot '{}' does not contain a stitch named '{}'",
knot, stitch_name
),
None => write!(
f,
"Invalid address: story does not contain a knot name '{}'",
knot
),
},
InvalidChoice {
selection,
presented_choices,
} => write!(
f,
"Invalid selection of choice: selection was {} but number of choices was {} \
(maximum selection index is {})",
selection,
presented_choices.len(),
presented_choices.len() - 1
),
InvalidVariable { name } => write!(
f,
"Invalid variable: no variable with name '{}' exists in the story",
name
),
MadeChoiceWithoutChoice => write!(
f,
"Tried to make a choice, but no choice is currently active. Call `resume` \
and assert that a branching choice is returned before calling this again."
),
OutOfChoices {
address: Address::Validated(AddressKind::Location { knot, stitch }),
} => write!(
f,
"Story reached a branching choice with no available choices to present \
or default choices to fall back on (knot: {}, stitch: {})",
knot, stitch
),
OutOfChoices { address } => write!(
f,
"Internal error: Tried to use a non-validated or non-location `Address` ('{:?}') \
when following a story",
address
),
OutOfContent => write!(f, "Story ran out of content before an end was reached"),
PrintInvalidVariable { name, value } => write!(
f,
"Cannot print variable '{}' which has value '{:?}': invalid type",
name, value
),
ResumeBeforeStart => write!(f, "Tried to resume a story that has not yet been started"),
StartOnStoryInProgress => {
write!(f, "Called `start` on a story that is already in progress")
}
VariableError(err) => write!(f, "{}", err),
}
}
}