Skip to main content

bed_utils/bed/
score.rs

1//! BED record score.
2
3use std::ops::Deref;
4use std::{error, fmt, str::FromStr};
5
6use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10/// A BED record score.
11#[derive(
12    Archive, RkyvSerialize, RkyvDeserialize, Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord,
13)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub struct Score(u16);
16
17impl fmt::Display for Score {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        write!(f, "{}", self.0)
20    }
21}
22
23impl Deref for Score {
24    type Target = u16;
25    fn deref(&self) -> &Self::Target {
26        &self.0
27    }
28}
29
30/// An error returned when a raw BED record score fails to parse.
31#[derive(Clone, Debug, Eq, PartialEq)]
32pub enum ParseError {
33    /// The input failed to be parsed as an integer.
34    Parse(lexical::Error),
35    /// The input is invalid.
36    Invalid(TryFromIntError),
37}
38
39impl error::Error for ParseError {}
40
41impl fmt::Display for ParseError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            Self::Parse(e) => write!(f, "parse error: {}", e),
45            Self::Invalid(e) => write!(f, "invalid input: {}", e),
46        }
47    }
48}
49
50impl FromStr for Score {
51    type Err = ParseError;
52
53    fn from_str(s: &str) -> Result<Self, Self::Err> {
54        let n: u32 = lexical::parse(s).map_err(ParseError::Parse)?;
55        Self::try_from(n).map_err(ParseError::Invalid)
56    }
57}
58
59/// An error returned when a raw BED record score fails to convert.
60#[derive(Clone, Debug, Eq, PartialEq)]
61pub struct TryFromIntError(u32);
62
63impl error::Error for TryFromIntError {}
64
65impl fmt::Display for TryFromIntError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "invalid value: {}", self.0)
68    }
69}
70
71impl TryFrom<u32> for Score {
72    type Error = TryFromIntError;
73
74    fn try_from(n: u32) -> Result<Self, Self::Error> {
75        u16::try_from(n)
76            .map(|n| Self(n))
77            .map_err(|_| TryFromIntError(n))
78    }
79}
80
81impl From<u16> for Score {
82    fn from(n: u16) -> Self {
83        Self(n)
84    }
85}
86
87impl From<Score> for u16 {
88    fn from(score: Score) -> Self {
89        score.0
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_fmt() {
99        assert_eq!(Score(1).to_string(), "1");
100        assert_eq!(Score(1000).to_string(), "1000");
101    }
102
103    #[test]
104    fn test_try_from_u16_for_score() {
105        assert_eq!(Score::try_from(1u16), Ok(Score(1)));
106        assert_eq!(Score::try_from(1000u16), Ok(Score(1000)));
107        assert_eq!(Score::try_from(2000u16), Ok(Score(2000)));
108    }
109
110    #[test]
111    fn test_from_score_for_u16() {
112        assert_eq!(u16::from(Score(8)), 8);
113    }
114}