Skip to main content

omics_coordinate/coordinate/
interbase.rs

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