oc_wasm_opencomputers/error.rs
1//! Provides an error type used for higher level calls.
2
3use core::fmt::{Display, Formatter};
4
5/// The errors that a component call can return.
6#[derive(Clone, Debug, Eq, Hash, PartialEq)]
7pub enum Error {
8 /// The call was addressed to a component that does not exist, is not accessible, or is of the
9 /// wrong type.
10 ///
11 /// The underlying syscall error is encapsulated.
12 BadComponent(oc_wasm_safe::error::Error),
13
14 /// An unsupported screen resolution, viewport size, or screen coordinate was requested.
15 BadCoordinate,
16
17 /// An unsupported colour depth was requested.
18 BadDepth,
19
20 /// The filename passed to a function is structurally invalid to be a filename.
21 BadFilename,
22
23 /// The character to use to fill the screen lies outside the basic multilingual plane and
24 /// therefore cannot be used for filling.
25 BadFillCharacter,
26
27 /// An index number is outside the range of slots for an inventory or tanks for a
28 /// fluid-containing block.
29 ///
30 /// In the case of item inventories, this is only returned if the block is in fact an
31 /// inventory; [`NoInventory`](Self::NoInventory) is returned for non-inventories. In the case
32 /// of fluid containers, this is also returned if the block is not a fluid container at all (it
33 /// is treated as a fluid container with zero tanks), but not if the block is in an unloaded
34 /// chunk.
35 BadInventorySlot,
36
37 /// An item is not usable for the requested purpose.
38 ///
39 /// For example, an item that does not hold fluid cannot have its fluid level or capacity
40 /// queried.
41 BadItem,
42
43 /// A set-colour request tried to set a colour by palette index, and the palette index was
44 /// unacceptable. This could be because the palette index was outside the range of the palette
45 /// for the current bit depth, or it could be because the current bit depth does not support a
46 /// palette at all.
47 BadPaletteIndex,
48
49 /// The address specified when binding a GPU does not exist, is inaccessible, or is not a
50 /// screen; or, a GPU operation which requires a screen was executed when the GPU is unbound or
51 /// the screen to which it was bound has been disconnected.
52 BadScreen,
53
54 /// The robot cannot move because there is something in the way.
55 Blocked(super::robot::BlockContent),
56
57 /// The checksum passed when trying to make an EEPROM read-only does not match the checksum of
58 /// the contents of the EEPROM.
59 ChecksumMismatch,
60
61 /// The data (e.g. to write to a file or EEPROM or send over a communication interface) is too
62 /// large.
63 DataTooLarge,
64
65 /// The named file or directory does not exist.
66 FileNotFound,
67
68 /// The robot tried to move to a position that is too far away from support (and does not have
69 /// a suitable hover upgrade to allow such movement), tried to move into an unloaded chunk, or
70 /// the destination is otherwise unsuitable for a reason other than there being something in
71 /// the way.
72 ImpossibleMove,
73
74 /// An attempt was made to move an item or fluid into an inventory slot or tank, but it could
75 /// not be inserted because the slot or tank is full, or the existing contents are not
76 /// compatible with the new addition.
77 InventoryFull,
78
79 /// A seek in a file would place the file pointer at a negative position.
80 NegativeSeek,
81
82 /// There is no item in an inventory slot when one is required.
83 NoItem,
84
85 /// There is no inventory in the specified location. This includes if the inventory is in an
86 /// unloaded chunk.
87 ///
88 /// This is also returned when attempting to access a fluid tank in an unloaded chunk, but not
89 /// when attempting to access a fluid tank in a block that does not contain any tanks; in the
90 /// latter case, [`BadInventorySlot`](Self::BadInventorySlot) is used instead.
91 NoInventory,
92
93 /// The computer does not have enough energy to perform the operation.
94 NotEnoughEnergy,
95
96 /// The storage (e.g. EEPROM or filesystem) cannot be written to because it is read-only.
97 StorageReadOnly,
98
99 /// There are too many open descriptors.
100 TooManyDescriptors,
101
102 /// There are too many listening network ports.
103 TooManyOpenPorts,
104
105 /// There are too many parts in a packet.
106 TooManyParts,
107
108 /// The operation is not supported for this component.
109 ///
110 /// For example:
111 /// * An attempt was made to set a filesystem’s label, but this particular filesystem does not
112 /// support labels.
113 /// * An attempt was made to access item stack information in an inventory, but detailed item
114 /// information access is disabled in the configuration file.
115 Unsupported,
116
117 /// The operation failed but no more detailed information is available at the type level. The
118 /// individual method may document more specific reasons for this error to appear.
119 Failed,
120}
121
122impl Error {
123 /// Returns a string describing the error.
124 #[must_use = "This function is only useful for its return value"]
125 pub fn as_str(&self) -> &'static str {
126 match self {
127 Self::BadComponent(_) => "nonexistent or incorrect component",
128 Self::BadCoordinate => "bad coordinate",
129 Self::BadDepth => "bad depth",
130 Self::BadFilename => "bad filename",
131 Self::BadFillCharacter => "bad fill character",
132 Self::BadInventorySlot => "bad inventory slot",
133 Self::BadItem => "bad item",
134 Self::BadPaletteIndex => "bad palette index",
135 Self::BadScreen => "bad screen",
136 Self::Blocked(super::robot::BlockContent::Entity) => "blocked by entity",
137 Self::Blocked(super::robot::BlockContent::Air) => "blocked by air",
138 Self::Blocked(super::robot::BlockContent::Liquid) => "blocked by liquid",
139 Self::Blocked(super::robot::BlockContent::Replaceable) => "blocked by replaceable",
140 Self::Blocked(super::robot::BlockContent::Passable) => "blocked by passable",
141 Self::Blocked(super::robot::BlockContent::Solid) => "blocked by solid",
142 Self::ChecksumMismatch => "checksum mismatch",
143 Self::DataTooLarge => "data too large",
144 Self::FileNotFound => "file not found",
145 Self::ImpossibleMove => "impossible move",
146 Self::InventoryFull => "inventory full",
147 Self::NegativeSeek => "seek to negative position",
148 Self::NoInventory => "no inventory",
149 Self::NoItem => "no item",
150 Self::NotEnoughEnergy => "not enough energy",
151 Self::StorageReadOnly => "storage is read-only",
152 Self::TooManyDescriptors => "too many descriptors",
153 Self::TooManyOpenPorts => "too many open ports",
154 Self::TooManyParts => "too many parts",
155 Self::Unsupported => "unsupported",
156 Self::Failed => "failed",
157 }
158 }
159}
160
161impl Display for Error {
162 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
163 match self {
164 Self::BadComponent(e) => write!(f, "nonexistent or incorrect component: {e}"),
165 _ => self.as_str().fmt(f),
166 }
167 }
168}
169
170#[cfg(feature = "std")]
171impl std::error::Error for Error {
172 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
173 match self {
174 Self::BadComponent(underlying) => Some(underlying),
175 Self::BadCoordinate
176 | Self::BadDepth
177 | Self::BadFilename
178 | Self::BadFillCharacter
179 | Self::BadInventorySlot
180 | Self::BadItem
181 | Self::BadPaletteIndex
182 | Self::BadScreen
183 | Self::Blocked(_)
184 | Self::ChecksumMismatch
185 | Self::DataTooLarge
186 | Self::FileNotFound
187 | Self::ImpossibleMove
188 | Self::InventoryFull
189 | Self::NegativeSeek
190 | Self::NoInventory
191 | Self::NoItem
192 | Self::NotEnoughEnergy
193 | Self::StorageReadOnly
194 | Self::TooManyDescriptors
195 | Self::TooManyOpenPorts
196 | Self::TooManyParts
197 | Self::Unsupported
198 | Self::Failed => None,
199 }
200 }
201}
202
203impl From<oc_wasm_safe::error::Error> for Error {
204 fn from(source: oc_wasm_safe::error::Error) -> Self {
205 match source {
206 oc_wasm_safe::error::Error::BadParameters | oc_wasm_safe::error::Error::Other => {
207 Self::Failed
208 }
209 oc_wasm_safe::error::Error::TooManyDescriptors => Self::TooManyDescriptors,
210 _ => Self::BadComponent(source),
211 }
212 }
213}
214
215impl From<oc_wasm_safe::component::MethodCallError<'_>> for Error {
216 fn from(source: oc_wasm_safe::component::MethodCallError<'_>) -> Self {
217 source.simplify().into()
218 }
219}