biodiff_align/
rustbio.rs

1use serde::{Deserialize, Serialize};
2
3pub const DEFAULT_KMER: usize = 8;
4pub const DEFAULT_WINDOW: usize = 6;
5/// Determines whether to use the banded variant of the algorithm with given k-mer length
6/// and window size for the rustbio backend
7#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
8pub enum Banded {
9    #[default]
10    Normal,
11    Banded {
12        kmer: usize,
13        window: usize,
14    },
15}
16
17/// The RustBio aligner, with optional banding.
18#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
19pub struct RustBio {
20    pub band: Banded,
21}
22
23#[cfg(feature = "bio")]
24/// Whether the RustBio backend is available.
25pub const RUSTBIO_AVAILABLE: bool = true;
26#[cfg(not(feature = "bio"))]
27/// Whether the RustBio backend is available.
28pub const RUSTBIO_AVAILABLE: bool = false;
29
30#[cfg(feature = "bio")]
31mod implemented {
32    use crate::{Align, AlignAlgorithm, CheckStatus, InternalMode, Op};
33    use bio::alignment::{
34        pairwise::{self, MatchFunc, Scoring},
35        AlignmentOperation,
36    };
37
38    use super::*;
39    fn scorer(
40        algo: &AlignAlgorithm,
41        mode: InternalMode,
42    ) -> Scoring<impl MatchFunc + Copy + Send + Sync> {
43        let match_score = algo.match_score;
44        let mismatch_score = algo.mismatch_score;
45        let score = move |a: u8, b: u8| {
46            if a == b {
47                match_score
48            } else {
49                mismatch_score
50            }
51        };
52        let scorer = Scoring::new(algo.gap_open, algo.gap_extend, score);
53        match mode {
54            InternalMode::Global => scorer,
55            InternalMode::Semiglobal => scorer.yclip(0),
56        }
57    }
58
59    impl Align for RustBio {
60        fn align(&self, algo: &AlignAlgorithm, mode: InternalMode, x: &[u8], y: &[u8]) -> Vec<Op> {
61            let scoring = scorer(algo, mode);
62            let res = match self.band {
63                Banded::Normal => {
64                    pairwise::Aligner::with_scoring(scoring)
65                        .custom(x, y)
66                        .operations
67                }
68                Banded::Banded { kmer, window } => {
69                    pairwise::banded::Aligner::with_scoring(scoring, kmer, window)
70                        .custom(x, y)
71                        .operations
72                }
73            };
74            res.into_iter()
75                .map(|op| match op {
76                    AlignmentOperation::Match => Op::Match,
77                    AlignmentOperation::Subst => Op::Subst,
78                    AlignmentOperation::Del => Op::Del,
79                    AlignmentOperation::Ins => Op::Ins,
80                    AlignmentOperation::Xclip(x) => Op::Xclip(x),
81                    AlignmentOperation::Yclip(y) => Op::Yclip(y),
82                })
83                .collect()
84        }
85
86        fn check_params(
87            &self,
88            _: &AlignAlgorithm,
89            _: InternalMode,
90            x_size: usize,
91            y_size: usize,
92        ) -> CheckStatus {
93            const SIZE_LIMIT: u64 = 1 << 30;
94            if x_size as u64 * y_size as u64 > SIZE_LIMIT {
95                return CheckStatus::MemoryWarning;
96            }
97            CheckStatus::Ok
98        }
99    }
100}
101
102#[cfg(not(feature = "bio"))]
103mod unimplemented {
104    use crate::{Align, CheckStatus, Op};
105
106    impl Align for super::RustBio {
107        fn align(
108            &self,
109            _algo: &crate::AlignAlgorithm,
110            _mode: crate::InternalMode,
111            _x: &[u8],
112            _y: &[u8],
113        ) -> Vec<Op> {
114            unimplemented!()
115        }
116
117        fn check_params(
118            &self,
119            _algo: &crate::AlignAlgorithm,
120            _mode: crate::InternalMode,
121            _x_size: usize,
122            _y_size: usize,
123        ) -> CheckStatus {
124            return CheckStatus::Error(String::from(
125                "Rust-bio is not available. Please recompile with the\n\
126                `bio` feature enabled or choose another algorithm.",
127            ));
128        }
129    }
130}