rsvart/ops/
transposable.rs

1use crate::genomic::{Contiged, Strand, Stranded};
2use crate::ops::{Located, Unit};
3
4pub trait Transposable<C> {
5    fn start_on_strand(&self, strand: Strand) -> C;
6
7    fn end_on_strand(&self, strand: Strand) -> C;
8}
9
10impl<C, T> Transposable<C> for T
11where
12    C: Unit,
13    T: Contiged<C> + Located<C> + Stranded,
14{
15    fn start_on_strand(&self, strand: Strand) -> C {
16        match self.strand().eq(&strand) {
17            true => *self.start(),
18            false => *self.contig().end() - *self.end(),
19        }
20    }
21
22    fn end_on_strand(&self, strand: Strand) -> C {
23        match self.strand().eq(&strand) {
24            true => *self.end(),
25            false => *self.contig().end() - *self.start(),
26        }
27    }
28}
29
30#[cfg(test)]
31mod test {
32    use super::*;
33    use crate::genomic::{AssignedMoleculeType, Contig, SequenceRole};
34    use rstest::rstest;
35
36    #[derive(PartialEq, Eq)]
37    struct TestRegion {
38        strand: Strand,
39        start: u8,
40        end: u8,
41        contig: Contig<u8>,
42    }
43
44    impl Stranded for TestRegion {
45        fn strand(&self) -> Strand {
46            self.strand
47        }
48    }
49
50    impl Located<u8> for TestRegion {
51        fn start(&self) -> &u8 {
52            &self.start
53        }
54
55        fn end(&self) -> &u8 {
56            &self.end
57        }
58    }
59
60    impl Contiged<u8> for TestRegion {
61        type Contig = Contig<u8>;
62
63        fn contig(&self) -> &Self::Contig {
64            &self.contig
65        }
66    }
67    fn get_test_contig() -> Contig<u8> {
68        Contig::new(
69            "1".to_string(),
70            SequenceRole::AssembledMolecule,
71            "1".to_string(),
72            AssignedMoleculeType::Chromosome,
73            249,
74            "CM000663.1".to_string(),
75            "NC_000001.10".to_string(),
76            "chr1".to_string(),
77        )
78        .unwrap()
79    }
80    #[rstest]
81    fn test_start_on_strand() {
82        let contig = get_test_contig();
83        let test_region = TestRegion {
84            strand: Strand::Reverse,
85            start: 32,
86            end: 200,
87            contig,
88        };
89        assert_eq!(
90            test_region.start_on_strand(Strand::Reverse),
91            *test_region.start()
92        );
93        assert_eq!(test_region.start_on_strand(Strand::Forward), 49);
94    }
95
96    #[rstest]
97    fn test_end_on_strand() {
98        let contig = get_test_contig();
99        let test_region = TestRegion {
100            strand: Strand::Reverse,
101            start: 32,
102            end: 200,
103            contig,
104        };
105        assert_eq!(
106            test_region.end_on_strand(Strand::Reverse),
107            *test_region.end()
108        );
109        assert_eq!(test_region.end_on_strand(Strand::Forward), 217);
110    }
111}