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
96pub 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
112pub(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}