mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
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:
parent
2facc8da36
commit
9a6b6a33d0
208
servo/components/style/values/resolved/mod.rs
Normal file
208
servo/components/style/values/resolved/mod.rs
Normal 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)
|
||||
}
|
||||
}
|
69
servo/components/style_derive/to_resolved_value.rs
Normal file
69
servo/components/style_derive/to_resolved_value.rs
Normal 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,
|
||||
}
|
Loading…
Reference in New Issue
Block a user