Fast QR code generator library written in MoonBit
基于 MoonBit 的高性能二维码(QR Code)生成库。 纯 MoonBit 实现、无外部依赖,逐位对齐 Rust 参考库 fast_qr v0.14.0。
| 语言 | MoonBit(仅 wasm-gc;边界见「能力与局限」) |
| 标准 | ISO/IEC 18004 二维码(版本 1–40,ECL L/M/Q/H,8 掩码评分择优) |
| 许可 | Apache-2.0 |
| 参考 | Rust fast_qr v0.14.0 逐位移植对齐 |
| 能力 | 说明 |
|---|---|
| 编码内容 | 字节(ASCII) 输入;自动选择 Numeric / Alphanumeric / Byte,也可强制指定模式 |
| 版本/纠错 | 自动最小适配或强制指定版本 V01–V40;ECL 缺省 Quartile(Q),可显式 L/M/Q/H |
| 掩码 | 自动 8 轮评分择优,或指定固定掩码(走快速路径) |
| 输出 | 终端 Unicode 字符画、SVG 字符串 |
# 需本模块已发布至 mooncakes;发布前的过渡期为 clone 本仓库按「从源码构建」体验
moon add TryAndRun-TvT/fast_qr_moonbit发布状态:尚未发布(0.1.0 待发布)。发布流程、元数据/命名核验、归档面治理 与发布前门禁清单见 mooncakes-发布方案.md; 发布动作已脚本化:bash scripts/publish.sh(默认干跑,--publish 真发), 模块名迁移记录见 模块名迁移与发布链路核验.md。
import {
"TryAndRun-TvT/fast_qr_moonbit/lib",
}/// 由字符串输入构建 QRCode(缺省全部自动:mode 自动、ECL=Q、version 最小、mask 择优)。
fn gen() -> @lib.QRCode {
match @lib.QRBuilder::from_string("https://example.com/").build() {
Ok(q) => q
Err(_) => abort("content too large")
}
}
fn main {
let qr = gen()
// 输出终端 Unicode 半块字符画(含边距)
println(qr.to_str())
// 输出 SVG 字符串(默认黑色方块 + 白色背景、margin=4),链式定制颜色与模块形状
let svg = @lib.SvgBuilder::default()
.module_color("#0000ff")
.background_color("#ffffff")
.shape(@lib.Shape::RoundedSquare)
.to_str(qr)
println(svg[:200].to_owned() + "...")
}| 类型 | 位置/说明 |
|---|---|
| ECL / Version / Mode / Mask | 纠错级别(L/M/Q/H)、版本(V01–V40)、编码模式、掩码枚举 |
| QRCode | 生成结果容器(矩阵 + size/version/ecl/mask/mode 元数据 + to_str/print) |
| QRCode::build / build_fixed | 过程式编排入口(input/mode/ecl/version/mask → Result[QRCode];build 的 Some(mask) 分支委托 build_fixed) |
| QRCode::empty | 空矩阵构造(宿主自建/改写矩阵的唯一入口,见下「矩阵读写」) |
| QRCode::get / set / meta / data(+ size/version/ecl/mask/mode) | 逐格读写与元数据访问器(set 不可变式,返回新 QRCode) |
| QRCode::select_capacity | 容量/版本三元组解析(显式模式参与判定,供自定义编排复用) |
| QRBuilder | 链式构造器:from_string/new + mode/ecl/version/mask + build |
| Module / ModuleType | 单像素模块(明暗 + 8 种功能归属);Module::new(value, type) 为通用构造 |
| SvgBuilder / Shape | SVG 字符串输出;6 种模块形状(square/circle/rounded_square/vertical/horizontal/diamond);链式 margin/module_color/background_color/shape |
| Shape::from_name | 由名字(大小写不敏感)取形状枚举,未知名回退 |
| ECL::to_char | 纠错级别 → 显示字符(L/M/Q/H) |
| QRCodeError | 构造错误(EncodedData 数据过大、SpecifiedVersion 版本过小) |
// ① 已有编码结果:读/改单格(set 为不可变式,返回新 QRCode,不改源)
let (v, ecl, mask, mode) = qr.meta() // 元数据快照
let dark = qr.get(0, 0).value() // 逐格读
let qr2 = qr.set(0, 0, @lib.Module::new(true, @lib.ModuleType::Data)) // 逐格写
// ② 从零自建:空矩阵(全亮)作起点,逐格写入后输出
let canvas = @lib.QRCode::empty(@lib.Version::V05) // 边长 = 版本*4+17
let drawn = canvas.set(10, 10, @lib.Module::new(true, @lib.ModuleType::Data))
println(drawn.to_str())命名/形状等辅助入口:Shape::from_name("circle")(按名取形状)、 ECL::to_char(ECL::Q)(级别显示字符)、SvgBuilder::default().module_color(...)(链式配色)。
curl -fsSL https://cli.moonbitlang.cn/install/unix.sh | bash
export PATH="$HOME/.moon/bin:$PATH"moon build lib # 编译库包
moon build cmd/main # 编译 CLI
moon run cmd/main # 运行 CLI 演示(终端字符画 + SVG)
moon test # 运行单元/快照测试export PATH="$HOME/.moon/bin:$PATH"
moon fmt && moon info && moon check --deny-warn && moon test
moon build lib --target wasm-gc --release
moon build cmd/main --target wasm-gc --release
moon test --target wasm-gc# 唯一后端 wasm-gc(体积最小、性能最优,宿主只需提供 spectest.print_char)
moon build cmd/main --release
moon run cmd/main| 产物 | 后端 | raw | -Oz(可加载档) |
|---|---|---|---|
| cmd/qr-min(纯库调用 = 库实际体积) | wasm-gc | 41427 B(40.5 KiB) | 31365 B(30.6 KiB) |
| cmd/bench(基准外壳:argv/迭代/--dump) | wasm-gc | 48038 B(46.9 KiB) | 36174 B(35.3 KiB) |
| cmd/main(CLI:字符画 + SVG) | wasm-gc | 44424 B(43.4 KiB) | 33593 B |
引用规范:cmd/bench / cmd/main 是「命令形态」产物,外壳不随库分发, 不能代表库被宿主嵌入时的实际体积——引用库体积请用 cmd/qr-min 口径并注明后端与优化档。 体积金字塔(wasm-gc,-Oz):运行时地板(一行 println)263 B → QR 核心净增 +31102 B(cmd/qr-min)→ 输出层(终端画 + SVG)+2228 B(cmd/main)→ 基准外壳 +4809 B(cmd/bench)。
# -Oz 体积最优档(默认后端 wasm-gc):
# --all-features 会开 custom-descriptors(RTT),其 exact heap type 在 Node/moonrun 上编译不过;
# --disable-custom-descriptors 才产出「可被真实宿主加载」的最优档。
moon-wasm-opt _build/wasm-gc/release/build/cmd/main/main.wasm \
--all-features --disable-custom-descriptors -Oz -o main.min.wasm # 33593 B| 口径(B) | MoonBit wasm-gc | fast_qr 裸探针 | ours / fast |
|---|---|---|---|
| raw | 41427 | 59440 | 0.70× |
| -Oz(可加载档) | 31365 | 45687 | 0.69× |
| 核心净增(扣 hello 地板 263 / 20052 B) | +31102 | +25635 | 1.21× |
引用的性能数字仅作选型与迭代基线,不代表对 fast_qr 的追赶承诺;逐条口径见 S9 系列文档。
| 对比 | 结果 | 出处 |
|---|---|---|
| ① vs Rust fast_qr-wasm32(默认后端 wasm-gc) | 单次 build 慢 ≈1.3–2.5×,逐位对齐 sha256 零差异;差距集中在 8 轮掩码择优主循环 | 明细见下表 · S9p · S9j |
| ② vs moonbit 生态 moonqr(同宿主、完整实现可比子集) | 本仓库全程快 2.5–4.1×(V03H 0.318 vs 0.805、V40H 9.46 vs 38.29 ms/单次,历史口径) | S9d |
| ③ 产物体积 vs fast_qr | wasm-gc 各口径均更小(对称锚点 0.69×) | 对照表见 编译为 Wasm · S9i |
① 的数据随本轮 P0/P2/P2b 优化已刷新(2026-09-12 重测);② 为优化前(2026-09-06)历史口径, 未随本轮重测,量级参考即可。
| 点 | 模块数 | 本仓库 MoonBit(wasm-gc) | fast_qr-wasm32 | fast / ours | 每模块成本 ours / fast |
|---|---|---|---|---|---|
| V03H | 841 | 0.213 ms | 0.087 ms | 0.407×(慢 ≈2.5×) | 0.253 / 0.103 µs |
| V10H | 3249 | 0.643 ms | 0.399 ms | 0.620×(慢 ≈1.6×) | 0.198 / 0.123 µs |
| V40H | 31329 | 4.659 ms | 3.523 ms | 0.756×(慢 ≈1.3×) | 0.149 / 0.112 µs |
旧命令形态口径(cmd/bench,保留作对照):A 每次新建 Instance (与 fast_qr「一次调用」同形,会系统性夸大差距)fast/ours = 0.263 / 0.528 / 0.728×; B 单实例摊薄 = 0.340 / 0.574 / 0.737×。三者对照见 S9p §4.1。 护栏全绿:宿主面 checksum 与 cmd/bench <点> 1 逐点相同(41/81/230,证明两个口径 是同一计算)· 同实例重复调用结果恒定 · 逐位对齐 sha256 三点相同 · Node shim vs moonrun 跨宿主一致。 统计口径(S9q):上表上行为「R=5 中位数」口径(R=3 回退取最小并与离散成对报出)。 同一产物重复测量(15 轮 × 5 次)的比值 CV:V03H 5.98% ≫ V10H 3.54% > V40H 0.35%—— 单次 build 越便宜,相对统计误差越大(固定项占比);V03H 单轮最坏可偏离真值 +17.3%。 噪声非白噪声(lag-1 自相关 r1 = 0.28~0.68,存在热/频漂移),故同一进程内加轮次收益有限; 更大偏差来自宿主调度态(6 线程满载竞争使三点一致慢 1.43–1.50×)与 Node 大版本(v22→v24 两侧共模 1.12–1.23×)。 纪律:只用「同 run 内成对比值」,不跨 run 加减绝对毫秒;主数取中位数而非算术平均(分布右偏)。 绝对毫秒数绑定测量环境(本表 Node v24.21.0 + 2026-09-14 宿主):跨环境只比「同 run 成对比值」, 方向性结论全环境成立,归因见 S9h。 生态另两个 QR 包(qrc/moonbitqrcode)缺完整择优/Format 等,不可同口径对齐,仅参考口径见 S9d。
| 层 | 覆盖 |
|---|---|
| 黑盒 | 公共枚举与 select_capacity 四态 + 模式/版本语义回归(4 条,v5)、QRBuilder 链式等价、择优 mask 号回归(T2-d)、SVG 全串、终端画、21 个端到端全矩阵 hex 快照、11 条固化解码向量(T3-c) |
| 白盒 | 位流、常量表交叉不变量 + 全表值级校验(T1-f)、生成多项式独立推导(T1-a)、三模式编码、GF(256) 交织 + 黄金余数/交织向量(T1-c/T1-d)+ 交叉独立证据(T1-e)、逐行/逐列打分明细(T2-a/T2-b)+ 结算边界(T2-b2/b3)、8 种掩码、放置逐格坐标(T2-c)、Format 双副本布局(T2-e)、独立数字真值(T0-c)、属性测试四则(T4-a)、枚举全量回环(T5-b) |
| 黄金值来源 | 参考 fast_qr commit 53e8c99 侧由脚本产出(禁止手抄):snapshot_gen_s6.rs(全矩阵)、snapshot_gen_tables.py(常量表全表指纹)、snapshot_gen_rs_vectors.rs(division/structure)、snapshot_gen_score.rs(打分明细)、snapshot_gen_placement.rs(放置坐标)、snapshot_gen_default.py(Python qrcode 独立真值);一键校验 bash scripts/gen-goldens.sh --verify(四项零差异) |
面向读者的口径与结论汇总在本文;实现细节、逐条口径、历史记录在下列文档 (随附代码实测与复跑方式)。文件名前缀 S1–S9n 为按实现顺序编号的阶段文档。
| 文档 | 说明 |
|---|---|
| moonbit-项目目录设置-最佳实践.md | 目录/包/测试设置的官方依据 + 实证验证 + 落地清单 |
| moonbit-工具链与构建-setup-分析.md | 工具链安装、构建系统与 CI 集成;附录含仓库初始化与云原生构建配置记录 |
| mooncakes-发布方案.md | 发布入口:mooncakes.io 发布流程核验、元数据/命名/归档面评估、.moonignore 治理、版本策略与发布前门禁清单 |
| mooncakes-发布阻塞项3-4-落地方案.md | 发布落地:阻塞项 #3(归档面收敛 .moonignore,155→32 项)与 #4(发布前门禁 publish-check.sh)的深挖、实测与负向验证 |
| 模块名迁移与发布链路核验.md | 迁移记录:mooncakes 账户定为 TryAndRun-TvT 后的全仓改名清单、Cannot find import ... 报错根因、moon publish --dry-run 退出码实测与 push 流水线移除后的本地门禁执行方式 |
| 性能测试脚本-公开评审说明.md | 性能/体积测试脚本位置、参数口径与可复现路径(公开评审/审计入口) |
| S9i-纯库调用体积探针与库实际体积.md | 库实际体积口径(cmd/qr-min 纯库调用探针;体积金字塔 + 引用规范) |
| S9j-层②统一Node对比-wasm-gc与fast_qr.md | 层② MoonBit 侧收敛为 wasm-gc;Node 进程内 shim 直测(性能主口径) |
| S9k-性能瓶颈与理论上限评估.md | 进程级差分把 auto build 拆为 5 段:瓶颈定位与理论上限(roadmap 依据) |
| S9n-优化方案复评与wasm-gc收敛审计.md | 收敛审计 + 单一优化优先级清单 + P0/P2/P2b 与 ReadOnlyArray 落地记录 |
| README示例二维码-SVG资源与生成.md | README 头部示例码为何用 SVG + 资产规格 + 生成脚本 + 一致性核验 |
| README优化-冗余清理与最佳实践.md | README 精简的冗余清单、官方 README 约定对照与取舍(含示例实测) |
| S9o-性能与体积数据重测-与README冗余清理.md | 本轮重测记录:性能/体积数据刷新方法与归因 + README 去冗余清单 |
| S9p-宿主调用面性能口径-JS向wasm传参.md | 宿主调用面主口径:JS 反复带参调 wasm(cmd/host-probe + bench-host.sh);wasm-gc 传字符串的技术路径与踩坑(性能主口径) |
| S9q-性能口径统计差异与取平均评估.md | 统计口径:为什么 R 轮取最小≠真值;轮次级重抽样的 CV / 单跑失稳率 / 漂移判定;调度态与 Node 版本的量级对照;主数取中位数 + 必须报离散 |
| moonbit-实现布局与文件职责.md | 布局规则、lib/ + lib/internal/ 文件级职责、无环依赖、测试规划(维护者入口) |
| S10-测试用例设计与完善roadmap.md | 测试 roadmap v6:参考 fast_qr 测试体系盘点(含证据等级)+ 覆盖差距矩阵(G1–G15)+ 分阶段 T0–T7 路线 + 七条铁律;附录 D/E/F/G/H 为实跑结论(第三方解码回读、变异检测 21/21、v3/v4/v5 落地 + v6 订正记录)(测试维护入口) |
| S10c-select_capacity模式语义缺陷-定位与修复.md | v5 真 bug 修复记录:T3-d 探针首跑暴露的「显式模式未参与容量判定」缺陷——现象/根因/实测证据/修法/与参考 83,160 组参数对照/回归与变异项 |
| S10b-测试覆盖率报告.md | T5-a 覆盖率报告(行级,scripts/coverage.sh 产出)+ T5-b 不下降门禁(顶部 coverage-floor 机器可读标记) |
| S11-无效代码与冗余文档清理评估.md | 清理评估入口:无效/冗余代码与文档的判定口径、实测清单、分级处置队列与执行纪律(Issue #63);§10 二次复核(修正 v1 的「能力缺口」误判)。逐轮落地记录见下条分册 |
| S11b-清理落地记录-v3-v5.md | 清理落地记录分册:§11 v3 P0/P1 落地(删冗余符号、消 2 处双份实现、补 QRCode::empty、覆盖率 26→15)、§12 v4 文件级「无实践内容」(删纯注释文件 fast_qr_moonbit.mbt、合并薄委托文件 qr_output.mbt、删 3 个零信息符号)、§13 v5 注释级过期口径巡检(6 源码文件 9 处注释 + 11 文档订正,第 5 把尺子「口径引用有效性」) |
| AGENTS.md | AI/协作者硬性约定:密钥安全、MoonBit 布局、文档死链零容忍(贡献前必读) |
| ⤷ S1–S9n 实现系列文档 | 按阶段编号的实现方案/记录/评审与性能评估全套(按需深入,从 S1 进入) |
| ⤷ fast_qr 移植参考 | Rust 参考库 v0.14.0 的架构/接口/概念分析语料(由索引统辖) |
| ⤷ 项目基础框架-详细分析.md | 立项时的资产盘点、目标架构、移植策略与分阶段路线(历史基线) |
| ⤷ wasm-编译与运行-结果分析.md | 历史记录:wasm 编译/运行全过程与早期多后端对比(wasm(WASI) 已移除) |
| ⤷ rust-环境配置脚本与fast_qr对比-setup.md | Rust 参考环境配置(scripts/setup-rust.sh)+ fast_qr 对比用法 |
⤷ 行是该目录/系列的总入口(不再逐篇平铺,避免索引与文档本体重复)。 S11 是清理/收敛的评估入口(无效代码与冗余文档的判定口径 + 处置队列), 不替代 S10(测试覆盖面)与 S10b(覆盖率数字)。 其中 S1–S9n 每篇含「实现方案 / 实现记录 / 评审与优化」等分部,按阶段顺序编号; 性能相关重点篇目:S9b(优化路线与已否决项)、S9d(vs moonbit 生态)、S9f/S9g(历史体积口径)、 S9h(环境归因)、S9l(参考 fast_qr 拆解)、S9m(ReadOnlyArray)。
.
├── moon.mod # MoonBit 模块配置(模块根不建包)
├── lib/ # 库包(公共 API,lib/moon.pkg)
│ ├── ecl / version / mode / mask.mbt # 公共枚举(ECL/Version/Mode/Mask)
│ ├── module.mbt # 公共 Module / ModuleType(单字节位打包)
│ ├── qr.mbt # QRCode 结果容器 + QRCodeError + 访问器
│ ├── qr_build.mbt # 编排/构造:select_capacity + build_fixed/build
│ ├── qr_builder.mbt # 公共 QRBuilder 构造器
│ ├── helpers.mbt # 输出层:终端画渲染 + QRCode::to_str/print
│ ├── svg.mbt / shape.mbt # 输出层:SVG 渲染 + Shape 枚举
│ ├── *_test.mbt / *_wbtest.mbt # 黑盒测试 / 白盒测试
│ └── internal/ # 实现子包(各带 moon.pkg;不反向依赖 lib)
│ ├── constants/ # 常量表 + 容量/元数据表
│ ├── bitstream/ # 位流缓冲(CompactQR)
│ ├── reedsolomon/ # GF(256) 除法 + 交织
│ ├── data_encoding/ # 三模式编码 + 自动回退
│ └── matrix/ # module/matrix/placement/datamasking/score
├── cmd/main/ # CLI 可执行入口(演示终端画 + SVG)
├── cmd/bench/ # 性能基准(含 --dump 值全集导出)
├── cmd/qr-min/ # 纯库调用体积探针(库实际体积口径,零外壳)
├── docs/ # 项目文档(见上文「文档索引」)
│ └── assets/ # 文档资源(qr-example.svg = README 示例码)
├── scripts/ # 构建与开发辅助脚本(见下节)
├── .githooks/ # 可选 Git 钩子(需自行启用)
├── .cnb.yml # 云原生构建(CNB CI)配置
├── AGENTS.md # AI 协作代理指南
├── README.md # 本文件(moon.mod 的 readme)
└── LICENSE # Apache-2.0| 角色 | 脚本 | 执行方式 |
|---|---|---|
| 环境配置 | setup-moonbit.sh、setup-rust.sh、setup-fast-qr-wasm-env.sh | 手动(幂等,本地/审计) |
| 全量门禁 | gates.sh(fmt-check → check → test → docs-link-check → test-scale → build-and-run → diff-gate → publish-check) | 本地 |
| 发布 | publish.sh(默认干跑;--publish 才真发,需确认) | 本地(不进 CI) |
| 门禁链单项 | fmt-check.sh → check.sh → test.sh → build-and-run.sh | 本地(亦由 gates.sh 串起) |
| 性能基准 | bench-host.sh + host-bench.mjs(宿主调用面:JS 反复带参调 wasm,主口径)、bench-host-var.sh + bench-host-var.mjs(统计稳定性:CV / 单跑失稳率 / 漂移)、bench.sh(层①)、bench-layer2.sh + gc-compare.mjs(层② vs fast_qr) | ❌ |
| 体积基准 | bench-size.sh + wasm-size.mjs(同规则口径 + 纯库探针 + 语义护栏) | ❌ |
| 外部检出 | build-fast-qr-wasm.sh(fast_qr 侧产物,检出副本不入库) | ❌ |
| 测试审计 | test-audit.sh(变异检测 + 解码回读)+ apply-mutation.py + qr-decode-check.mjs(--points 三基准点 / --corpus T3-d 54 组) | ❌ |
| 黄金值/规模 | gen-goldens.sh(钉版重建 + --verify 四项)+ snapshot_gen_tables.py / snapshot_gen_default.py / snapshot_gen_rs_vectors.rs / snapshot_gen_score.rs / snapshot_gen_placement.rs + snapshot_verify_*.py + test-scale.sh(单测试文件 ≤800 行护栏) | ❌ |
| 差分门禁 | diff-gate.sh(vs 参考 wasm 逐位 sha256;无制品显式 skipped) | 本地(可 skipped) |
| 覆盖率 | coverage.sh(moon coverage analyze 报告)+ --floor 不下降门禁(T5-b) | ❌ |
| 文档/规模护栏 | docs-link-check.sh(T6-c 相对链接死链) + test-scale.sh(T7-b 单测试文件 ≤800 行) | 本地 |
| 资源生成 | gen-readme-qr-svg.sh(重建 docs/assets/qr-example.svg,临时包用完即删) | ❌ |
Install
Download zipFast QR code generator library written in MoonBit