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
86pub 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
102pub(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}