Skip to main content

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}