rsvg/
coord_units.rs

1//! `userSpaceOnUse` or `objectBoundingBox` values.
2
3use cssparser::Parser;
4
5use crate::error::*;
6use crate::parse_identifiers;
7use crate::parsers::Parse;
8
9/// Defines the units to be used for things that can consider a
10/// coordinate system in terms of the current transformation, or in
11/// terms of the current object's bounding box.
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum CoordUnits {
14    UserSpaceOnUse,
15    ObjectBoundingBox,
16}
17
18impl Parse for CoordUnits {
19    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
20        Ok(parse_identifiers!(
21            parser,
22            "userSpaceOnUse" => CoordUnits::UserSpaceOnUse,
23            "objectBoundingBox" => CoordUnits::ObjectBoundingBox,
24        )?)
25    }
26}
27
28/// Creates a newtype around `CoordUnits`, with a default value.
29///
30/// SVG attributes that can take `userSpaceOnUse` or
31/// `objectBoundingBox` values often have different default values
32/// depending on the type of SVG element.  We use this macro to create
33/// a newtype for each SVG element and attribute that requires values
34/// of this type.  The newtype provides an `impl Default` with the
35/// specified `$default` value.
36#[doc(hidden)]
37#[macro_export]
38macro_rules! coord_units {
39    ($name:ident, $default:expr) => {
40        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
41        pub struct $name(pub CoordUnits);
42
43        impl Default for $name {
44            fn default() -> Self {
45                $name($default)
46            }
47        }
48
49        impl From<$name> for CoordUnits {
50            fn from(u: $name) -> Self {
51                u.0
52            }
53        }
54
55        impl $crate::parsers::Parse for $name {
56            fn parse<'i>(
57                parser: &mut ::cssparser::Parser<'i, '_>,
58            ) -> Result<Self, $crate::error::ParseError<'i>> {
59                Ok($name($crate::coord_units::CoordUnits::parse(parser)?))
60            }
61        }
62    };
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    coord_units!(MyUnits, CoordUnits::ObjectBoundingBox);
70
71    #[test]
72    fn parsing_invalid_strings_yields_error() {
73        assert!(MyUnits::parse_str("").is_err());
74        assert!(MyUnits::parse_str("foo").is_err());
75    }
76
77    #[test]
78    fn parses_paint_server_units() {
79        assert_eq!(
80            MyUnits::parse_str("userSpaceOnUse").unwrap(),
81            MyUnits(CoordUnits::UserSpaceOnUse)
82        );
83        assert_eq!(
84            MyUnits::parse_str("objectBoundingBox").unwrap(),
85            MyUnits(CoordUnits::ObjectBoundingBox)
86        );
87    }
88
89    #[test]
90    fn has_correct_default() {
91        assert_eq!(MyUnits::default(), MyUnits(CoordUnits::ObjectBoundingBox));
92    }
93
94    #[test]
95    fn converts_to_coord_units() {
96        assert_eq!(
97            CoordUnits::from(MyUnits(CoordUnits::ObjectBoundingBox)),
98            CoordUnits::ObjectBoundingBox
99        );
100    }
101}