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
This commit is contained in:
Emilio Cobos Álvarez 2019-04-10 12:10:11 +00:00
parent 2facc8da36
commit 9a6b6a33d0
2 changed files with 277 additions and 0 deletions

View File

@ -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)
}
}

View File

@ -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,
}