1 use std::str::FromStr;
2 
3 use {
4     Error,
5     Result,
6     Stream,
7     WriteBuffer,
8     WriteOptions,
9 };
10 
11 /// Representation of the [`<list-of-numbers>`] type.
12 ///
13 /// [`<list-of-numbers>`]: https://www.w3.org/TR/SVG11/types.html#DataTypeList
14 #[derive(Clone, PartialEq, Default)]
15 pub struct NumberList(pub Vec<f64>);
16 
17 impl_from_vec!(NumberList, NumberList, f64);
18 impl_vec_defer!(NumberList, f64);
19 impl_display!(NumberList);
20 impl_debug_from_display!(NumberList);
21 
22 /// A pull-based [`<list-of-numbers>`] parser.
23 ///
24 /// # Example
25 ///
26 /// ```
27 /// use svgtypes::NumberListParser;
28 ///
29 /// let mut p = NumberListParser::from("10, 20 -50");
30 /// assert_eq!(p.next().unwrap().unwrap(), 10.0);
31 /// assert_eq!(p.next().unwrap().unwrap(), 20.0);
32 /// assert_eq!(p.next().unwrap().unwrap(), -50.0);
33 /// assert_eq!(p.next().is_none(), true);
34 /// ```
35 ///
36 /// [`<list-of-numbers>`]: https://www.w3.org/TR/SVG11/types.html#DataTypeList
37 #[derive(Clone, Copy, PartialEq, Debug)]
38 pub struct NumberListParser<'a>(Stream<'a>);
39 
40 impl<'a> From<&'a str> for NumberListParser<'a> {
from(v: &'a str) -> Self41     fn from(v: &'a str) -> Self {
42         NumberListParser(Stream::from(v))
43     }
44 }
45 
46 impl<'a> Iterator for NumberListParser<'a> {
47     type Item = Result<f64>;
48 
next(&mut self) -> Option<Self::Item>49     fn next(&mut self) -> Option<Self::Item> {
50         if self.0.at_end() {
51             None
52         } else {
53             let v = self.0.parse_list_number();
54             if v.is_err() {
55                 self.0.jump_to_end();
56             }
57 
58             Some(v)
59         }
60     }
61 }
62 
63 impl FromStr for NumberList {
64     type Err = Error;
65 
from_str(text: &str) -> Result<Self>66     fn from_str(text: &str) -> Result<Self> {
67         let mut vec = Vec::new();
68         for number in NumberListParser::from(text) {
69             vec.push(number?);
70         }
71 
72         Ok(NumberList(vec))
73     }
74 }
75 
76 #[cfg(test)]
77 mod tests {
78     use super::*;
79     use ListSeparator;
80 
81     #[test]
write_1()82     fn write_1() {
83         let list = NumberList(vec![1.0, 2.0, 3.0]);
84 
85         let mut opt = WriteOptions::default();
86         opt.list_separator = ListSeparator::Space;
87 
88         assert_eq!(list.with_write_opt(&opt).to_string(), "1 2 3");
89     }
90 
91     #[test]
write_2()92     fn write_2() {
93         let list = NumberList(vec![1.0, 2.0, 3.0]);
94 
95         let mut opt = WriteOptions::default();
96         opt.list_separator = ListSeparator::Comma;
97 
98         assert_eq!(list.with_write_opt(&opt).to_string(), "1,2,3");
99     }
100 
101     #[test]
write_3()102     fn write_3() {
103         let list = NumberList(vec![1.0, 2.0, 3.0]);
104 
105         let mut opt = WriteOptions::default();
106         opt.list_separator = ListSeparator::CommaSpace;
107 
108         assert_eq!(list.with_write_opt(&opt).to_string(), "1, 2, 3");
109     }
110 }
111