diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 78c3865b999..a865c20a598 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -17,9 +17,10 @@ use custom_properties::CustomPropertiesBuilder; use servo_arc::{Arc, UniqueArc}; use smallbitvec::SmallBitVec; use std::borrow::Cow; -use std::{mem, ops}; +use std::{ops, ptr}; use std::cell::RefCell; use std::fmt::{self, Write}; +use std::mem::{self, ManuallyDrop}; #[cfg(feature = "servo")] use cssparser::RGBA; use cssparser::{CowRcStr, Parser, TokenSerializationType, serialize_identifier}; @@ -1441,28 +1442,94 @@ impl PropertyId { } } -/// Servo's representation for a property declaration. -#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, PartialEq)] -pub enum PropertyDeclaration { - % for property in data.longhands: - <% +<% + variants = [] + for property in data.longhands: if property.predefined_type and not property.is_vector and not property.is_gecko_size_type_hack: ty = "::values::specified::{}".format(property.predefined_type) else: ty = "longhands::{}::SpecifiedValue".format(property.ident) if property.boxed: ty = "Box<{}>".format(ty) - %> - /// ${property.name} - ${property.camel_case}(${ty}), + variants.append({ + "name": property.camel_case, + "type": ty, + "doc": "`" + property.name + "`", + }) + variants += [ + { + "name": "CSSWideKeyword", + "type": "WideKeywordDeclaration", + "doc": "A CSS-wide keyword.", + }, + { + "name": "WithVariables", + "type": "VariableDeclaration", + "doc": "An unparsed declaration.", + }, + { + "name": "Custom", + "type": "CustomDeclaration", + "doc": "A custom property declaration.", + }, + ] +%> + +/// Servo's representation for a property declaration. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] +#[derive(PartialEq)] +#[repr(u16)] +pub enum PropertyDeclaration { + % for variant in variants: + /// ${variant["doc"]} + ${variant["name"]}(${variant["type"]}), % endfor - /// A css-wide keyword. - CSSWideKeyword(WideKeywordDeclaration), - /// An unparsed declaration. - WithVariables(VariableDeclaration), - /// A custom property declaration. - Custom(CustomDeclaration), +} + +<% + from itertools import groupby + + groups = {} + keyfunc = lambda x: x["type"] + for ty, group in groupby(sorted(variants, key=keyfunc), keyfunc): + groups[ty] = list(group) +%> + +impl Clone for PropertyDeclaration { + #[inline] + fn clone(&self) -> Self { + use self::PropertyDeclaration::*; + + #[repr(C)] + struct VariantRepr { + tag: u16, + value: T + } + + match *self { + % for ty, variants in groups.iteritems(): + % if len(variants) == 1: + ${variants[0]["name"]}(ref value) => { + ${variants[0]["name"]}(value.clone()) + } + % else: + ${" | ".join("{}(ref value)".format(v["name"]) for v in variants)} => { + unsafe { + let mut out = ManuallyDrop::new(mem::uninitialized()); + ptr::write( + &mut out as *mut _ as *mut VariantRepr<${ty}>, + VariantRepr { + tag: *(self as *const _ as *const u16), + value: value.clone(), + }, + ); + ManuallyDrop::into_inner(out) + } + } + % endif + % endfor + } + } } /// A declaration using a CSS-wide keyword.