1use std::{error::Error, fmt};
4
5use crate::{
6 error::runtime::InklingError,
7 follow::ChoiceInfo,
8 knot::{Address, AddressKind},
9 node::Stack,
10};
11
12impl Error for InternalError {}
13
14#[derive(Clone, Debug)]
15pub enum InternalError {
30 BadKnotStack(StackError),
32 CouldNotProcess(ProcessError),
34 IncorrectChoiceIndex {
36 selection: usize,
38 available_choices: Vec<ChoiceInfo>,
40 stack_index: usize,
42 stack: Stack,
44 },
45 IncorrectNodeStack(IncorrectNodeStackError),
47 UseOfVariableAsLocation { name: String },
49 UseOfUnvalidatedAddress { address: Address },
51}
52
53impl_from_error![
54 InternalError;
55 [BadKnotStack, StackError],
56 [CouldNotProcess, ProcessError],
57 [IncorrectNodeStack, IncorrectNodeStackError]
58];
59
60impl fmt::Display for InternalError {
61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 use IncorrectNodeStackError::*;
63 use InternalError::*;
64 use ProcessErrorKind::*;
65 use StackError::*;
66
67 match self {
68 BadKnotStack(err) => match err {
69 BadAddress {
70 address: Address::Validated(AddressKind::Location { knot, stitch }),
71 } => write!(
72 f,
73 "The currently set knot address (knot: {}, stitch: {}) does not \
74 actually represent a knot in the story",
75 knot, stitch
76 ),
77 BadAddress { address } => write!(
78 f,
79 "Tried to used a non-validated or non-location `Address` ('{:?}') in \
80 a function",
81 address
82 ),
83 NoLastChoices => write!(
84 f,
85 "Tried to follow with a choice but the last set of presented choices has \
86 not been saved"
87 ),
88 NoRootKnot { knot_name } => write!(
89 f,
90 "After reading a set of knots, the root knot with name {} \
91 does not exist in the set",
92 knot_name
93 ),
94 NoStack => write!(
95 f,
96 "There is no currently set knot or address to follow the story from"
97 ),
98 },
99 CouldNotProcess(ProcessError { kind }) => match kind {
100 InvalidAlternativeIndex => write!(
101 f,
102 "When processing an alternative, an invalid index was used to pick an item"
103 ),
104 InklingError(err) => write!(f, "{}", err),
105 },
106 IncorrectChoiceIndex {
107 selection,
108 ref available_choices,
109 stack_index,
110 ref stack,
111 } => write!(
112 f,
113 "Tried to resume after a choice was made but the chosen index does not exist \
114 in the set of choices. Somehow a faulty set of choices was created from this \
115 branch point and returned upwards, the stack is wrong, or the wrong set of \
116 choices was used elsewhere in the preparation of the choice list. \
117 Selection index: {}, number of branches: {} \
118 (node level: {}, stack: {:?})",
119 selection,
120 available_choices.len(),
121 stack_index,
122 stack
123 ),
124 IncorrectNodeStack(err) => match err {
125 EmptyStack => write!(f, "Tried to advance through a knot with an empty stack"),
126 ExpectedBranchingPoint { stack_index, stack } => {
127 let item_number = stack[*stack_index];
128
129 write!(
130 f,
131 "While resuming a follow the stack found a regular line where \
132 it expected a branch point to nest deeper into. \
133 The stack has been corrupted. \
134 (stack level: {}, item number: {}, stack: {:?}",
135 stack_index, item_number, stack
136 )
137 }
138 MissingBranchIndex { stack_index, stack } => write!(
139 f,
140 "While resuming a follow the stack did not contain an index to \
141 select a branch with from a set of choices. The stack has been \
142 corrupted.
143 (stack level: {}, attempted index: {}, stack: {:?}",
144 stack_index,
145 stack_index + 1,
146 stack
147 ),
148 OutOfBounds {
149 stack_index,
150 stack,
151 num_items,
152 } => write!(
153 f,
154 "Current stack has invalid index {} at node level {}: size of set is {} \
155 (stack: {:?})",
156 stack[*stack_index], stack_index, num_items, stack
157 ),
158 },
159 UseOfVariableAsLocation { name } => write!(
160 f,
161 "Tried to use variable '{}' as a location in the story",
162 name
163 ),
164 UseOfUnvalidatedAddress { address } => {
165 write!(f, "Tried to use unvalidated address '{:?}'", address)
166 }
167 }
168 }
169}
170
171#[derive(Clone, Debug)]
172pub struct ProcessError {
174 pub kind: ProcessErrorKind,
176}
177
178impl From<InklingError> for ProcessError {
179 fn from(err: InklingError) -> Self {
180 ProcessError {
181 kind: ProcessErrorKind::InklingError(Box::new(err)),
182 }
183 }
184}
185
186#[derive(Clone, Debug)]
187pub enum ProcessErrorKind {
189 InvalidAlternativeIndex,
191 InklingError(Box<InklingError>),
193}
194
195#[derive(Clone, Debug)]
196pub enum StackError {
199 NoStack,
201 BadAddress { address: Address },
206 NoLastChoices,
208 NoRootKnot { knot_name: String },
210}
211
212#[derive(Clone, Debug)]
213pub enum IncorrectNodeStackError {
215 EmptyStack,
217 ExpectedBranchingPoint { stack_index: usize, stack: Stack },
219 MissingBranchIndex { stack_index: usize, stack: Stack },
222 OutOfBounds {
224 stack_index: usize,
225 stack: Stack,
226 num_items: usize,
227 },
228}