omics_coordinate/coordinate/
base.rs

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