Skip to content

Commit ed39f9c

Browse files
committed
chore: unify cigar stringification
1 parent e0a10fe commit ed39f9c

6 files changed

Lines changed: 33 additions & 59 deletions

File tree

src/align/read_align.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ pub fn align_read(
323323
} else {
324324
"unknown"
325325
};
326-
let cigar_str: String = t.cigar.iter().map(|op| format!("{}", op)).collect();
327326
eprintln!(
328327
" transcript[{}]: chr={}:{}-{} ({}) score={} mm={} junctions={} cigar={}",
329328
ti,
@@ -334,7 +333,7 @@ pub fn align_read(
334333
t.score,
335334
t.n_mismatch,
336335
t.n_junction,
337-
cigar_str
336+
t.cigar_string()
338337
);
339338
}
340339
}
@@ -633,7 +632,6 @@ pub fn align_read(
633632
} else {
634633
"unknown"
635634
};
636-
let cigar_str: String = t.cigar.iter().map(|op| format!("{}", op)).collect();
637635
eprintln!(
638636
" FINAL[{}]: chr={}:{}-{} ({}) score={} mm={} junctions={} cigar={}",
639637
i,
@@ -644,7 +642,7 @@ pub fn align_read(
644642
t.score,
645643
t.n_mismatch,
646644
t.n_junction,
647-
cigar_str
645+
t.cigar_string()
648646
);
649647
}
650648
}

src/align/transcript.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// Transcript data structures for storing alignment results
2-
use std::fmt;
2+
use std::fmt::Write as _;
33

44
/// A complete alignment of a read to the genome
55
#[derive(Debug, Clone)]
@@ -134,16 +134,18 @@ impl CigarOp {
134134
}
135135
}
136136

137-
impl fmt::Display for CigarOp {
138-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139-
write!(f, "{}{}", self.len(), self.op_char())
140-
}
137+
/// Convert CIGAR operations to CIGAR string
138+
pub(crate) fn cigar_to_string(cigar: &[CigarOp]) -> String {
139+
cigar.iter().fold(String::new(), |mut c, op| {
140+
let _ = write!(c, "{}{}", op.len(), op.op_char()); // infallible
141+
c
142+
})
141143
}
142144

