bed_utils/bed/
score.rs

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