# 与 thiserror 的关系
`orion-error` 和 `thiserror` 不是互斥关系,但它们的定位不同。
## 1. 定位差异
### `thiserror`
更偏向:
- 定义标准 Rust error 类型
- 服务于 `std::error::Error` 生态
- 为 `Display`、`source`、`from` 等标准错误能力提供 derive 支持
### `orion-error`
更偏向:
- 定义运行时结构化错误载体
- 管理上下文、source frame、快照、协议投影
- 为领域 reason 提供稳定身份
## 2. 当前推荐路径
新代码里的领域 reason,默认不需要 `thiserror`。
推荐直接使用 `OrionError`:
```rust
use derive_more::From;
use orion_error::{prelude::*, reason::UvsReason};
#[derive(Debug, Clone, PartialEq, From, OrionError)]
enum AppReason {
#[orion_error(identity = "biz.invalid_request")]
InvalidRequest,
#[orion_error(transparent)]
Uvs(UvsReason),
}
```
这样就能同时获得:
- `Display`
- `DomainReason`
- 稳定身份
- 分类
- 兼容数值码
## 3. 能力对比
| 定义标准错误类型 | 强 | 不是主要目标 |
| 领域 reason derive | 需要额外补稳定身份 | `OrionError` 是推荐入口 |
| 运行时结构化上下文 | 无 | 有 |
| source frame 追踪 | 无 | 有 |
| stable code / category | 无 | 有 |
| snapshot / report / projection | 无 | 有 |
## 4. 什么时候仍然适合 `thiserror`
下面这些场景仍然适合保留 `thiserror`:
- 你对外公开的就是标准 `std::error::Error` 类型
- 外部库 API 要求你传递标准 error 类型
- 你需要 `#[from]`、`#[source]` 这类标准错误生态能力
这种情况下,`thiserror` 类型可以作为 source 进入 `StructError<R>`。
## 5. 如何和 `orion-error` 配合
最常见的配合方式是:
- 边界外还是标准 error
- 进入你的业务边界后,再转成 `StructError<R>`
例如:
```rust
use orion_error::{IntoAs, UvsReason};
let err = std::fs::read_to_string("config.toml")
.into_as(UvsReason::system_error(), "read config failed")
.unwrap_err();
```
注意:当前 `into_as(...)` 不是 blanket `E: std::error::Error` 实现。
如果你的第三方错误类型不在内建支持列表里,需要显式 `raw_source(...)` opt-in。
## 6. `into_as(...)`、`wrap_as(...)`、`err_conv()`
当前推荐分工:
- `into_as(...)`
- 普通错误第一次进入结构化体系
- `wrap_as(...)`
- 上游已经是 `StructError<_>`,当前层要建立新语义边界
- `err_conv()`
- 上游已经是 `StructError<_>`,当前层只做 reason 收敛
如果上游已经是 `StructError<_>`,不要再回退到:
- `.into_as(...)`
- `owe(...)`
## 7. source 建议
如果你已经在 `StructError` 世界里,推荐优先使用当前 source API:
- `with_std_source(...)`
- `with_struct_source(...)`
- `builder.source_std(...)`
- `builder.source_struct(...)`
`with_source(...)` / `builder.source(...)` 仍可用,但属于自动分流兼容入口;新代码优先显式 API。
## 8. 实践建议
- 领域 reason 默认 derive `OrionError`
- 标准错误类型继续用 `thiserror` 时,把它们视为边界外或边界前对象
- 稳定协议依赖 stable code,不依赖自然语言文案
- 结构化错误跨层传播时优先使用 `StructError<R>` 体系