use anyhow::{Context, Result};
use clap::Args;
use crate::core::{SeqReader, SeqRecord, SeqWriter};
#[derive(Args, Debug)]
pub struct RenameArgs {
#[arg(value_name = "in.fq", default_value = "-")]
pub input: String,
#[arg(value_name = "prefix")]
pub prefix: Option<String>,
}
fn names_equal(name1: &[u8], name2: &[u8]) -> bool {
if name1.len() != name2.len() {
return false;
}
let compare_len = if name1.len() > 2
&& name1[name1.len() - 2] == b'/'
&& name2[name2.len() - 2] == b'/'
&& name1[name1.len() - 1].is_ascii_digit()
&& name2[name2.len() - 1].is_ascii_digit()
{
name1.len() - 2
} else {
name1.len()
};
name1[..compare_len] == name2[..compare_len]
}
fn write_renamed_record<W: std::io::Write>(
writer: &mut SeqWriter<W>,
record: &SeqRecord,
prefix: Option<&str>,
number: u64,
) -> Result<()> {
let new_name = if let Some(p) = prefix {
format!("{}{}", p, number).into_bytes()
} else {
format!("{}", number).into_bytes()
};
let renamed_record = SeqRecord {
name: new_name,
comment: record.comment.clone(),
seq: record.seq.clone(),
qual: record.qual.clone(),
};
writer.write_record(&renamed_record)?;
Ok(())
}
pub fn run(args: &RenameArgs) -> Result<()> {
let mut reader = if args.input == "-" {
SeqReader::from_stdin()
} else {
SeqReader::from_path(&args.input)
.with_context(|| format!("无法打开输入文件: {}", args.input))?
};
let mut writer = SeqWriter::to_stdout();
let mut last_record: Option<SeqRecord> = None;
let mut current_record = SeqRecord::new(Vec::new(), Vec::new());
let mut sequence_number: u64 = 1;
while reader.read_next(&mut current_record)? {
if let Some(last) = last_record.take() {
if names_equal(&last.name, ¤t_record.name) {
write_renamed_record(&mut writer, &last, args.prefix.as_deref(), sequence_number)?;
write_renamed_record(
&mut writer,
¤t_record,
args.prefix.as_deref(),
sequence_number,
)?;
sequence_number += 1;
} else {
write_renamed_record(&mut writer, &last, args.prefix.as_deref(), sequence_number)?;
sequence_number += 1;
last_record = Some(current_record.clone());
}
} else {
last_record = Some(current_record.clone());
}
}
if let Some(last) = last_record {
write_renamed_record(&mut writer, &last, args.prefix.as_deref(), sequence_number)?;
}
writer.flush()?;
Ok(())
}