firefly_runtime/
error.rs

1use core::fmt;
2
3pub enum Error {
4    Wasmi(wasmi::Error),
5    FuncCall(&'static str, wasmi::Error, RuntimeStats),
6    FileEmpty(&'static str),
7    OpenDir(alloc::string::String, firefly_hal::FSError),
8    OpenFile(&'static str, firefly_hal::FSError),
9    ReadFile(&'static str, firefly_hal::FSError),
10    NoLauncher,
11    InvalidAuthorID(firefly_types::ValidationError),
12    InvalidAppID(firefly_types::ValidationError),
13    CannotDisplay,
14    AuthorIDMismatch,
15    AppIDMismatch,
16
17    DecodeMeta(postcard::Error),
18    DecodeStats(postcard::Error),
19    SerialEncode(postcard::Error),
20    SerialDecode(postcard::Error),
21
22    SerialStart(firefly_hal::NetworkError),
23    SerialSend(firefly_hal::NetworkError),
24    SerialRecv(firefly_hal::NetworkError),
25
26    CheatUndefined,
27    CheatInNet,
28}
29
30impl fmt::Display for Error {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        match self {
33            Error::Wasmi(err) => {
34                write!(f, "wasm error: ")?;
35                use wasmi::errors::ErrorKind::*;
36                match err.kind() {
37                    TrapCode(_) => write!(f, "trap code: {err}"),
38                    Message(_) => write!(f, "message: {err}"),
39                    I32ExitStatus(_) => write!(f, "exit status: {err}"),
40                    Host(_) => write!(f, "host: {err}"),
41                    Global(_) => write!(f, "global: {err}"),
42                    Memory(_) => write!(f, "memory: {err}"),
43                    Table(_) => write!(f, "table: {err}"),
44                    Linker(_) => write!(f, "linker: {err}"),
45                    Instantiation(_) => write!(f, "instantiation: {err}"),
46                    Fuel(_) => write!(f, "fuel: {err}"),
47                    Func(_) => write!(f, "func: {err}"),
48                    Read(_) => write!(f, "read: {err}"),
49                    Wasm(_) => write!(f, "parse: {err}"),
50                    Translation(_) => write!(f, "translation: {err}"),
51                    Limits(_) => write!(f, "limits: {err}"),
52                    Ir(_) => write!(f, "IR: {err}"),
53                    _ => write!(f, "unknown: {err}"),
54                }
55            }
56            Error::FileEmpty(s) => write!(f, "file is empty: {s}"),
57            Error::OpenDir(s, e) => write!(f, "cannot open {s} dir: {e}"),
58            Error::OpenFile(s, e) => write!(f, "cannot open {s} file: {e}"),
59            Error::NoLauncher => write!(f, "no launcher installed"),
60            Error::FuncCall(func, err, stats) => write!(f, "error calling {func}: {err}.\n{stats}"),
61            Error::InvalidAuthorID(err) => write!(f, "invalid author ID: {err}"),
62            Error::InvalidAppID(err) => write!(f, "invalid app ID: {err}"),
63            Error::CannotDisplay => write!(f, "failed to draw on the display"),
64            Error::ReadFile(name, err) => write!(f, "cannot read {name}: {err}"),
65            Error::AuthorIDMismatch => write!(f, "author ID in meta and in path don't match"),
66            Error::AppIDMismatch => write!(f, "app ID in meta and in path don't match"),
67            Error::DecodeMeta(err) => write!(f, "cannot decode _meta: {err}"),
68            Error::DecodeStats(err) => write!(f, "cannot decode stats: {err}"),
69            Error::SerialEncode(err) => write!(f, "cannot encode response for serial: {err}"),
70            Error::SerialDecode(err) => write!(f, "cannot decode request from serial: {err}"),
71            Error::SerialStart(err) => write!(f, "cannot connect to serial port: {err}"),
72            Error::SerialSend(err) => write!(f, "cannot send into serial port: {err}"),
73            Error::SerialRecv(err) => write!(f, "cannot read from serial port: {err}"),
74            Error::CheatUndefined => write!(f, "the app doesn't have cheat callback"),
75            Error::CheatInNet => write!(f, "cheats are disabled in multiplayer"),
76        }
77    }
78}
79
80impl From<wasmi::Error> for Error {
81    fn from(value: wasmi::Error) -> Self {
82        Self::Wasmi(value)
83    }
84}
85
86/// Runtime stats provided on guest failure that should help to debug the failure cause.
87pub struct RuntimeStats {
88    pub(crate) last_called: &'static str,
89}
90
91impl fmt::Display for RuntimeStats {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        if self.last_called.is_empty() {
94            writeln!(f, "No host functions were called.")?;
95        } else {
96            writeln!(f, "The last called host function is {}.", self.last_called)?;
97        }
98        Ok(())
99    }
100}
101
102/// Errors logged into console by host-defined functions.
103pub(crate) enum HostError {
104    MemoryNotFound,
105    OomPointer,
106    BufferSize,
107    DataFileInNet,
108    FileReadOnly,
109    FileNotFound,
110    FileRead(firefly_hal::FSError),
111    FileWrite,
112    FileFlush,
113    FileNameUtf8,
114    FileName(firefly_types::ValidationError),
115    MenuItemUtf8,
116    IdUtf8,
117    Id(firefly_types::ValidationError),
118    TextUtf8,
119    InvalidWidth,
120    NoneColor,
121    UnknownPeer(u32),
122    AudioNode(firefly_audio::NodeError),
123    NoStats,
124    NoBadges,
125    NoBadge(u32),
126    NoBoards,
127    NoBoard(u32),
128    ValueTooBig,
129}
130
131impl fmt::Display for HostError {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            HostError::MemoryNotFound => write!(f, "memory not found"),
135            HostError::FileReadOnly => write!(f, "files in the app ROM cannot be modified"),
136            HostError::DataFileInNet => write!(f, "cannot read data files in multiplayer"),
137            HostError::OomPointer => write!(f, "buffer points out of memory"),
138            HostError::FileRead(e) => write!(f, "cannot read file: {e}"),
139            HostError::FileWrite => write!(f, "cannot write file"),
140            HostError::FileNotFound => write!(f, "file not found"),
141            HostError::FileFlush => write!(f, "cannot flush file"),
142            HostError::BufferSize => write!(f, "buffer size for file does not match file size"),
143            HostError::FileNameUtf8 => write!(f, "file name is not valid UTF-8"),
144            HostError::FileName(err) => write!(f, "bad file name: {err}"),
145            HostError::MenuItemUtf8 => write!(f, "menu item name is not valid UTF-8"),
146            HostError::IdUtf8 => write!(f, "ID is not valid UTF-8"),
147            HostError::Id(err) => write!(f, "bad ID: {err}"),
148            HostError::TextUtf8 => write!(f, "text is not valid UTF-8"),
149            HostError::InvalidWidth => write!(f, "the image has invalid width"),
150            HostError::NoneColor => write!(f, "color is None (0)"),
151            HostError::UnknownPeer(p) => write!(f, "peer {p} is not connected"),
152            HostError::AudioNode(err) => write!(f, "audio node error: {err}"),
153            HostError::NoStats => write!(f, "the app doesn't have stats file"),
154            HostError::NoBadges => write!(f, "the app doesn't have any badges"),
155            HostError::NoBadge(id) => write!(f, "the app doesn't have a badge with ID {id}"),
156            HostError::NoBoards => write!(f, "the app doesn't have any boards"),
157            HostError::NoBoard(id) => write!(f, "the app doesn't have a board with ID {id}"),
158            HostError::ValueTooBig => write!(f, "the value is too big"),
159        }
160    }
161}