refactor(core): M126 r1 返工:词表改由宏单表生成,安装侧解析收口
复审 r1 的三条: P1(CI 会红):`const MARKERS: [(LoaderKind, &'static str); 6]` 触发 clippy::redundant_static_lifetimes(`error: constants have by default a 'static lifetime`)。返工直接**删掉 MARKERS**:标记串就取 `LoaderKind::as_str()`,候选顺序取 `LoaderKind::ALL`,认不认标记看 `has_marker()`——解析表既没有独立字面量,也没有独立清单。 P2-1:「漏加 ALL 不会被任何东西拦住」是真话,之前的 doc 覆盖声明是假的。返工用 `loader_kind_vocab!` 宏从**一张表**一次生成枚举 / `ALL` / `as_str` / `has_marker`: 「加了一支却忘了进清单」在物理上不可能(没有第二份清单可写)。尺寸锚随之删除(`[Self; N]` 的宽度本来就由表决定),`parse` 留在宏外的独立 impl 里。 P2-2:「全仓唯一一份 id 字面量」原先不成立——安装侧 `LoaderKind::parse` 还手写了一份反向 匹配表,并带一个只进不出的 `neo-forge` 别名。返工让 install 侧 `parse` **委派** `core::game::LoaderKind::parse`,只额外收 `neo-forge`(Modrinth 拼法)这一个输入别名, 并新增 `addon::loader::tests::vocabulary` 覆盖「委派没接错 + 别名只进不出 + 装不了的几家 返回 None」。 测试:core 的 `markers_cover_every_kind_that_has_one` 换成 `every_stable_id_parses_back_to_its_kind`(往返 + 顺序优先级),仍是「改名不可见、只有契约 测试能抓」的分工,doc 里写明。 门禁:fmt OK;clippy -p unlucky-core -p unlucky-presenter -p unlucky-cli --all-targets -- -D warnings 干净;三 crate 测试 core lib 401 / presenter 220 / cli 41 全 ok。 文件行数:loader.rs 397(≤400)。
This commit is contained in:
1 parent
be37c17962
commit
a322cfcbfe
4 files changed
+219
-138
No files matched your search
@@ -62,15 +62,33 @@ pub enum LoaderKind {
|
||||
}
|
||||
|
||||
impl LoaderKind {
|
||||
/// 解析命令行里的加载器名(大小写不敏感;`neo-forge` 是 Modrinth 的另一种拼法)。
|
||||
/// 解析命令行 / 整合包清单里的加载器名(大小写不敏感)。
|
||||
///
|
||||
/// 七个 id 的匹配**委派**给 [`crate::game::LoaderKind::parse`](词表唯一真相源,M126),
|
||||
/// 本方法只多收一个**输入别名** `neo-forge`:那是 Modrinth 的拼法(mrpack
|
||||
/// `dependencies` 的键、CF 包里也有这种写法),**只进不出**——[`Self::as_str`] 绝不产出
|
||||
/// 它。识别得出但本启动器装不了的几家(原版 / OptiFine / LiteLoader)返回 `None`。
|
||||
#[must_use]
|
||||
pub fn parse(raw: &str) -> Option<Self> {
|
||||
match raw.trim().to_ascii_lowercase().as_str() {
|
||||
"fabric" => Some(Self::Fabric),
|
||||
"quilt" => Some(Self::Quilt),
|
||||
"neoforge" | "neo-forge" => Some(Self::NeoForge),
|
||||
"forge" => Some(Self::Forge),
|
||||
_ => None,
|
||||
let wanted = raw.trim();
|
||||
if wanted.eq_ignore_ascii_case("neo-forge") {
|
||||
return Some(Self::NeoForge);
|
||||
}
|
||||
Self::from_core(crate::game::LoaderKind::parse(wanted)?)
|
||||
}
|
||||
|
||||
/// core 的宽种类 → 本模块的四家(`None` = 识别得出但本启动器装不了)。
|
||||
///
|
||||
/// 穷尽 match:core 加一支就编不过,逼作者决定「它能不能装」。
|
||||
const fn from_core(kind: crate::game::LoaderKind) -> Option<Self> {
|
||||
match kind {
|
||||
crate::game::LoaderKind::Fabric => Some(Self::Fabric),
|
||||
crate::game::LoaderKind::Quilt => Some(Self::Quilt),
|
||||
crate::game::LoaderKind::NeoForge => Some(Self::NeoForge),
|
||||
crate::game::LoaderKind::Forge => Some(Self::Forge),
|
||||
crate::game::LoaderKind::Vanilla
|
||||
| crate::game::LoaderKind::OptiFine
|
||||
| crate::game::LoaderKind::LiteLoader => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ mod fabric;
|
||||
mod forge;
|
||||
mod maven;
|
||||
mod plan;
|
||||
mod vocabulary;
|
||||
|
||||
/// 裁剪过的 Fabric `/profile/json`(1.20.1 + fabric-loader 0.15.11)。
|
||||
pub(crate) const FABRIC_PROFILE: &str = r#"{
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//! 安装侧词表与 `crate::game` 词表的对接:委派有没有接错、别名有没有漏进产出。
|
||||
//!
|
||||
//! 词表本体(七个对外 id)在 `crate::game::loader`,这里只验**安装侧这一半**:
|
||||
//! [`LoaderKind::as_str`] 委派给 core,[`LoaderKind::parse`] 委派 core 的解析并只多收一个
|
||||
//! Modrinth 输入别名。为什么放在安装侧的测试目录:这一半的存在理由是「装出来的版本 id 得
|
||||
//! 能被认回来」,那正好是生成端与解析端的接缝。
|
||||
|
||||
use crate::addon::loader::LoaderKind;
|
||||
use crate::game::{InstanceLoader, LoaderKind as Wide};
|
||||
|
||||
/// `as_str` 是 core 词表的委派:四家装得上的一一对应,且绝不产出别名。
|
||||
///
|
||||
/// 抓得住:委派接错支(`Fabric` 映到 `Quilt`);有人把 `as_str` 改回手写字面量并写错;
|
||||
/// 有人让 `as_str` 产出 `neo-forge`(别名只进不出);生成端 `<mc>-<kind>-<loader>` 与解析端
|
||||
/// 脱节(装出来的 id 认不回同一家)。
|
||||
/// 抓不住:core 词表的字面值(那是 `game::loader` 的往返测试与 presenter 契约测试的职责)。
|
||||
#[test]
|
||||
fn install_side_ids_are_delegated_to_the_core_vocabulary() {
|
||||
let cases = [
|
||||
(LoaderKind::Fabric, Wide::Fabric),
|
||||
(LoaderKind::Quilt, Wide::Quilt),
|
||||
(LoaderKind::NeoForge, Wide::NeoForge),
|
||||
(LoaderKind::Forge, Wide::Forge),
|
||||
];
|
||||
for (install, wide) in cases {
|
||||
assert_eq!(
|
||||
install.as_str(),
|
||||
wide.as_str(),
|
||||
"{install:?} 的 id 没走 core 词表"
|
||||
);
|
||||
assert_ne!(install.as_str(), "neo-forge", "别名只进不出");
|
||||
assert_eq!(LoaderKind::parse(install.as_str()), Some(install), "反查");
|
||||
|
||||
let id = install.version_id("1.20.4", "0.16.5");
|
||||
let parsed = InstanceLoader::parse(&id);
|
||||
assert_eq!(parsed.kind.as_str(), install.as_str(), "`{id}` 认错了家");
|
||||
assert_eq!(parsed.version, "0.16.5", "`{id}` 的版本段");
|
||||
}
|
||||
}
|
||||
|
||||
/// 别名策略:`neo-forge` 只作为**输入**被接受(Modrinth 的拼法),产出永远是 `neoforge`。
|
||||
///
|
||||
/// 抓得住:别名被搬进词表(`as_str` 开始产出 `neo-forge`);别名只认小写;安装侧顺手接受了
|
||||
/// 本启动器装不了的几家(原版 / OptiFine / LiteLoader)。
|
||||
/// 抓不住:`neo-forge` 之外 Modrinth 以后可能再发明的拼法——没有样本可写。
|
||||
#[test]
|
||||
fn modrinth_alias_is_input_only() {
|
||||
for raw in ["neo-forge", "NEO-FORGE", " neo-forge "] {
|
||||
assert_eq!(
|
||||
LoaderKind::parse(raw),
|
||||
Some(LoaderKind::NeoForge),
|
||||
"`{raw}`"
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
LoaderKind::NeoForge.as_str(),
|
||||
"neoforge",
|
||||
"产出不许带连字符"
|
||||
);
|
||||
for raw in ["vanilla", "optifine", "liteloader", "", "rift"] {
|
||||
assert_eq!(LoaderKind::parse(raw), None, "`{raw}` 不该被安装侧接受");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user