Skip to content
Permalink
Browse files

style: Add derive code for a new ToResolvedValue trait, and a few tri…

…vial implementations.

Differential Revision: https://phabricator.services.mozilla.com/D26782
  • Loading branch information...
emilio committed Apr 10, 2019
1 parent 9b66f45 commit 6ac777ebf22e2d619f5ffe7a253b27b7d104ccf4
Showing with 277 additions and 0 deletions.
  1. +208 −0 components/style/values/resolved/mod.rs
  2. +69 −0 components/style_derive/to_resolved_value.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)
}
}
@@ -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,
}

0 comments on commit 6ac777e

Please sign in to comment.
You can’t perform that action at this time.