1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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),
}
}
}