143145
impl Transcript {
144146
/// Format CIGAR string
145147
pub fn cigar_string(&self) -> String {
146-
self.cigar.iter().map(|op| op.to_string()).collect()
148+
cigar_to_string(&self.cigar)
147149
}
148150

149151
/// Calculate number of matched bases (for filtering)
@@ -201,12 +203,16 @@ mod tests {
201203
use super::*;
202204

203205
#[test]
204-
fn test_cigar_op_display() {
205-
assert_eq!(CigarOp::Match(50).to_string(), "50M");
206-
assert_eq!(CigarOp::Ins(3).to_string(), "3I");
207-
assert_eq!(CigarOp::Del(2).to_string(), "2D");
208-
assert_eq!(CigarOp::RefSkip(1000).to_string(), "1000N");
209-
assert_eq!(CigarOp::SoftClip(5).to_string(), "5S");
206+
fn test_cigar_to_string() {
207+
let cigar = vec![
208+
CigarOp::Match(50),
209+
CigarOp::Ins(2),
210+
CigarOp::Del(3),
211+
CigarOp::RefSkip(1000),
212+
CigarOp::SoftClip(5),
213+
];
214+
215+
assert_eq!(cigar_to_string(&cigar), "50M2I3D1000N5S");
210216
}
211217

212218
#[test]

src/chimeric/output.rs

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ impl ChimericJunctionWriter {
7878
let acceptor_start = alignment.acceptor.genome_start + 1;
7979

8080
// Convert CIGAR to string
81-
let donor_cigar = cigar_to_string(&alignment.donor.cigar);
82-
let acceptor_cigar = cigar_to_string(&alignment.acceptor.cigar);
81+
let donor_cigar = alignment.donor.cigar_string();
82+
let acceptor_cigar = alignment.acceptor.cigar_string();
8383

8484
// Write line
8585
writeln!(
@@ -162,7 +162,7 @@ fn format_sa_entry(
162162
let chr_start = chr_starts[seg.chr_idx];
163163
let pos = seg.genome_start - chr_start + 1; // 1-based per-chr
164164
let strand = if seg.is_reverse { '-' } else { '+' };
165-
let cigar = cigar_to_string(&seg.cigar);
165+
let cigar = seg.cigar_string();
166166
format!(
167167
"{},{},{},{},{},{};",
168168
chr, pos, strand, cigar, mapq, seg.n_mismatch
@@ -233,26 +233,6 @@ fn build_segment_record(
233233
Ok(record)
234234
}
235235

236-
/// Convert CIGAR operations to CIGAR string
237-
fn cigar_to_string(cigar: &[crate::align::transcript::CigarOp]) -> String {
238-
use crate::align::transcript::CigarOp;
239-
240-
let mut result = String::new();
241-
for op in cigar {
242-
match op {
243-
CigarOp::Match(len) => result.push_str(&format!("{}M", len)),
244-
CigarOp::Equal(len) => result.push_str(&format!("{}=", len)),
245-
CigarOp::Diff(len) => result.push_str(&format!("{}X", len)),
246-
CigarOp::Ins(len) => result.push_str(&format!("{}I", len)),
247-
CigarOp::Del(len) => result.push_str(&format!("{}D", len)),
248-
CigarOp::RefSkip(len) => result.push_str(&format!("{}N", len)),
249-
CigarOp::SoftClip(len) => result.push_str(&format!("{}S", len)),
250-
CigarOp::HardClip(len) => result.push_str(&format!("{}H", len)),
251-
}
252-
}
253-
result
254-
}
255-
256236
#[cfg(test)]
257237
mod tests {
258238
use super::*;
@@ -261,19 +241,6 @@ mod tests {
261241
use std::io::Read;
262242
use tempfile::tempdir;
263243

264-
#[test]
265-
fn test_cigar_to_string() {
266-
let cigar = vec![
267-
CigarOp::Match(50),
268-
CigarOp::Ins(2),
269-
CigarOp::Del(3),
270-
CigarOp::RefSkip(1000),
271-
CigarOp::SoftClip(5),
272-
];
273-
274-
assert_eq!(cigar_to_string(&cigar), "50M2I3D1000N5S");
275-
}
276-
277244
#[test]
278245
fn test_chimeric_junction_writer_creation() {
279246
let dir = tempdir().unwrap();

src/chimeric/segment.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// ChimericSegment and ChimericAlignment data structures
22

3-
use crate::align::transcript::CigarOp;
3+
use crate::align::transcript::{CigarOp, cigar_to_string};
44

55
/// A single segment of a chimeric alignment
66
#[derive(Debug, Clone)]
@@ -31,6 +31,11 @@ impl ChimericSegment {
3131
pub fn meets_min_length(&self, min_len: u32) -> bool {
3232
self.read_length() >= min_len as usize
3333
}
34+
35+
/// Format CIGAR string
36+
pub fn cigar_string(&self) -> String {
37+
cigar_to_string(&self.cigar)
38+
}
3439
}
3540

3641
/// A chimeric alignment consisting of two segments

src/io/sam.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,10 @@ impl SamWriter {
149149
.name()
150150
.map(|n| String::from_utf8_lossy(n.as_ref()).to_string())
151151
.unwrap_or_default();
152-
let cigar_str: String = cigar_ops
153-
.iter()
154-
.map(|op| format!("{}{:?}", op.len(), op.kind()))
155-
.collect::<String>();
152+
let cigar_str = cigar_ops.iter().fold(String::new(), |mut c, op| {
153+
let _ = write!(c, "{}{:?}", op.len(), op.kind()); // infallible
154+
c
155+
});
156156
panic!(
157157
"[SAM-MISMATCH] read={} cigar_query_len={} seq_len={} flags={:?} cigar={}",
158158
name,

src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
clippy::cast_precision_loss,
88
clippy::cast_sign_loss,
99
clippy::doc_markdown,
10-
clippy::format_collect,
11-
clippy::format_push_string,
1210
clippy::items_after_statements,
1311
clippy::match_same_arms,
1412
clippy::missing_errors_doc,

0 commit comments

Comments
 (0)