Files
Unlucky-Launcher/crates/core/src/game/error.rs
T
AskaEth bc41dfcf7d
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Unlucky Launcher v0.0.1-alpha
Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent),
MCP server 接入外部 Agent 工具,GUI 开发中。
2026-10-31 21:54:10 +08:00

125 lines
4.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! `core::game` 的错误类型。
//!
//! 采用手写 `Display`/`Error` 而不用 `thiserror`:core 的依赖面越窄越好(D3 模块纪律),
//! 且这里的变体数量固定、不需要派生宏的收益。
use std::fmt;
use std::path::PathBuf;
/// `core::game` 的失败集合。
#[derive(Debug)]
pub enum GameError {
/// JSON 解析/序列化失败(版本清单、版本 JSON、profiles)。
Json {
/// 出错的文档种类,用于给用户看上下文(如 `version_manifest_v2`)。
context: String,
/// 底层 serde_json 错误。
source: serde_json::Error,
},
/// 清单或版本 JSON 缺少必需的 `id`。
MissingVersionId,
/// `inheritsFrom` 指向的父版本在本仓库中不存在。
MissingParent {
/// 缺失的父版本 id。
parent: String,
/// 发起继承的子版本 id。
required_by: String,
},
/// `inheritsFrom` 成环。
CircularInheritance {
/// 从根到环的 id 链(首尾为同一个 id)。
chain: Vec<String>,
},
/// Maven 坐标(`group:artifact:version[:classifier][@ext]`)不合法。
InvalidCoordinate {
/// 原始字符串。
raw: String,
/// 不合法的原因。
reason: &'static str,
},
/// 资源对象哈希不合法(长度不足以做两级分片)。
InvalidAssetHash {
/// 原始哈希。
hash: String,
},
/// 文件系统错误。
Io {
/// 出错的路径。
path: PathBuf,
/// 底层 IO 错误。
source: std::io::Error,
},
/// 已有草稿持有写权,同一仓库同时只允许一个写会话。
DraftBusy,
/// 实例隔离档位是 `custom`,但没有可用的自定义目录(不猜默认值)。
CustomIsolationWithoutDir {
/// 实例 id(可能为空:调用方没给实例上下文)。
instance: String,
},
}
impl fmt::Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Json { context, source } => write!(f, "解析 {context} 失败: {source}"),
Self::MissingVersionId => write!(f, "版本 JSON 缺少 id"),
Self::MissingParent {
parent,
required_by,
} => write!(
f,
"版本 {required_by} 继承的父版本 {parent} 不存在(缺失前置版本)"
),
Self::CircularInheritance { chain } => {
write!(f, "版本继承成环: {}", chain.join(" -> "))
}
Self::InvalidCoordinate { raw, reason } => {
write!(f, "Maven 坐标不合法({reason}): {raw}")
}
Self::InvalidAssetHash { hash } => {
write!(f, "资源哈希不合法(短于两个字符): {hash}")
}
Self::Io { path, source } => write!(f, "IO 失败 {}: {source}", path.display()),
Self::DraftBusy => write!(f, "已有草稿持有写权(单写者约束)"),
Self::CustomIsolationWithoutDir { instance } => {
if instance.is_empty() {
write!(f, "隔离档位为 custom,但没有指定自定义运行目录")
} else {
write!(
f,
"实例 {instance} 的隔离档位为 custom,但没有指定自定义运行目录"
)
}
}
}
}
}
impl std::error::Error for GameError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Json { source, .. } => Some(source),
Self::Io { source, .. } => Some(source),
_ => None,
}
}
}
impl GameError {
/// 包装 serde_json 错误并带上文档上下文。
pub fn json(context: impl Into<String>, source: serde_json::Error) -> Self {
Self::Json {
context: context.into(),
source,
}
}
/// 包装 IO 错误并带上路径。
pub fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
Self::Io {
path: path.into(),
source,
}
}
}