gaia_types/errors/mod.rs
1#![doc = include_str!("readme.md")]
2
3pub use self::diagnostics::GaiaDiagnostics;
4use crate::{
5 helpers::{Architecture, CompilationTarget},
6 reader::SourceLocation,
7};
8use std::{
9 error::Error,
10 fmt::{Debug, Display, Formatter},
11 panic::Location,
12};
13use tracing::Level;
14use url::Url;
15
16mod convert;
17mod diagnostics;
18mod display;
19
20/// 本crate的结果类型,使用GaiaError作为错误类型
21///
22/// 这个类型别名简化了错误处理,所有可能返回错误的函数都应该使用这个类型
23pub type Result<T> = std::result::Result<T, GaiaError>;
24
25/// Gaia 错误类型,包装了具体的错误类 [GaiaErrorKind]
26///
27/// 这里使用 [Box] 来减少枚举的大小,提高性能
28pub struct GaiaError {
29 level: Level,
30 /// 具体的错误种类,使用Box包装以减少内存占用
31 ///
32 /// 这个字段包含了实际的错误信息,通过Box指针间接存储,
33 /// 这样可以避免在栈上分配较大的枚举值,提高性能
34 kind: Box<GaiaErrorKind>,
35}
36
37/// Gaia 错误种类枚举,定义了所有可能的错误类型
38#[derive(Debug)]
39pub enum GaiaErrorKind {
40 /// 无效指令错误,当解析到未知或不支持的指令时使用
41 InvalidInstruction {
42 /// 无效的指令字符串
43 instruction: String,
44 /// 指令所属的架构
45 architecture: Architecture,
46 },
47 /// 不支持的架构错误,当尝试在不支持的架构上执行操作时使用
48 UnsupportedArchitecture {
49 /// 不支持的架构
50 architecture: Architecture,
51 },
52 /// 无效范围错误,当实际长度与期望长度不匹配时使用
53 ///
54 /// 这种错误通常发生在解析二进制数据或验证数据结构时,
55 /// 当实际数据长度与期望的长度不符时抛出此错误。
56 InvalidRange {
57 /// 实际长度
58 ///
59 /// 表示实际测量或解析得到的数据长度。
60 length: usize,
61 /// 期望长度
62 ///
63 /// 表示根据规范或预期应该具有的长度。
64 expect: usize,
65 },
66 /// IO 错误,包含底层的 IO 错误和可选的 URL 信息
67 ///
68 /// 当文件读写、网络请求等 IO 操作失败时使用
69 IoError {
70 /// 底层的 IO 错误
71 ///
72 /// 包含了具体的 IO 错误信息,如文件不存在、权限不足等。
73 io_error: std::io::Error,
74 /// 与 IO 操作相关的 URL,可选
75 ///
76 /// 如果 IO 操作与特定文件或网络资源相关,这里存储其 URL。
77 /// 可以是文件系统路径或网络地址。
78 url: Option<Url>,
79 },
80 /// 语法错误,包含错误消息和源代码位置信息
81 ///
82 /// 当解析源代码发现语法问题时使用,提供详细的错误位置信息
83 SyntaxError {
84 /// 错误消息,描述具体的语法问题
85 ///
86 /// 包含了人类可读的语法错误描述,如 "缺少分号"、"未闭合的括号" 等。
87 message: String,
88 /// 错误发生的源代码位置信息
89 ///
90 /// 包含了错误所在的文件、行号、列号等位置信息,
91 /// 帮助开发者快速定位问题。
92 location: SourceLocation,
93 },
94 /// 停止运行
95 StageError {
96 /// 停止运行的地方
97 location: Location<'static>,
98 },
99 /// 功能未实现错误
100 ///
101 /// 当调用尚未实现的功能时使用
102 NotImplemented {
103 /// 未实现功能的描述
104 feature: String,
105 },
106 /// 不支持的功能错误
107 ///
108 /// 当尝试使用不支持的功能时使用
109 UnsupportedFeature {
110 /// 不支持的功能描述
111 feature: String,
112 /// 错误发生的源代码位置信息
113 location: SourceLocation,
114 },
115 /// 自定义错误,包含自定义的错误消息
116 ///
117 /// 当需要表示特定业务逻辑错误或其他非标准错误时使用
118 CustomError {
119 /// 自定义错误消息
120 message: String,
121 },
122 /// 适配器错误,当适配器操作失败时使用
123 ///
124 /// 包含适配器名称和具体的错误信息
125 AdapterError {
126 /// 适配器名称
127 adapter_name: String,
128 /// 错误消息
129 message: String,
130 /// 可选的源错误
131 source: Option<Box<GaiaError>>,
132 },
133 /// 平台不支持错误,当目标平台不支持某个操作时使用
134 ///
135 /// 包含平台名称和不支持的操作描述
136 PlatformUnsupported {
137 /// 平台名称
138 platform: String,
139 /// 不支持的操作描述
140 operation: String,
141 },
142 /// 配置错误,当配置文件解析或验证失败时使用
143 ///
144 /// 包含配置文件路径和错误信息
145 ConfigError {
146 /// 配置文件路径
147 config_path: Option<String>,
148 /// 错误消息
149 message: String,
150 },
151 /// 不支持的编译目标错误
152 ///
153 /// 当尝试编译到不支持的目标平台时使用
154 UnsupportedTarget {
155 /// 不支持的编译目标
156 target: CompilationTarget,
157 },
158 /// 编译失败错误
159 ///
160 /// 当编译过程中发生错误时使用
161 CompilationFailed {
162 /// 编译目标
163 target: CompilationTarget,
164 /// 错误消息
165 message: String,
166 },
167 /// 不可达错误,当程序执行到不可达的位置时使用
168 UnreachableError {
169 /// 不可达位置的源代码位置信息
170 location: Location<'static>,
171 },
172 /// 保存错误,当保存文件失败时使用
173 ///
174 /// 包含保存格式和错误消息
175 SaveError {
176 /// 保存格式
177 format: String,
178 /// 错误消息
179 message: String,
180 },
181}
182
183impl GaiaError {
184 /// 创建一个语法错误
185 ///
186 /// 当源代码解析过程中发现语法问题时使用此函数创建错误
187 ///
188 /// # 参数
189 ///
190 /// * `message` - 错误消息,描述具体的语法问题
191 /// * `location` - 错误发生的源代码位置信息
192 ///
193 /// # 返回值
194 ///
195 /// 返回一个包含语法错误信息的GaiaError实例
196 ///
197 /// # 示例
198 ///
199 /// ```
200 /// # use gaia_types::GaiaError;
201 /// # use gaia_types::reader::SourceLocation;
202 /// let location = SourceLocation::default();
203 /// let error = GaiaError::syntax_error("缺少分号", location);
204 /// ```
205 pub fn syntax_error(message: impl ToString, location: SourceLocation) -> Self {
206 GaiaErrorKind::SyntaxError { message: message.to_string(), location }.into()
207 }
208
209 /// 创建一个IO错误
210 ///
211 /// 当文件读写、网络请求等IO操作失败时使用此函数创建错误
212 ///
213 /// # 参数
214 ///
215 /// * `io_error` - 底层的IO错误
216 /// * `url` - 与IO操作相关的URL(如文件路径或网络地址)
217 ///
218 /// # 返回值
219 ///
220 /// 返回一个包含IO错误信息的GaiaError实例
221 ///
222 /// # 示例
223 ///
224 /// ```
225 /// use gaia_types::GaiaError;
226 /// use url::Url;
227 /// let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "文件不存在");
228 /// let url = Url::from_file_path("/path/to/file")
229 /// .ok()
230 /// .and_then(|x| Some(x))
231 /// .unwrap_or_else(|| Url::parse("file:///path/to/file").unwrap());
232 /// let error = GaiaError::io_error(io_err, url);
233 /// ```
234 pub fn io_error(io_error: std::io::Error, url: Url) -> Self {
235 GaiaErrorKind::IoError { io_error, url: Some(url) }.into()
236 }
237
238 /// 创建一个无效指令错误
239 ///
240 /// 当解析到未知或不支持的指令时使用此函数创建错误
241 ///
242 /// # 参数
243 ///
244 /// * `instruction` - 无效的指令字符串
245 /// * `architecture` - 指令所属的架构
246 ///
247 /// # 返回值
248 ///
249 /// 返回一个包含无效指令错误信息的GaiaError实例
250 ///
251 /// # 示例
252 ///
253 /// ```
254 /// use gaia_types::{helpers::Architecture, GaiaError};
255 /// let error = GaiaError::invalid_instruction("未知指令", Architecture::X86);
256 /// ```
257 pub fn invalid_instruction(instruction: impl ToString, architecture: Architecture) -> Self {
258 GaiaErrorKind::InvalidInstruction { instruction: instruction.to_string(), architecture }.into()
259 }
260
261 /// 创建一个不支持的架构错误
262 ///
263 /// 当尝试在不支持的架构上执行操作时使用此函数创建错误
264 ///
265 /// # 参数
266 ///
267 /// * `architecture` - 不支持的架构
268 ///
269 /// # 返回值
270 ///
271 /// 返回一个包含不支持的架构错误信息的GaiaError实例
272 ///
273 /// # 示例
274 ///
275 /// ```
276 /// use gaia_types::{helpers::Architecture, GaiaError};
277 /// let error = GaiaError::unsupported_architecture(Architecture::ARM32);
278 /// ```
279 pub fn unsupported_architecture(architecture: Architecture) -> Self {
280 GaiaErrorKind::UnsupportedArchitecture { architecture }.into()
281 }
282
283 /// 创建一个无效范围错误
284 ///
285 /// 当实际数据长度与期望长度不匹配时使用此函数创建错误
286 ///
287 /// # 参数
288 ///
289 /// * `length` - 实际长度
290 /// * `expect` - 期望长度
291 ///
292 /// # 返回值
293 ///
294 /// 返回一个包含无效范围错误信息的GaiaError实例
295 ///
296 /// # 示例
297 ///
298 /// ```
299 /// use gaia_types::GaiaError;
300 /// let error = GaiaError::invalid_range(1024, 2048);
301 /// ```
302 pub fn invalid_range(length: usize, expect: usize) -> Self {
303 GaiaErrorKind::InvalidRange { length, expect }.into()
304 }
305
306 /// 创建一个无效数据错误。
307 ///
308 /// # 参数
309 ///
310 /// * `data` - 无效数据的描述。
311 ///
312 /// # 返回值
313 ///
314 /// 返回一个包含无效数据错误信息的GaiaError实例。
315 pub fn invalid_data(data: impl ToString) -> Self {
316 Self {
317 level: Level::ERROR,
318 kind: Box::new(GaiaErrorKind::CustomError { message: format!("无效数据: {}", data.to_string()) }),
319 }
320 }
321
322 /// 创建一个无效魔术头错误。
323 ///
324 /// # 参数
325 ///
326 /// * `head` - 实际的魔术头。
327 /// * `expect` - 期望的魔术头。
328 ///
329 /// # 返回值
330 ///
331 /// 返回一个包含无效魔术头错误信息的GaiaError实例。
332 pub fn invalid_magic_head(head: Vec<u8>, expect: Vec<u8>) -> Self {
333 Self {
334 level: Level::ERROR,
335 kind: Box::new(GaiaErrorKind::CustomError {
336 message: format!("无效数据头: {:?}, 期望: {:?}", head, expect)
337 }),
338 }
339 }
340
341 /// 返回错误的种类。
342 pub fn kind(&self) -> &GaiaErrorKind {
343 &self.kind
344 }
345
346 /// 返回错误的级别。
347 pub fn level(&self) -> &Level {
348 &self.level
349 }
350
351 /// 创建一个功能未实现错误
352 ///
353 /// 当调用尚未实现的功能时使用此函数创建错误
354 ///
355 /// # 参数
356 ///
357 /// * `feature` - 未实现功能的描述
358 ///
359 /// # 返回值
360 ///
361 /// 返回一个包含功能未实现错误信息的GaiaError实例
362 ///
363 /// # 示例
364 ///
365 /// ```
366 /// # use gaia_types::GaiaError;
367 /// let error = GaiaError::not_implemented("PE context creation");
368 /// ```
369 pub fn not_implemented(feature: impl ToString) -> Self {
370 GaiaErrorKind::NotImplemented { feature: feature.to_string() }.into()
371 }
372
373 /// 创建适配器错误
374 ///
375 /// # 参数
376 /// * `adapter_name` - 适配器名称
377 /// * `message` - 错误消息
378 /// * `source` - 可选的源错误
379 ///
380 /// # 示例
381 /// ```
382 /// # use gaia_types::GaiaError;
383 /// let error = GaiaError::adapter_error("PeExportAdapter", "导出失败", None);
384 /// ```
385 pub fn adapter_error(adapter_name: impl ToString, message: impl ToString, source: Option<Box<GaiaError>>) -> Self {
386 GaiaErrorKind::AdapterError { adapter_name: adapter_name.to_string(), message: message.to_string(), source }.into()
387 }
388
389 /// 创建平台不支持错误
390 ///
391 /// # 参数
392 /// * `platform` - 平台名称
393 /// * `operation` - 不支持的操作描述
394 ///
395 /// # 示例
396 /// ```
397 /// # use gaia_types::GaiaError;
398 /// let error = GaiaError::platform_unsupported("WASI", "内联汇编");
399 /// ```
400 pub fn platform_unsupported(platform: impl ToString, operation: impl ToString) -> Self {
401 GaiaErrorKind::PlatformUnsupported { platform: platform.to_string(), operation: operation.to_string() }.into()
402 }
403
404 /// 创建配置错误
405 ///
406 /// # 参数
407 /// * `config_path` - 可选的配置文件路径
408 /// * `message` - 错误消息
409 ///
410 /// # 示例
411 /// ```
412 /// # use gaia_types::GaiaError;
413 /// let error = GaiaError::config_error(Some("config.toml"), "配置文件格式错误");
414 /// ```
415 pub fn config_error(config_path: Option<impl ToString>, message: impl ToString) -> Self {
416 GaiaErrorKind::ConfigError { config_path: config_path.map(|p| p.to_string()), message: message.to_string() }.into()
417 }
418
419 /// 创建不支持的编译目标错误
420 ///
421 /// # 参数
422 /// * `target` - 不支持的编译目标
423 ///
424 /// # 示例
425 /// ```
426 /// # use gaia_types::{
427 /// # helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
428 /// # GaiaError,
429 /// # };
430 /// let target = CompilationTarget {
431 /// build: Architecture::X86_64,
432 /// host: AbiCompatible::ELF,
433 /// target: ApiCompatible::Gnu,
434 /// };
435 /// let error = GaiaError::unsupported_target(target);
436 /// ```
437 pub fn unsupported_target(target: CompilationTarget) -> Self {
438 GaiaErrorKind::UnsupportedTarget { target }.into()
439 }
440
441 /// 创建编译失败错误
442 ///
443 /// # 参数
444 /// * `target` - 编译目标
445 /// * `message` - 错误消息
446 ///
447 /// # 示例
448 /// ```
449 /// # use gaia_types::{
450 /// # helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
451 /// # GaiaError,
452 /// # };
453 /// let target = CompilationTarget {
454 /// build: Architecture::X86_64,
455 /// host: AbiCompatible::ELF,
456 /// target: ApiCompatible::Gnu,
457 /// };
458 /// let error = GaiaError::compilation_failed(target, "无法生成字节码");
459 /// ```
460 pub fn compilation_failed(target: CompilationTarget, message: impl ToString) -> Self {
461 GaiaErrorKind::CompilationFailed { target, message: message.to_string() }.into()
462 }
463
464 /// 创建一个保存错误。
465 ///
466 /// # 参数
467 ///
468 /// * `format` - 保存格式。
469 /// * `message` - 错误消息。
470 ///
471 /// # 返回值
472 ///
473 /// 返回一个包含保存错误信息的GaiaError实例。
474 pub fn save_error(format: impl ToString, message: impl ToString) -> Self {
475 GaiaErrorKind::SaveError { format: format.to_string(), message: message.to_string() }.into()
476 }
477 /// 创建一个不支持的功能错误。
478 ///
479 /// # 参数
480 ///
481 /// * `p0` - 不支持的功能描述。
482 /// * `p1` - 错误发生的源代码位置信息。
483 ///
484 /// # 返回值
485 ///
486 /// 返回一个包含不支持的功能错误信息的GaiaError实例。
487 pub fn unsupported_feature(feature: impl ToString, location: SourceLocation) -> Self {
488 GaiaErrorKind::UnsupportedFeature { feature: feature.to_string(), location }.into()
489 }
490 /// 创建一个自定义错误。
491 ///
492 /// # 参数
493 ///
494 /// * `message` - 错误消息。
495 ///
496 /// # 返回值
497 ///
498 /// 返回一个包含自定义错误信息的GaiaError实例。
499 pub fn custom_error(message: impl ToString) -> GaiaError {
500 GaiaErrorKind::CustomError { message: message.to_string() }.into()
501 }
502 /// 创建一个不可达错误。
503 ///
504 /// 当程序执行到理论上不可达的代码路径时调用此函数。它会自动捕获调用位置。
505 ///
506 /// # 返回值
507 ///
508 /// 返回一个包含不可达错误信息的 `GaiaError` 实例。
509 ///
510 /// # 示例
511 ///
512 /// ```
513 /// # use gaia_types::GaiaError;
514 /// fn example_unreachable() -> Result<(), GaiaError> {
515 /// let value = 1;
516 /// match value {
517 /// 1 => Ok(()),
518 /// _ => Err(GaiaError::unreachable()), // 此处理论上不可达
519 /// }
520 /// }
521 /// let _ = example_unreachable();
522 /// ```
523 #[track_caller]
524 pub fn unreachable() -> Self {
525 let location = Location::caller();
526 GaiaErrorKind::UnreachableError { location: *location }.into()
527 }
528}