use std::{error::Error, fmt};
use crate::{
error::runtime::InklingError,
follow::ChoiceInfo,
knot::{Address, AddressKind},
node::Stack,
};
impl Error for InternalError {}
#[derive(Clone, Debug)]
pub enum InternalError {
BadKnotStack(StackError),
CouldNotProcess(ProcessError),
IncorrectChoiceIndex {
selection: usize,
available_choices: Vec<ChoiceInfo>,
stack_index: usize,
stack: Stack,
},
IncorrectNodeStack(IncorrectNodeStackError),
UseOfVariableAsLocation { name: String },
UseOfUnvalidatedAddress { address: Address },
}
impl_from_error![
InternalError;
[BadKnotStack, StackError],
[CouldNotProcess, ProcessError],
[IncorrectNodeStack, IncorrectNodeStackError]
];
impl fmt::Display for InternalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use IncorrectNodeStackError::*;
use InternalError::*;
use ProcessErrorKind::*;
use StackError::*;
match self {
BadKnotStack(err) => match err {
BadAddress {
address: Address::Validated(AddressKind::Location { knot, stitch }),
} => write!(
f,
"The currently set knot address (knot: {}, stitch: {}) does not \
actually represent a knot in the story",
knot, stitch
),
BadAddress { address } => write!(
f,
"Tried to used a non-validated or non-location `Address` ('{:?}') in \
a function",
address
),
NoLastChoices => write!(
f,
"Tried to follow with a choice but the last set of presented choices has \
not been saved"
),
NoRootKnot { knot_name } => write!(
f,
"After reading a set of knots, the root knot with name {} \
does not exist in the set",
knot_name
),
NoStack => write!(
f,
"There is no currently set knot or address to follow the story from"
),
},
CouldNotProcess(ProcessError { kind }) => match kind {
InvalidAlternativeIndex => write!(
f,
"When processing an alternative, an invalid index was used to pick an item"
),
InklingError(err) => write!(f, "{}", err),
},
IncorrectChoiceIndex {
selection,
ref available_choices,
stack_index,
ref stack,
} => write!(
f,
"Tried to resume after a choice was made but the chosen index does not exist \
in the set of choices. Somehow a faulty set of choices was created from this \
branch point and returned upwards, the stack is wrong, or the wrong set of \
choices was used elsewhere in the preparation of the choice list. \
Selection index: {}, number of branches: {} \
(node level: {}, stack: {:?})",
selection,
available_choices.len(),
stack_index,
stack
),
IncorrectNodeStack(err) => match err {
EmptyStack => write!(f, "Tried to advance through a knot with an empty stack"),
ExpectedBranchingPoint { stack_index, stack } => {
let item_number = stack[*stack_index];
write!(
f,
"While resuming a follow the stack found a regular line where \
it expected a branch point to nest deeper into. \
The stack has been corrupted. \
(stack level: {}, item number: {}, stack: {:?}",
stack_index, item_number, stack
)
}
MissingBranchIndex { stack_index, stack } => write!(
f,
"While resuming a follow the stack did not contain an index to \
select a branch with from a set of choices. The stack has been \
corrupted.
(stack level: {}, attempted index: {}, stack: {:?}",
stack_index,
stack_index + 1,
stack
),
OutOfBounds {
stack_index,
stack,
num_items,
} => write!(
f,
"Current stack has invalid index {} at node level {}: size of set is {} \
(stack: {:?})",
stack[*stack_index], stack_index, num_items, stack
),
},
UseOfVariableAsLocation { name } => write!(
f,
"Tried to use variable '{}' as a location in the story",
name
),
UseOfUnvalidatedAddress { address } => {
write!(f, "Tried to use unvalidated address '{:?}'", address)
}
}
}
}
#[derive(Clone, Debug)]
pub struct ProcessError {
pub kind: ProcessErrorKind,
}
impl From<InklingError> for ProcessError {
fn from(err: InklingError) -> Self {
ProcessError {
kind: ProcessErrorKind::InklingError(Box::new(err)),
}
}
}
#[derive(Clone, Debug)]
pub enum ProcessErrorKind {
InvalidAlternativeIndex,
InklingError(Box<InklingError>),
}
#[derive(Clone, Debug)]
pub enum StackError {
NoStack,
BadAddress { address: Address },
NoLastChoices,
NoRootKnot { knot_name: String },
}
#[derive(Clone, Debug)]
pub enum IncorrectNodeStackError {
EmptyStack,
ExpectedBranchingPoint { stack_index: usize, stack: Stack },
MissingBranchIndex { stack_index: usize, stack: Stack },
OutOfBounds {
stack_index: usize,
stack: Stack,
num_items: usize,
},
}