# CLAUDE.md
本文件为 Claude Code (claude.ai/code) 在此代码仓库中工作时提供指导。
## ⚠️ 重要提示:语言使用规范
**本项目强制使用中文进行所有交流和开发工作:**
1. **代码注释**:所有代码注释必须使用中文(包括文档注释、行内注释、TODO等)
2. **与用户交流**:与用户的所有对话必须使用中文
3. **思考过程**:Claude的内部思考过程必须使用中文
4. **提交信息**:Git commit消息使用中文
5. **文档**:除代码本身外的所有文档使用中文
**唯一例外**:Rust代码本身(变量名、函数名、类型名等)使用英文,以符合Rust社区规范。
---
## 项目概述
**seqtkrs** 是 [seqtk](https://github.com/lh3/seqtk) 的 Rust 重新实现,seqtk 是一个快速轻量的生物序列(FASTA/FASTQ格式)处理工具集。项目目标是保持与原始C语言实现的算法兼容性,同时利用Rust的内存安全、零成本抽象和现代工具链优势。
原始的 seqtk C 实现位于 `raw/seqtk/` 目录,可供参考。
## 构建和开发命令
```bash
# 构建项目
cargo build
# 构建优化的release版本
cargo build --release
# 运行特定命令(实现后)
cargo run -- seq <input.fq>
# 运行测试
cargo test
# 运行测试并显示输出
cargo test -- --nocapture
# 运行特定的测试
cargo test test_name
# 检查代码而不构建
cargo check
# 格式化代码
cargo fmt
# 运行clippy静态检查
cargo clippy -- -D warnings
# 生成并打开文档
cargo doc --open
# 运行性能基准测试(实现后)
cargo bench
# 检查测试覆盖率(需要安装cargo-tarpaulin)
cargo tarpaulin --out Html
```
## 架构概览
### 模块组织结构
代码库采用分层架构,从底层I/O到高层命令实现:
```
src/
├── core/ # 基础层:I/O、数据结构、查找表
├── utils/ # 工具层:随机数、区域解析、质量值处理
├── algorithms/ # 算法层:Mott修剪、采样、X-dropoff
└── commands/ # 命令层:CLI命令实现(共24个命令)
```
### 核心设计原则
1. **缓冲区复用**:通过 `.clear()` 在循环中复用 `SeqRecord` 对象,避免内存分配
2. **查找表**:预计算的256元素数组(`LOOKUP_TABLES`)提供O(1)的碱基转换
3. **尽可能零拷贝**:使用字节切片(`&[u8]`)和引用避免拷贝
4. **16KB I/O缓冲区**:与原版seqtk保持一致以获得最佳吞吐量
5. **流式处理**:一次处理一条序列,不将整个文件加载到内存
### 关键数据结构
**`SeqRecord`** (`core/seq_record.rs`)
- 表示单条FASTA/FASTQ序列
- 字段:`name: Vec<u8>`(序列名)、`comment: Option<Vec<u8>`(注释)、`seq: Vec<u8>`(序列)、`qual: Option<Vec<u8>>`(质量值)
- 使用 `.is_fastq()` 区分FASTQ和FASTA格式
- 复用前调用 `.clear()` 重置缓冲区
**`LookupTables`** (`core/tables.rs`)
- 通过 `LazyLock` 实现的全局单例:`LOOKUP_TABLES.comp`、`.nt16`、`.nt6` 等
- `comp`:ASCII → 互补碱基映射
- `nt16`:ASCII → 4位IUPAC编码(A=1, C=2, G=4, T=8,支持模糊碱基)
- `nt6`:ASCII → 简化编码(A=1, C=2, G=3, T=4, N=5)
- `bitcnt`:4位编码中1的个数
- `nt16_str`:4位编码 → ASCII字符
**`SeqReader<R: BufRead>`** (`core/seq_reader.rs`)
- 解析FASTA/FASTQ,自动检测gzip/bzip2压缩
- 循环中使用 `.read_next(&mut record)`,返回 `Result<bool>`(false表示EOF)
- 实现了 `Iterator` trait,支持函数式处理
- 通过 `SeqReader::from_path()` 或 `SeqReader::from_stdin()` 创建
**`SeqWriter<W: Write>`** (`core/seq_writer.rs`)
- 写入FASTA/FASTQ,支持可选的行宽设置
- 使用 `.with_line_width(60)` 设置FASTA换行输出
- 退出前务必调用 `.flush()` 确保缓冲区写入
## 算法实现
### Mott修剪算法 (`algorithms/trimmer.rs`)
- 使用动态规划在质量值串中找到最大得分区间
- 得分 = `error_threshold - error_prob(qual[i])`
- 如果最佳区间 < `min_length`,回退到滑动窗口方法
- 返回 `TrimResult { start, end }` 作为0-based索引
### 蓄水池采样 (`algorithms/sampler.rs`)
- **标准模式**:在内存中存储选中的序列(`ReservoirSampler`)
- **两遍模式**:仅存储索引,需要可seek的输入(`TwoPassSampler`)
- 使用 Mersenne Twister 随机数生成器(`rand_mt`)以与seqtk保持可重现性
### X-dropoff算法 (`algorithms/xdropoff.rs`)
- 用于GC含量区域检测(`gc` 命令)
- 扫描时累积得分,当 `max_score - current_score > xdrop` 时停止
- 可配置匹配/错配得分
## 命令实现模式
每个命令遵循以下结构:
```rust
// src/commands/mycommand.rs
use clap::Args;
use anyhow::Result;
use crate::core::{SeqReader, SeqWriter, SeqRecord};
#[derive(Args, Debug)]
pub struct MyCommandArgs {
#[arg(value_name = "in.fq")]
pub input: String,
// 其他标志参数...
}
pub fn run(args: &MyCommandArgs) -> Result<()> {
let mut reader = SeqReader::from_path(&args.input)?;
let mut writer = SeqWriter::to_stdout();
let mut record = SeqRecord::new(Vec::new(), Vec::new());
while reader.read_next(&mut record)? {
// 处理记录...
writer.write_record(&record)?;
}
writer.flush()?;
Ok(())
}
```
然后在 `main.rs` 中注册:
```rust
#[derive(Subcommand)]
enum Commands {
MyCommand(commands::mycommand::MyCommandArgs),
}
match cli.command {
Commands::MyCommand(args) => commands::mycommand::run(&args),
}
```
## 与原版seqtk对比测试
验证算法正确性:
```bash
# 从原版seqtk生成测试输出
cd raw/seqtk
./seqtk seq test.fq > expected.fq
# 与Rust实现对比
cd ../..
cargo run --release -- seq test.fq > actual.fq
diff expected.fq actual.fq
```
对于双端测序采样,确保使用相同的随机种子:
```bash
seqtk sample -s100 r1.fq 10000 > expected_r1.fq
cargo run -- sample -s 100 r1.fq 10000 > actual_r1.fq
```
## 性能优化要点
- **Release配置**:`Cargo.toml` 中使用 `lto = "fat"` 和 `codegen-units = 1`
- 使用 `rustc-hash::FxHashMap` 替代 `std::HashMap` 可获得约2倍速度提升
- `utils/quality.rs` 中的质量值表预计算避免重复的 `powf()` 调用
- 考虑使用 `rayon` 并行处理独立的序列
- 优化前使用 `cargo flamegraph` 或 `perf` 进行性能分析
## 开发工作流
### 添加新命令
1. 创建 `src/commands/mycommand.rs`,包含 `MyCommandArgs` 结构体和 `run()` 函数
2. 在 `src/commands/mod.rs` 中添加模块声明:`pub mod mycommand;`
3. 在 `src/main.rs` 的枚举和match语句中注册
4. 使用现有的 core/utils/algorithms 模块实现功能
5. 在 `tests/test_mycommand.rs` 中添加集成测试
6. 将输出与原版seqtk对比
### 关键实现细节
**质量值偏移**
- Phred+33(Sanger, Illumina 1.8+):最常见,默认使用33
- Phred+64(Illumina 1.3-1.7):较老的格式
- 通过 `utils::quality::detect_quality_offset()` 自动检测
**区域/BED文件解析**
- 使用 `utils::region::parse_regions()` → 返回 `FxHashMap<Vec<u8>, RegionList>`
- 同时处理名称列表(单列)和BED格式(chr, start, end, 可选链方向)
- 坐标系统为0-based,半开区间 `[start, end)`
**标准输入/输出约定**
- 输入文件 `-` 表示stdin:`if args.input == "-" { SeqReader::from_stdin() }`
- 输出始终通过 `SeqWriter::to_stdout()` 发送到stdout
- 错误消息和统计信息通过 `eprintln!()` 发送到stderr
**IUPAC模糊碱基编码**
- 通过 `nt16` 表完全支持
- R=A/G, Y=C/T, M=A/C, K=G/T, S=C/G, W=A/T
- H=非G, B=非A, V=非T, D=非C, N=任意
## 需要实现的24个命令
优先级顺序(来自 RUST_IMPLEMENTAION_PLAN.md):
**第一批(第6周)**:`seq`、`sample`、`subseq`
**第二批(第7周)**:`trimfq`、`fqchk`、`comp`
**第三批(第8周)**:`mergepe`、`dropse`、`split`、`rename`
**第四批(第9周)**:`mutfa`、`mergefa`、`famask`、`gc`、`hety`
**第五批(第10周)**:`cutN`、`gap`、`hpc`、`hrun`、`telo`、`kfreq`、`listhet`、`randbase`、`size`
参考 `raw/seqtk/seqtk.c` 查看每个命令的确切C语言实现。