use crate::{
line::ChoiceData,
node::{NodeItem, NodeType, Stack},
story::Choice,
};
use std::{error::Error, fmt};
#[derive(Clone, Debug)]
pub enum InklingError {
BadGraph(BadGraphKind),
IncorrectStack {
kind: IncorrectStackKind,
stack: Stack,
},
InvalidChoice {
index: usize,
choice: Option<Choice>,
presented_choices: Vec<(bool, Choice)>,
internal_choices: Vec<ChoiceData>,
},
NoKnotStack,
ResumeBeforeStart,
StartOnStoryInProgress,
UnknownKnot { knot_name: String },
}
impl fmt::Display for InklingError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use IncorrectStackKind::*;
use InklingError::*;
match self {
BadGraph(BadGraphKind::ExpectedNode {
index,
node_level,
expected,
found,
}) => write!(
f,
"Expected a `DialogueNode` that is a {:?} but got a {:?} \
(node level: {}, index: {})",
expected, found, node_level, index
),
InvalidChoice {
index,
choice,
presented_choices,
..
} => {
let presented_choices_string = presented_choices
.iter()
.map(|(shown, choice)| {
if *shown {
format!("{:?} (shown as available)", choice)
} else {
format!("{:?} (not shown)", choice)
}
})
.collect::<Vec<_>>()
.join("\n");
match choice {
Some(choice) => {
write!(f,
"Tried to resume the story with an invalid choice: input choice was {:?}, \
while available choices were: \n
{}",
choice, presented_choices_string
)
}
None => write!(
f,
"Tried to resume the story with an invalid choice: \
input choice cannot be found but its internal index was {}, \
available choices were: [{}]",
index, presented_choices_string
),
}
}
NoKnotStack => write!(
f,
"`Story` object was created but no root `Knot` was set to start \
following the story from"
),
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")
}
UnknownKnot { knot_name } => write!(
f,
"Tried to follow a knot with name {} but no such knot exists",
knot_name
),
IncorrectStack { kind, stack } => match kind {
BadIndices {
node_level,
index,
num_items,
} => write!(
f,
"Current stack has invalid index {} at node level {}: size of set is {} \
(stack: {:?})",
index, node_level, num_items, stack
),
EmptyStack => write!(f, "Tried to advance through a knot with an empty stack"),
Gap { node_level } => write!(
f,
"Current stack is too short for the current node level {}: \
cannot get or add a stack index because stack indices for one or more \
prior nodes are missing, which means the stack is incorrect (stack: {:?})",
node_level, stack
),
MissingIndices { node_level, kind } => {
let level = match kind {
WhichIndex::Parent => *node_level,
WhichIndex::Child => *node_level + 1,
};
write!(f, "Current stack has no index for node level {}", level)?;
if let WhichIndex::Child = kind {
write!(f, ", which was accessed as a child node during a follow")?;
}
write!(f, " (stack: {:?}", stack)
}
NotTruncated { node_level } => write!(
f,
"Current stack is not truncated to the current node level {} (stack: {:?})",
node_level, stack
),
},
}
}
}
impl Error for InklingError {}
#[derive(Clone, Debug)]
pub enum BadGraphKind {
ExpectedNode {
index: usize,
node_level: usize,
expected: NodeItemKind,
found: NodeItemKind,
},
}
#[derive(Clone, Debug)]
pub enum NodeItemKind {
Line,
Choice,
ChoiceSet,
}
impl From<&NodeItem> for NodeItemKind {
fn from(item: &NodeItem) -> Self {
match item {
NodeItem::Line(..) => NodeItemKind::Line,
NodeItem::Node {
kind: NodeType::Choice(..),
..
} => NodeItemKind::Choice,
NodeItem::Node {
kind: NodeType::ChoiceSet,
..
} => NodeItemKind::ChoiceSet,
}
}
}
#[derive(Clone, Debug)]
pub enum IncorrectStackKind {
BadIndices {
node_level: usize,
index: usize,
num_items: usize,
},
EmptyStack,
Gap { node_level: usize },
MissingIndices { node_level: usize, kind: WhichIndex },
NotTruncated { node_level: usize },
}
#[derive(Clone, Debug)]
pub enum WhichIndex {
Parent,
Child,
}