noodles_core/
position.rs

1//! 1-based position.
2
3mod sequence_index;
4
5pub use self::sequence_index::SequenceIndex;
6
7use std::{
8    fmt,
9    num::{self, NonZeroUsize},
10    str::FromStr,
11};
12
13/// A 1-based position.
14#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
15pub struct Position(NonZeroUsize);
16
17impl Position {
18    /// The minimum value of a position.
19    pub const MIN: Self = Self(NonZeroUsize::MIN);
20
21    /// The maximum value of a position.
22    pub const MAX: Self = Self(NonZeroUsize::MAX);
23
24    /// Creates a position if the given value is not zero.
25    ///
26    /// # Examples
27    ///
28    /// ```
29    /// use noodles_core::Position;
30    /// assert!(Position::new(8).is_some());
31    /// assert!(Position::new(0).is_none());
32    /// ```
33    pub const fn new(n: usize) -> Option<Self> {
34        if let Some(m) = NonZeroUsize::new(n) {
35            Some(Self(m))
36        } else {
37            None
38        }
39    }
40
41    /// Returns the inner value.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use noodles_core::Position;
47    /// assert_eq!(Position::MIN.get(), 1);
48    /// ```
49    pub const fn get(&self) -> usize {
50        self.0.get()
51    }
52
53    /// Adds an unsigned integer to a 1-based position.
54    ///
55    /// This returns `None` if the operation overflowed.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use noodles_core::Position;
61    /// let position = Position::try_from(8)?;
62    /// assert_eq!(position.checked_add(5), Position::new(13));
63    /// # Ok::<_, noodles_core::position::TryFromIntError>(())
64    /// ```
65    pub const fn checked_add(self, other: usize) -> Option<Self> {
66        if let Some(n) = self.0.checked_add(other) {
67            Some(Self(n))
68        } else {
69            None
70        }
71    }
72}
73
74impl fmt::Display for Position {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        self.0.fmt(f)
77    }
78}
79
80/// An error returned when a position fails to parse.
81pub type ParseError = num::ParseIntError;
82
83impl FromStr for Position {
84    type Err = ParseError;
85
86    fn from_str(s: &str) -> Result<Self, Self::Err> {
87        s.parse().map(Self)
88    }
89}
90
91/// An error returned when a raw position fails to convert.
92pub type TryFromIntError = num::TryFromIntError;
93
94impl TryFrom<usize> for Position {
95    type Error = TryFromIntError;
96
97    fn try_from(n: usize) -> Result<Self, Self::Error> {
98        NonZeroUsize::try_from(n).map(Position)
99    }
100}
101
102impl From<Position> for usize {
103    fn from(position: Position) -> Self {
104        position.0.get()
105    }
106}