Skip to main content

nifty_runtime/
failure.rs

1//! Why running an app's code can fail. The interpreter and compiled apps both report these,
2//! so an app fails the same way however it runs.
3
4use std::fmt;
5
6/// How deeply functions may call each other before the app stops with an error. The
7/// interpreter takes roughly 10 KB of native stack per call in debug builds, so this stops
8/// runaway recursion well before a 2 MB thread stack overflows.
9pub const MAX_CALL_DEPTH: usize = 128;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum Failure {
13    DivideByZero,
14    /// An `int` result outside the 64-bit range.
15    TooLarge,
16    /// A length that doesn't fit in an `int`.
17    TooLong,
18    NegativePosition(i64),
19    NoItem {
20        position: usize,
21        len: usize,
22    },
23    /// A call deeper than [`MAX_CALL_DEPTH`], into the function named `function`.
24    TooDeep {
25        function: String,
26    },
27    DownloadIntoVariable,
28    /// A file dialog's answer bound to a variable, which is gone by the time it closes.
29    DialogIntoVariable,
30    /// The platform couldn't show a file dialog or read its answer, for this reason.
31    Dialog(String),
32}
33
34impl fmt::Display for Failure {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Self::DivideByZero => f.write_str("can't divide by zero"),
38            Self::TooLarge => f.write_str("this number is too large"),
39            Self::TooLong => f.write_str("this is too long to count"),
40            Self::NegativePosition(index) => {
41                write!(f, "list positions start at 0, so {index} isn't one")
42            }
43            Self::NoItem { position, len } => {
44                write!(f, "there is no item {position}; the list has {len}")
45            }
46            Self::TooDeep { function } => {
47                write!(
48                    f,
49                    "`{function}` calls itself too deeply; does it ever stop?"
50                )
51            }
52            Self::DownloadIntoVariable => {
53                f.write_str("`download` can only report into state, not into a variable")
54            }
55            Self::DialogIntoVariable => {
56                f.write_str("a file dialog can only answer into state, not into a variable")
57            }
58            Self::Dialog(reason) => write!(f, "the file dialog failed: {reason}"),
59        }
60    }
61}