1use crate::Stream;
2
3/// List of possible [`ViewBox`] parsing errors.
4#[derive(Clone, Copy, Debug)]
5pub enum ViewBoxError {
6 /// One of the numbers is invalid.
7 InvalidNumber,
8
9 /// ViewBox has a negative or zero size.
10 InvalidSize,
11}
12
13impl std::fmt::Display for ViewBoxError {
14 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
15 match *self {
16 ViewBoxError::InvalidNumber => {
17 write!(f, "viewBox contains an invalid number")
18 }
19 ViewBoxError::InvalidSize => {
20 write!(f, "viewBox has a negative or zero size")
21 }
22 }
23 }
24}
25
26impl std::error::Error for ViewBoxError {
27 fn description(&self) -> &str {
28 "a viewBox parsing error"
29 }
30}
31
32/// Representation of the [`<viewBox>`] type.
33///
34/// [`<viewBox>`]: https://www.w3.org/TR/SVG2/coords.html#ViewBoxAttribute
35#[allow(missing_docs)]
36#[derive(Clone, Copy, PartialEq, Debug)]
37pub struct ViewBox {
38 pub x: f64,
39 pub y: f64,
40 pub w: f64,
41 pub h: f64,
42}
43
44impl ViewBox {
45 /// Creates a new `ViewBox`.
46 pub fn new(x: f64, y: f64, w: f64, h: f64) -> Self {
47 ViewBox { x, y, w, h }
48 }
49}
50
51impl std::str::FromStr for ViewBox {
52 type Err = ViewBoxError;
53
54 fn from_str(text: &str) -> Result<Self, ViewBoxError> {
55 let mut s = Stream::from(text);
56
57 let x = s
58 .parse_list_number()
59 .map_err(|_| ViewBoxError::InvalidNumber)?;
60 let y = s
61 .parse_list_number()
62 .map_err(|_| ViewBoxError::InvalidNumber)?;
63 let w = s
64 .parse_list_number()
65 .map_err(|_| ViewBoxError::InvalidNumber)?;
66 let h = s
67 .parse_list_number()
68 .map_err(|_| ViewBoxError::InvalidNumber)?;
69
70 if w <= 0.0 || h <= 0.0 {
71 return Err(ViewBoxError::InvalidSize);
72 }
73
74 Ok(ViewBox::new(x, y, w, h))
75 }
76}
77
78#[rustfmt::skip]
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use std::str::FromStr;
83
84 macro_rules! test {
85 ($name:ident, $text:expr, $result:expr) => (
86 #[test]
87 fn $name() {
88 let v = ViewBox::from_str($text).unwrap();
89 assert_eq!(v, $result);
90 }
91 )
92 }
93
94 test!(parse_1, "-20 30 100 500", ViewBox::new(-20.0, 30.0, 100.0, 500.0));
95
96 macro_rules! test_err {
97 ($name:ident, $text:expr, $result:expr) => (
98 #[test]
99 fn $name() {
100 assert_eq!(ViewBox::from_str($text).unwrap_err().to_string(), $result);
101 }
102 )
103 }
104
105 test_err!(parse_err_1, "qwe", "viewBox contains an invalid number");
106 test_err!(parse_err_2, "10 20 30 0", "viewBox has a negative or zero size");
107 test_err!(parse_err_3, "10 20 0 40", "viewBox has a negative or zero size");
108 test_err!(parse_err_4, "10 20 0 0", "viewBox has a negative or zero size");
109 test_err!(parse_err_5, "10 20 -30 0", "viewBox has a negative or zero size");
110 test_err!(parse_err_6, "10 20 30 -40", "viewBox has a negative or zero size");
111 test_err!(parse_err_7, "10 20 -30 -40", "viewBox has a negative or zero size");
112}
113