Bug 1542178 - Add derive code for a new ToResolvedValue trait, and a few trivial implementations. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 10 Apr 2019 12:10:11 +0000
changeset 468797 b8e84c48c6720e03b24170671b502ec306939bf3
parent 468796 f38ce082341e1631132dfcac799bca6cce8380f3
child 468798 79752758fc82bda5a89bd3a3860fc20aea10d72f
push id112755
push userdvarga@mozilla.com
push dateWed, 10 Apr 2019 22:06:41 +0000
treeherdermozilla-inbound@606f85641d0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1542178
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1542178 - Add derive code for a new ToResolvedValue trait, and a few trivial implementations. r=heycam Differential Revision: https://phabricator.services.mozilla.com/D26782
servo/components/style/values/resolved/mod.rs
servo/components/style_derive/to_resolved_value.rs
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/resolved/mod.rs
@@ -0,0 +1,208 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! Resolved values. These are almost always computed values, but in some cases
+//! there are used values.
+
+use cssparser;
+use smallvec::SmallVec;
+use crate::properties::ComputedValues;
+use crate::values::computed;
+
+/// Information needed to resolve a given value.
+pub struct Context<'a> {
+    /// The style we're resolving for. This is useful to resolve currentColor.
+    pub style: &'a ComputedValues,
+    // TODO(emilio): Add layout box information, and maybe property-specific
+    // information?
+}
+
+/// A trait to represent the conversion between resolved and resolved values.
+///
+/// This trait is derivable with `#[derive(ToResolvedValue)]`.
+///
+/// The deriving code assumes that if the type isn't generic, then the trait can
+/// be implemented as simple move. This means that a manual implementation with
+/// `ResolvedValue = Self` is bogus if it returns anything else than a clone.
+pub trait ToResolvedValue {
+    /// The resolved value type we're going to be converted to.
+    type ResolvedValue;
+
+    /// Convert a resolved value to a resolved value.
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue;
+
+    /// Convert a resolved value to resolved value form.
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self;
+}
+
+macro_rules! trivial_to_resolved_value {
+    ($ty:ty) => {
+        impl $crate::values::resolved::ToResolvedValue for $ty {
+            type ResolvedValue = Self;
+
+            #[inline]
+            fn to_resolved_value(self, _: &Context) -> Self {
+                self
+            }
+
+            #[inline]
+            fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+                resolved
+            }
+        }
+    };
+}
+
+trivial_to_resolved_value!(());
+trivial_to_resolved_value!(bool);
+trivial_to_resolved_value!(f32);
+trivial_to_resolved_value!(i32);
+trivial_to_resolved_value!(u8);
+trivial_to_resolved_value!(i8);
+trivial_to_resolved_value!(u16);
+trivial_to_resolved_value!(u32);
+#[cfg(feature = "servo")]
+trivial_to_resolved_value!(Prefix);
+trivial_to_resolved_value!(String);
+trivial_to_resolved_value!(Box<str>);
+trivial_to_resolved_value!(cssparser::RGBA);
+trivial_to_resolved_value!(crate::Atom);
+trivial_to_resolved_value!(app_units::Au);
+trivial_to_resolved_value!(computed::url::ComputedUrl);
+trivial_to_resolved_value!(computed::url::ComputedImageUrl);
+
+impl<A, B> ToResolvedValue for (A, B)
+where
+    A: ToResolvedValue,
+    B: ToResolvedValue,
+{
+    type ResolvedValue = (
+        <A as ToResolvedValue>::ResolvedValue,
+        <B as ToResolvedValue>::ResolvedValue,
+    );
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        (
+            self.0.to_resolved_value(context),
+            self.1.to_resolved_value(context),
+        )
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        (
+            A::from_resolved_value(resolved.0),
+            B::from_resolved_value(resolved.1),
+        )
+    }
+}
+
+impl<T> ToResolvedValue for Option<T>
+where
+    T: ToResolvedValue,
+{
+    type ResolvedValue = Option<<T as ToResolvedValue>::ResolvedValue>;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        self.map(|item| item.to_resolved_value(context))
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        resolved.map(T::from_resolved_value)
+    }
+}
+
+impl<T> ToResolvedValue for SmallVec<[T; 1]>
+where
+    T: ToResolvedValue,
+{
+    type ResolvedValue = SmallVec<[<T as ToResolvedValue>::ResolvedValue; 1]>;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        self.into_iter()
+            .map(|item| item.to_resolved_value(context))
+            .collect()
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        resolved.into_iter().map(T::from_resolved_value).collect()
+    }
+}
+
+impl<T> ToResolvedValue for Vec<T>
+where
+    T: ToResolvedValue,
+{
+    type ResolvedValue = Vec<<T as ToResolvedValue>::ResolvedValue>;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        self.into_iter()
+            .map(|item| item.to_resolved_value(context))
+            .collect()
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        resolved.into_iter().map(T::from_resolved_value).collect()
+    }
+}
+
+impl<T> ToResolvedValue for Box<T>
+where
+    T: ToResolvedValue,
+{
+    type ResolvedValue = Box<<T as ToResolvedValue>::ResolvedValue>;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        Box::new(T::to_resolved_value(*self, context))
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        Box::new(T::from_resolved_value(*resolved))
+    }
+}
+
+impl<T> ToResolvedValue for Box<[T]>
+where
+    T: ToResolvedValue,
+{
+    type ResolvedValue = Box<[<T as ToResolvedValue>::ResolvedValue]>;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        Vec::from(self).to_resolved_value(context).into_boxed_slice()
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        Vec::from_resolved_value(Vec::from(resolved)).into_boxed_slice()
+    }
+}
+
+
+/// A resolved color value is an rgba color, with currentcolor resolved.
+pub type Color = cssparser::RGBA;
+
+impl ToResolvedValue for computed::Color {
+    type ResolvedValue = Color;
+
+    #[inline]
+    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+        context.style.resolve_color(self)
+    }
+
+    #[inline]
+    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+        use crate::values::generics::color::Color as GenericColor;
+        GenericColor::Numeric(resolved)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/style_derive/to_resolved_value.rs
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use derive_common::cg;
+use proc_macro2::TokenStream;
+use syn::DeriveInput;
+use synstructure::BindStyle;
+use to_computed_value;
+
+pub fn derive(input: DeriveInput) -> TokenStream {
+    let trait_impl = |from_body, to_body| {
+        quote! {
+            #[inline]
+            fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+                match resolved {
+                    #from_body
+                }
+            }
+
+            #[inline]
+            fn to_resolved_value(
+                self,
+                context: &crate::values::resolved::Context,
+            ) -> Self::ResolvedValue {
+                match self {
+                    #to_body
+                }
+            }
+       }
+    };
+
+    let non_generic_implementation = || {
+        Some(quote! {
+            type ResolvedValue = Self;
+
+            #[inline]
+            fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+                resolved
+            }
+
+            #[inline]
+            fn to_resolved_value(
+                self,
+                context: &crate::values::resolved::Context,
+            ) -> Self {
+                self
+            }
+        })
+    };
+
+    to_computed_value::derive_to_value(
+        input,
+        parse_quote!(crate::values::resolved::ToResolvedValue),
+        parse_quote!(ResolvedValue),
+        BindStyle::Move,
+        |binding| cg::parse_field_attrs::<ResolvedValueAttrs>(&binding.ast()).field_bound,
+        |binding| quote!(crate::values::resolved::ToResolvedValue::from_resolved_value(#binding)),
+        |binding| quote!(crate::values::resolved::ToResolvedValue::to_resolved_value(#binding, context)),
+        trait_impl,
+        non_generic_implementation,
+    )
+}
+
+#[darling(attributes(resolve), default)]
+#[derive(Default, FromField)]
+struct ResolvedValueAttrs {
+    field_bound: bool,
+}