1
//! Type for values in the [0.0, 1.0] range.
2

            
3
use cssparser::Parser;
4

            
5
use crate::error::*;
6
use crate::length::*;
7
use crate::parsers::Parse;
8
use crate::util;
9

            
10
29929783
#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
11
1018
pub struct UnitInterval(pub f64);
12

            
13
impl UnitInterval {
14
3966
    pub fn clamp(val: f64) -> UnitInterval {
15
3966
        UnitInterval(util::clamp(val, 0.0, 1.0))
16
3966
    }
17
}
18

            
19
impl Parse for UnitInterval {
20
3813
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<UnitInterval, ParseError<'i>> {
21
3813
        let loc = parser.current_source_location();
22
3813
        let l: Length<Both> = Parse::parse(parser)?;
23
3808
        match l.unit {
24
3808
            LengthUnit::Px | LengthUnit::Percent => Ok(UnitInterval::clamp(l.length)),
25
            _ => Err(loc.new_custom_error(ValueErrorKind::value_error(
26
                "<unit-interval> must be in default or percent units",
27
            ))),
28
        }
29
3813
    }
30
}
31

            
32
impl From<UnitInterval> for u8 {
33
3
    fn from(val: UnitInterval) -> u8 {
34
3
        let UnitInterval(x) = val;
35
3
        (x * 255.0 + 0.5).floor() as u8
36
3
    }
37
}
38

            
39
#[cfg(test)]
40
mod tests {
41
    use super::*;
42

            
43
    #[test]
44
2
    fn clamps() {
45
1
        assert_eq!(UnitInterval::clamp(-1.0), UnitInterval(0.0));
46
1
        assert_eq!(UnitInterval::clamp(0.0), UnitInterval(0.0));
47
1
        assert_eq!(UnitInterval::clamp(0.5), UnitInterval(0.5));
48
1
        assert_eq!(UnitInterval::clamp(1.0), UnitInterval(1.0));
49
1
        assert_eq!(UnitInterval::clamp(2.0), UnitInterval(1.0));
50
2
    }
51

            
52
    #[test]
53
2
    fn parses_percentages() {
54
1
        assert_eq!(UnitInterval::parse_str("-100%").unwrap(), UnitInterval(0.0));
55
1
        assert_eq!(UnitInterval::parse_str("0%").unwrap(), UnitInterval(0.0));
56
1
        assert_eq!(UnitInterval::parse_str("50%").unwrap(), UnitInterval(0.5));
57
1
        assert_eq!(UnitInterval::parse_str("100%").unwrap(), UnitInterval(1.0));
58
1
        assert_eq!(
59
1
            UnitInterval::parse_str("100.1%").unwrap(),
60
            UnitInterval(1.0)
61
        );
62
1
        assert_eq!(UnitInterval::parse_str("200%").unwrap(), UnitInterval(1.0));
63
2
    }
64

            
65
    #[test]
66
2
    fn parses_number() {
67
1
        assert_eq!(UnitInterval::parse_str("0").unwrap(), UnitInterval(0.0));
68
1
        assert_eq!(UnitInterval::parse_str("1").unwrap(), UnitInterval(1.0));
69
1
        assert_eq!(UnitInterval::parse_str("0.5").unwrap(), UnitInterval(0.5));
70
2
    }
71

            
72
    #[test]
73
2
    fn parses_out_of_range_number() {
74
1
        assert_eq!(UnitInterval::parse_str("-10").unwrap(), UnitInterval(0.0));
75
1
        assert_eq!(UnitInterval::parse_str("10").unwrap(), UnitInterval(1.0));
76
2
    }
77

            
78
    #[test]
79
2
    fn errors_on_invalid_input() {
80
1
        assert!(UnitInterval::parse_str("").is_err());
81
1
        assert!(UnitInterval::parse_str("foo").is_err());
82
1
        assert!(UnitInterval::parse_str("-x").is_err());
83
1
        assert!(UnitInterval::parse_str("0.0foo").is_err());
84
1
        assert!(UnitInterval::parse_str("0.0%%").is_err());
85
1
        assert!(UnitInterval::parse_str("%").is_err());
86
2
    }
87

            
88
    #[test]
89
2
    fn convert() {
90
1
        assert_eq!(u8::from(UnitInterval(0.0)), 0);
91
1
        assert_eq!(u8::from(UnitInterval(0.5)), 128);
92
1
        assert_eq!(u8::from(UnitInterval(1.0)), 255);
93
2
    }
94
}