minimap2_paf_io/output/
mod.rs

1use crate::data::{
2    AlignmentDifference, AlignmentType, Cigar, CigarColumn, DifferenceColumn, PAFLine,
3};
4use std::fmt::{Display, Formatter};
5
6impl Display for PAFLine {
7    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
8        // required fields
9        write!(f, "{}", self.query_sequence_name)?;
10        write!(f, "\t{}", self.query_sequence_length)?;
11        write!(f, "\t{}", self.query_start_coordinate)?;
12        write!(f, "\t{}", self.query_end_coordinate)?;
13        write!(f, "\t{}", if self.strand { '+' } else { '-' })?;
14        write!(f, "\t{}", self.target_sequence_name)?;
15        write!(f, "\t{}", self.target_sequence_length)?;
16        write!(f, "\t{}", self.target_start_coordinate_on_original_strand)?;
17        write!(f, "\t{}", self.target_end_coordinate_on_original_strand)?;
18        write!(f, "\t{}", self.number_of_matching_bases)?;
19        write!(f, "\t{}", self.number_of_bases_and_gaps)?;
20        write!(f, "\t{}", self.mapping_quality)?;
21
22        // optional fields with known order
23        if let Some(x) = self.total_number_of_mismatches_and_gaps {
24            write!(f, "\tNM:i:{x}")?;
25        }
26        if let Some(x) = self.best_segment_dp_score {
27            write!(f, "\tms:i:{x}")?;
28        }
29        if let Some(x) = self.dp_alignment_score {
30            write!(f, "\tAS:i:{x}")?;
31        }
32        if let Some(x) = self.number_of_ambiguous_bases {
33            write!(f, "\tnn:i:{x}")?;
34        }
35        if let Some(x) = &self.alignment_type {
36            write!(f, "\ttp:A:{x}")?;
37        }
38        if let Some(x) = self.number_of_minimisers {
39            write!(f, "\tcm:i:{x}")?;
40        }
41        if let Some(x) = self.chaining_score {
42            write!(f, "\ts1:i:{x}")?;
43        }
44        if let Some(x) = self.best_secondary_chaining_score {
45            write!(f, "\ts2:i:{x}")?;
46        }
47        if let Some(x) = self.gap_compressed_per_base_sequence_divergence {
48            write!(f, "\tde:f:{x}")?;
49        }
50        if let Some(x) = self.length_of_query_regions_with_repetitive_seeds {
51            write!(f, "\trl:i:{x}")?;
52        }
53
54        // optional fields without known order, or that do not contradict the known order (cg and cs)
55        // the order is the same as in the man page at https://lh3.github.io/minimap2/minimap2.html#10
56        if let Some(x) = &self.unknown_md {
57            write!(f, "\tMD:Z:{x}")?;
58        }
59        if let Some(x) = &self.supplementary_alignments {
60            write!(f, "\tSA:Z:{x}")?;
61        }
62        if let Some(x) = &self.transcript_strand {
63            write!(f, "\tts:A:{x}")?;
64        }
65        if let Some(x) = &self.cigar_string {
66            write!(f, "\tcg:Z:{x}")?;
67        }
68        if let Some(x) = &self.difference_string {
69            write!(f, "\tcs:Z:{x}")?;
70        }
71        if let Some(x) = self.approximate_per_base_sequence_divergence {
72            write!(f, "\tdv:f:{x}")?;
73        }
74
75        // unknown fields
76        for unknown_field in &self.unknown_fields {
77            write!(f, "\t{unknown_field}")?;
78        }
79
80        Ok(())
81    }
82}
83
84impl Display for AlignmentType {
85    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86        write!(
87            f,
88            "{}",
89            match self {
90                AlignmentType::Primary => "P",
91                AlignmentType::Secondary => "S",
92                AlignmentType::PrimaryInversion => "I",
93                AlignmentType::SecondaryInversion => "i",
94            }
95        )
96    }
97}
98
99impl Display for Cigar {
100    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101        for cigar_column in &self.0 {
102            write!(
103                f,
104                "{}{}",
105                match cigar_column {
106                    CigarColumn::Match(length)
107                    | CigarColumn::Insertion(length)
108                    | CigarColumn::Deletion(length)
109                    | CigarColumn::Mismatch(length) => length,
110                },
111                match cigar_column {
112                    CigarColumn::Match(_) => "M",
113                    CigarColumn::Insertion(_) => "I",
114                    CigarColumn::Deletion(_) => "D",
115                    CigarColumn::Mismatch(_) => "X",
116                }
117            )?;
118        }
119
120        Ok(())
121    }
122}
123
124impl Display for AlignmentDifference {
125    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
126        for difference_column in &self.0 {
127            match difference_column {
128                DifferenceColumn::Match { length } => write!(f, ":{length}")?,
129                DifferenceColumn::Insertion {
130                    superfluous_query_characters,
131                } => write!(f, "+{superfluous_query_characters}")?,
132                DifferenceColumn::Deletion {
133                    missing_query_characters,
134                } => write!(f, "-{missing_query_characters}")?,
135                DifferenceColumn::Mismatch { reference, query } => {
136                    write!(f, "*{reference}{query}")?
137                }
138            }
139        }
140
141        Ok(())
142    }
143}