macro_rules! make_properties {
    {
        shorthands: {
            $($short_str:tt => ( $short_presentation_attr:expr, $short_field:ident: $short_name:ident ),)*
        }

        longhands: {
            $($long_str:tt => ( $long_presentation_attr:expr, $long_field:ident: $long_name:ident ),)+
        }

        // These are for when expanded_name!("" "foo") is not defined yet
        // in markup5ever.  We create an ExpandedName by hand in that case.
        longhands_not_supported_by_markup5ever: {
            $($long_m5e_str:tt => ($long_m5e_presentation_attr:expr, $long_m5e_field:ident: $long_m5e_name:ident ),)+
        }

        non_properties: {
            $($nonprop_field:ident: $nonprop_name:ident,)+
        }
    } => { ... };
}
Expand description

Macro to generate all the machinery for properties.

This generates the following:

  • PropertyId, an fieldless enum with simple values to identify all the properties.
  • ParsedProperty, a variant enum for all the specified property values.
  • ComputedValue, a variant enum for all the computed values.
  • parse_value, the main function to parse a property or attribute value from user input.

There is a lot of repetitive code, for example, because sometimes we need to operate on PropertyId::Foo, ParsedProperty::Foo and ComputedValue::Foo together. This is why all this is done with a macro.

See the only invocation of this macro to see how it is used; it is just a declarative list of property names.

NOTE: If you get a compiler error similar to this:

362 |         "mix-blend-mode"              => mix_blend_mode              : MixBlendMode,
    |         ^^^^^^^^^^^^^^^^ no rules expected this token in macro call

Then it may be that you put the name inside the longhands block, when it should be inside the longhands_not_supported_by_markup5ever block. This is because the markup5ever crate does not have predefined names for every single property out there; just the common ones.