pa_types/
lib.rs

1pub mod cigar;
2pub mod cost;
3
4use std::cmp::Ordering;
5
6// Re-export types for convenience of `use pa_types::*;`.
7pub use cigar::*;
8pub use cost::*;
9
10/// A single base
11// NOTE: This is also part of rust-bio-types.
12pub type Base = u8;
13
14/// A sequence
15// NOTE: This is also part of rust-bio-types.
16pub type Sequence = Vec<Base>;
17
18/// A non-owning sequence
19pub type Seq<'a> = &'a [Base];
20
21/// Convert `seq` to a `String`.
22pub fn seq_to_string(seq: Seq) -> String {
23    String::from_utf8(seq.to_vec()).unwrap()
24}
25
26/// A 0-based index into a sequence.
27pub type I = i32;
28
29/// A position in a pairwise matching.
30///
31/// A matching starts at `(0,0)` and ends at `(n, m)`.
32#[derive(
33    Debug,
34    Clone,
35    Copy,
36    PartialEq,
37    Eq,
38    Hash,
39    Default,
40    derive_more::Add,
41    derive_more::Sub,
42    derive_more::AddAssign,
43    derive_more::SubAssign,
44)]
45pub struct Pos(pub I, pub I);
46
47impl std::fmt::Display for Pos {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        <Self as std::fmt::Debug>::fmt(self, f)
50    }
51}
52
53/// Partial ordering by
54/// (a,b) <= (c,d) when a<=c and b<=d.
55/// (a,b) < (c,d) when a<=c and b<=d and a<c or b<d.
56impl PartialOrd for Pos {
57    #[inline]
58    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
59        let a = self.0.cmp(&other.0);
60        let b = self.1.cmp(&other.1);
61        if a == b {
62            return Some(a);
63        }
64        if a == Ordering::Equal {
65            return Some(b);
66        }
67        if b == Ordering::Equal {
68            return Some(a);
69        }
70        None
71    }
72
73    #[inline]
74    fn le(&self, other: &Self) -> bool {
75        self.0 <= other.0 && self.1 <= other.1
76    }
77}
78
79/// The path corresponding to an alignment of two sequences.
80pub type Path = Vec<Pos>;
81
82impl Pos {
83    /// The start of an alignment.
84    pub fn start() -> Self {
85        Pos(0, 0)
86    }
87
88    /// The target of an alignment.
89    pub fn target(a: Seq, b: Seq) -> Self {
90        Pos(a.len() as I, b.len() as I)
91    }
92
93    /// The diagonal of position `(i, j)` is `i-j`.
94    pub fn diag(&self) -> I {
95        self.0 - self.1
96    }
97
98    /// The anti diagonal of position `(i, j)` is `i+j`.
99    pub fn anti_diag(&self) -> I {
100        self.0 + self.1
101    }
102
103    /// Mirror this position: `(i, j) -> (j, i)`.
104    pub fn mirror(&self) -> Pos {
105        Pos(self.1, self.0)
106    }
107
108    /// Create a position from differently typed positions.
109    pub fn from<T>(i: T, j: T) -> Self
110    where
111        T: TryInto<I>,
112        <T as TryInto<i32>>::Error: std::fmt::Debug,
113    {
114        Pos(i.try_into().unwrap(), j.try_into().unwrap())
115    }
116}
117
118/// A small wrapper around Pos that implements Ord for lexicographic ordering.
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub struct LexPos(pub Pos);
121
122impl PartialOrd for LexPos {
123    #[inline]
124    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
125        Some(self.cmp(other))
126    }
127
128    #[inline]
129    fn lt(&self, other: &Self) -> bool {
130        (self.0 .0, self.0 .1) < (other.0 .0, other.0 .1)
131    }
132}
133
134impl Ord for LexPos {
135    #[inline]
136    fn cmp(&self, other: &Self) -> Ordering {
137        (self.0 .0, self.0 .1).cmp(&(other.0 .0, other.0 .1))
138    }
139}
140
141/// Generic global pairwise alignment interface.
142pub trait Aligner: std::fmt::Debug {
143    /// An alignment of sequences `a` and `b`.
144    /// The returned cost is the *non-negative* cost of the alignment.
145    /// Costmodel and traceback parameters must be specified on construction of the aligner.
146    fn align(&mut self, a: Seq, b: Seq) -> (Cost, Option<Cigar>);
147}