From 9a6b6a33d045e5fdbeed8448a7462b3d12548d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 10 Apr 2019 12:10:11 +0000 Subject: [PATCH] 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 | 208 ++++++++++++++++++ .../style_derive/to_resolved_value.rs | 69 ++++++ 2 files changed, 277 insertions(+) create mode 100644 servo/components/style/values/resolved/mod.rs create mode 100644 servo/components/style_derive/to_resolved_value.rs diff --git a/servo/components/style/values/resolved/mod.rs b/servo/components/style/values/resolved/mod.rs new file mode 100644 index 000000000000..8d5aa2211575 --- /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); +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 ToResolvedValue for (A, B) +where + A: ToResolvedValue, + B: ToResolvedValue, +{ + type ResolvedValue = ( + ::ResolvedValue, + ::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 ToResolvedValue for Option +where + T: ToResolvedValue, +{ + type ResolvedValue = Option<::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 ToResolvedValue for SmallVec<[T; 1]> +where + T: ToResolvedValue, +{ + type ResolvedValue = SmallVec<[::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 ToResolvedValue for Vec +where + T: ToResolvedValue, +{ + type ResolvedValue = Vec<::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 ToResolvedValue for Box +where + T: ToResolvedValue, +{ + type ResolvedValue = Box<::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 ToResolvedValue for Box<[T]> +where + T: ToResolvedValue, +{ + type ResolvedValue = Box<[::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) + } +} diff --git a/servo/components/style_derive/to_resolved_value.rs b/servo/components/style_derive/to_resolved_value.rs new file mode 100644 index 000000000000..70d3f71876fe --- /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::(&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, +}