Skip to main content

firefly_runtime/
error.rs

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