1
//! Parser for the `stroke-dasharray` property.
2

            
3
use cssparser::Parser;
4

            
5
use crate::error::*;
6
use crate::length::*;
7
use crate::parsers::{optional_comma, Parse};
8

            
9
8899715
#[derive(Debug, Default, PartialEq, Clone)]
10
pub enum Dasharray {
11
    #[default]
12
1025853
    None,
13
878
    Array(Box<[ULength<Both>]>),
14
}
15

            
16
impl Parse for Dasharray {
17
496
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Dasharray, ParseError<'i>> {
18
496
        if parser
19
496
            .try_parse(|p| p.expect_ident_matching("none"))
20
496
            .is_ok()
21
        {
22
458
            return Ok(Dasharray::None);
23
        }
24

            
25
38
        let mut dasharray = Vec::new();
26

            
27
        loop {
28
96
            let d = ULength::<Both>::parse(parser)?;
29
88
            dasharray.push(d);
30

            
31
88
            if parser.is_exhausted() {
32
                break;
33
            }
34

            
35
58
            optional_comma(parser);
36
        }
37

            
38
30
        Ok(Dasharray::Array(dasharray.into_boxed_slice()))
39
496
    }
40
}
41

            
42
#[cfg(test)]
43
mod tests {
44
    use super::*;
45

            
46
8
    fn dasharray(l: &[ULength<Both>]) -> Dasharray {
47
8
        Dasharray::Array(l.to_vec().into_boxed_slice())
48
8
    }
49

            
50
    #[test]
51
2
    fn parses_dash_array() {
52
        // helper to cut down boilderplate
53
21
        let length_parse = |s| ULength::<Both>::parse_str(s).unwrap();
54

            
55
1
        let expected = dasharray(&[
56
1
            length_parse("1"),
57
1
            length_parse("2in"),
58
1
            length_parse("3"),
59
1
            length_parse("4%"),
60
        ]);
61

            
62
1
        let sample_1 = dasharray(&[length_parse("10"), length_parse("6")]);
63

            
64
1
        let sample_2 = dasharray(&[length_parse("5"), length_parse("5"), length_parse("20")]);
65

            
66
1
        let sample_3 = dasharray(&[
67
1
            length_parse("10px"),
68
1
            length_parse("20px"),
69
1
            length_parse("20px"),
70
        ]);
71

            
72
1
        let sample_4 = dasharray(&[
73
1
            length_parse("25"),
74
1
            length_parse("5"),
75
1
            length_parse("5"),
76
1
            length_parse("5"),
77
        ]);
78

            
79
1
        let sample_5 = dasharray(&[length_parse("3.1415926"), length_parse("8")]);
80
1
        let sample_6 = dasharray(&[length_parse("5"), length_parse("3.14")]);
81
1
        let sample_7 = dasharray(&[length_parse("2")]);
82

            
83
2
        assert_eq!(Dasharray::parse_str("none").unwrap(), Dasharray::None);
84
2
        assert_eq!(Dasharray::parse_str("1 2in,3 4%").unwrap(), expected);
85
2
        assert_eq!(Dasharray::parse_str("10,6").unwrap(), sample_1);
86
2
        assert_eq!(Dasharray::parse_str("5,5,20").unwrap(), sample_2);
87
2
        assert_eq!(Dasharray::parse_str("10px 20px 20px").unwrap(), sample_3);
88
2
        assert_eq!(Dasharray::parse_str("25  5 , 5 5").unwrap(), sample_4);
89
2
        assert_eq!(Dasharray::parse_str("3.1415926,8").unwrap(), sample_5);
90
2
        assert_eq!(Dasharray::parse_str("5, 3.14").unwrap(), sample_6);
91
2
        assert_eq!(Dasharray::parse_str("2").unwrap(), sample_7);
92

            
93
        // Negative numbers
94
1
        assert!(Dasharray::parse_str("20,40,-20").is_err());
95

            
96
        // Empty dash_array
97
1
        assert!(Dasharray::parse_str("").is_err());
98
1
        assert!(Dasharray::parse_str("\t  \n     ").is_err());
99
1
        assert!(Dasharray::parse_str(",,,").is_err());
100
1
        assert!(Dasharray::parse_str("10,  \t, 20 \n").is_err());
101

            
102
        // No trailing commas allowed, parse error
103
1
        assert!(Dasharray::parse_str("10,").is_err());
104

            
105
        // A comma should be followed by a number
106
1
        assert!(Dasharray::parse_str("20,,10").is_err());
107
2
    }
108
}