[librsvg] macros: extend macro to deal with properties that are not enums



commit 6f73b2d38dda7928439d6e4cee23216cfcae8326
Author: Paolo Borelli <pborelli gnome org>
Date:   Tue Mar 27 09:20:18 2018 +0200

    macros: extend macro to deal with properties that are not enums
    
    Also rename the macro since it is now more generic

 rsvg_internals/src/property_macros.rs | 68 ++++++++++++++++++++++++++++++++---
 rsvg_internals/src/state.rs           | 15 +++++---
 2 files changed, 73 insertions(+), 10 deletions(-)
---
diff --git a/rsvg_internals/src/property_macros.rs b/rsvg_internals/src/property_macros.rs
index 1bead060..a1d8197f 100644
--- a/rsvg_internals/src/property_macros.rs
+++ b/rsvg_internals/src/property_macros.rs
@@ -3,14 +3,14 @@ pub trait Property {
 }
 
 /// Generates a property definition that simply parses strings to enum variants
+/// or to a tuple struct of the given type.
 ///
-/// This can be used for properties with simple symbol-based values.
 /// For example, the SVG spec defines the `stroke-linejoin` property
 /// to have possible values `miter | round | bevel | inherit`, with a default
 /// of `miter`.  We can define the property like this:
 ///
 /// ```
-/// make_ident_property!(
+/// make_property!(
 /// StrokeLinejoin,
 /// default: Miter,
 ///
@@ -26,10 +26,11 @@ pub trait Property {
 /// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, where
 /// `type Data = ()` and `type Err = AttributeError`.
 #[macro_export]
-macro_rules! make_ident_property {
+macro_rules! make_property {
     ($name: ident,
      default: $default: ident,
      inherits_automatically: $inherits_automatically: expr,
+     identifiers:
      $($str_prop: expr => $variant: ident,)+
     ) => {
         #[derive(Debug, Copy, Clone, PartialEq)]
@@ -62,6 +63,41 @@ macro_rules! make_ident_property {
             }
         }
     };
+
+    ($name: ident,
+     default: $default: expr,
+     inherits_automatically: $inherits_automatically: expr,
+     newtype: $type: ty
+    ) => {
+        #[derive(Debug, Clone, PartialEq)]
+        pub struct $name(pub $type);
+
+        impl Default for $name {
+            fn default() -> $name {
+                $name($default)
+            }
+        }
+
+        impl ::property_macros::Property for $name {
+            fn inherits_automatically() -> bool {
+                $inherits_automatically
+            }
+        }
+
+        impl ::parsers::Parse for $name {
+            type Data = ();
+            type Err = ::error::AttributeError;
+
+            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
+                match s.trim().parse() {
+                    Ok(val) => Ok($name(val)),
+
+                    // FIXME: should this convert the string::ParseError into AttributeError?
+                    _ => Err(::error::AttributeError::from(::parsers::ParseError::new("invalid value"))),
+                }
+            }
+        }
+    };
 }
 
 #[cfg(test)]
@@ -72,11 +108,12 @@ mod tests {
 
     #[test]
     fn check_generated_property() {
-        make_ident_property! {
+        make_property! {
             Foo,
             default: Def,
             inherits_automatically: true,
 
+            identifiers:
             "def" => Def,
             "bar" => Bar,
             "baz" => Baz,
@@ -84,8 +121,29 @@ mod tests {
 
         assert_eq!(<Foo as Default>::default(), Foo::Def);
         assert_eq!(<Foo as Property>::inherits_automatically(), true);
-
         assert!(<Foo as Parse>::parse("blargh", ()).is_err());
         assert_eq!(<Foo as Parse>::parse("bar", ()), Ok(Foo::Bar));
+
+        make_property! {
+            Bar,
+            default: "bar".to_string(),
+            inherits_automatically: true,
+            newtype: String
+        }
+
+        assert_eq!(<Bar as Default>::default(), Bar("bar".to_string()));
+        assert_eq!(<Bar as Property>::inherits_automatically(), true);
+        assert_eq!(<Bar as Parse>::parse("test", ()), Ok(Bar("test".to_string())));
+
+        make_property! {
+            Baz,
+            default: 42f64,
+            inherits_automatically: true,
+            newtype: f64
+        }
+
+        assert_eq!(<Baz as Default>::default(), Baz(42f64));
+        assert_eq!(<Baz as Property>::inherits_automatically(), true);
+        assert_eq!(<Baz as Parse>::parse("42", ()), Ok(Baz(42f64)));
     }
 }
diff --git a/rsvg_internals/src/state.rs b/rsvg_internals/src/state.rs
index 777c8fe7..04125032 100644
--- a/rsvg_internals/src/state.rs
+++ b/rsvg_internals/src/state.rs
@@ -380,22 +380,24 @@ pub fn get_state_rust<'a>(state: *const RsvgState) -> &'a mut State {
 
 // FillRule ----------------------------------------
 
-make_ident_property!(
+make_property!(
     FillRule,
     default: NonZero,
     inherits_automatically: true,
 
+    identifiers:
     "nonzero" => NonZero,
     "evenodd" => EvenOdd,
 );
 
 // StrokeLinecap ----------------------------------------
 
-make_ident_property!(
+make_property!(
     StrokeLinecap,
     default: Butt,
     inherits_automatically: true,
 
+    identifiers:
     "butt" => Butt,
     "round" => Round,
     "square" => Square,
@@ -403,11 +405,12 @@ make_ident_property!(
 
 // StrokeLineJoin ----------------------------------------
 
-make_ident_property!(
+make_property!(
     StrokeLinejoin,
     default: Miter,
     inherits_automatically: true,
 
+    identifiers:
     "miter" => Miter,
     "round" => Round,
     "bevel" => Bevel,
@@ -415,11 +418,12 @@ make_ident_property!(
 
 // TextAnchor --------------------------------------
 
-make_ident_property!(
+make_property!(
     TextAnchor,
     default: Start,
     inherits_automatically: true,
 
+    identifiers:
     "start" => Start,
     "middle" => Middle,
     "end" => End,
@@ -427,11 +431,12 @@ make_ident_property!(
 
 // XmlSpace ----------------------------------------
 
-make_ident_property!(
+make_property!(
     XmlSpace,
     default: Default,
     inherits_automatically: true,
 
+    identifiers:
     "default" => Default,
     "preserve" => Preserve,
 );


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]