Skip to main content

omics_coordinate/coordinate/
base.rs

1//! Convenient access to a base [`Coordinate`](crate::Coordinate).
2
3use crate::Strand;
4use crate::contig;
5use crate::coordinate::Error;
6use crate::position;
7use crate::position::base::Position;
8use crate::strand;
9use crate::system::Base;
10use crate::system::Interbase;
11
12/// A base coordinate.
13pub type Coordinate = crate::Coordinate<Base>;
14
15impl Coordinate {
16    /// Consumes `self` and attempts to convert the coordinate to the next
17    /// interbase coordinate.
18    ///
19    /// This is only useful when converting a coordinate to the other coordinate
20    /// system, which is not a common operation. If, instead, you wish to move
21    /// the coordinate forward within the _same_ coordinate system, you're
22    /// almost certainly looking for
23    /// [`move_forward()`](crate::Coordinate::move_forward).
24    pub fn nudge_forward(self) -> Option<crate::Coordinate<Interbase>> {
25        let (contig, strand, position) = self.into_parts();
26
27        let position = match strand {
28            Strand::Positive => crate::Position::<Interbase>::new(position.get()),
29            Strand::Negative => position
30                .get()
31                .checked_sub(1)
32                .map(crate::Position::<Interbase>::new)?,
33        };
34
35        Some(crate::Coordinate::<Interbase>::new(
36            contig, strand, position,
37        ))
38    }
39
40    /// Consumes `self` and attempts to convert the coordinate to the previous
41    /// interbase coordinate.
42    ///
43    /// This is only useful when converting a coordinate to the other coordinate
44    /// system, which is not a common operation. If, instead, you wish to move
45    /// the coordinate backward within the _same_ coordinate system, you're
46    /// almost certainly looking for
47    /// [`move_backward()`](crate::Coordinate::move_backward).
48    pub fn nudge_backward(self) -> Option<crate::Coordinate<Interbase>> {
49        let (contig, strand, position) = self.into_parts();
50
51        let position = match strand {
52            Strand::Positive => position
53                .get()
54                .checked_sub(1)
55                .map(crate::Position::<Interbase>::new)?,
56            Strand::Negative => crate::Position::<Interbase>::new(position.get()),
57        };
58
59        Some(crate::Coordinate::<Interbase>::new(
60            contig, strand, position,
61        ))
62    }
63}
64
65impl crate::coordinate::r#trait::Coordinate<Base> for Coordinate {
66    fn try_new(
67        contig: impl TryInto<crate::Contig, Error = contig::Error>,
68        strand: impl TryInto<crate::Strand, Error = strand::Error>,
69        position: position::Number,
70    ) -> super::Result<Self> {
71        let contig = contig.try_into().map_err(Error::Contig)?;
72        let strand = strand.try_into().map_err(Error::Strand)?;
73        let position = Position::try_new(position).map_err(Error::Position)?;
74
75        Ok(Self {
76            system: Base,
77            contig,
78            strand,
79            position,
80        })
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::interbase;
88    use crate::position::Number;
89
90    fn create_coordinate(contig: &str, strand: &str, position: Number) -> Coordinate {
91        Coordinate::try_new(contig, strand, position).unwrap()
92    }
93
94    fn create_interbase_coordinate(
95        contig: &str,
96        strand: &str,
97        position: Number,
98    ) -> interbase::Coordinate {
99        interbase::Coordinate::try_new(contig, strand, position).unwrap()
100    }
101
102    #[test]
103    fn nudge_forward() {
104        let coordinate = create_coordinate("seq0", "+", 1);
105        assert_eq!(
106            coordinate.nudge_forward().unwrap(),
107            create_interbase_coordinate("seq0", "+", 1)
108        );
109
110        let coordinate = create_coordinate("seq0", "+", 10);
111        assert_eq!(
112            coordinate.nudge_forward().unwrap(),
113            create_interbase_coordinate("seq0", "+", 10)
114        );
115
116        let coordinate = create_coordinate("seq0", "+", Number::MAX);
117        assert_eq!(
118            coordinate.nudge_forward().unwrap(),
119            create_interbase_coordinate("seq0", "+", Number::MAX)
120        );
121
122        let coordinate = create_coordinate("seq0", "-", 1);
123        assert_eq!(
124            coordinate.nudge_forward().unwrap(),
125            create_interbase_coordinate("seq0", "-", 0)
126        );
127
128        let coordinate = create_coordinate("seq0", "-", 10);
129        assert_eq!(
130            coordinate.nudge_forward().unwrap(),
131            create_interbase_coordinate("seq0", "-", 9)
132        );
133
134        let coordinate = create_coordinate("seq0", "-", Number::MAX);
135        assert_eq!(
136            coordinate.nudge_forward().unwrap(),
137            create_interbase_coordinate("seq0", "-", Number::MAX - 1)
138        );
139    }
140
141    #[test]
142    fn nudge_backward() {
143        let coordinate = create_coordinate("seq0", "+", 1);
144        assert_eq!(
145            coordinate.nudge_backward().unwrap(),
146            create_interbase_coordinate("seq0", "+", 0)
147        );
148
149        let coordinate = create_coordinate("seq0", "+", 10);
150        assert_eq!(
151            coordinate.nudge_backward().unwrap(),
152            create_interbase_coordinate("seq0", "+", 9)
153        );
154
155        let coordinate = create_coordinate("seq0", "+", Number::MAX);
156        assert_eq!(
157            coordinate.nudge_backward().unwrap(),
158            create_interbase_coordinate("seq0", "+", Number::MAX - 1)
159        );
160
161        let coordinate = create_coordinate("seq0", "-", 1);
162        assert_eq!(
163            coordinate.nudge_backward().unwrap(),
164            create_interbase_coordinate("seq0", "-", 1)
165        );
166
167        let coordinate = create_coordinate("seq0", "-", 10);
168        assert_eq!(
169            coordinate.nudge_backward().unwrap(),
170            create_interbase_coordinate("seq0", "-", 10)
171        );
172
173        let coordinate = create_coordinate("seq0", "-", Number::MAX);
174        assert_eq!(
175            coordinate.nudge_backward().unwrap(),
176            create_interbase_coordinate("seq0", "-", Number::MAX)
177        );
178    }
179}