2017-05-21 16:48:10 +03:00
|
|
|
/* 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
|
2018-12-02 21:46:06 +03:00
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
2017-05-21 16:48:10 +03:00
|
|
|
|
2019-03-30 03:16:01 +03:00
|
|
|
use derive_common::cg;
|
2019-04-09 12:37:26 +03:00
|
|
|
use proc_macro2::TokenStream;
|
|
|
|
use syn::{DeriveInput, Ident, Path};
|
|
|
|
use synstructure::{BindStyle, BindingInfo};
|
2017-05-21 16:48:10 +03:00
|
|
|
|
2019-04-09 12:37:26 +03:00
|
|
|
pub fn derive_to_value(
|
|
|
|
mut input: DeriveInput,
|
|
|
|
trait_path: Path,
|
|
|
|
output_type_name: Ident,
|
|
|
|
bind_style: BindStyle,
|
|
|
|
// Returns whether to apply the field bound for a given item.
|
2020-03-26 16:04:20 +03:00
|
|
|
mut binding_attrs: impl FnMut(&BindingInfo) -> ToValueAttrs,
|
2019-04-09 12:37:26 +03:00
|
|
|
// Returns a token stream of the form: trait_path::from_foo(#binding)
|
|
|
|
mut call_from: impl FnMut(&BindingInfo) -> TokenStream,
|
|
|
|
mut call_to: impl FnMut(&BindingInfo) -> TokenStream,
|
|
|
|
// Returns a tokenstream of the form:
|
|
|
|
// fn from_function_syntax(foobar) -> Baz {
|
|
|
|
// #first_arg
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// fn to_function_syntax(foobar) -> Baz {
|
|
|
|
// #second_arg
|
|
|
|
// }
|
|
|
|
mut trait_impl: impl FnMut(TokenStream, TokenStream) -> TokenStream,
|
|
|
|
) -> TokenStream {
|
2019-04-09 04:48:18 +03:00
|
|
|
let name = &input.ident;
|
|
|
|
|
2018-03-10 01:29:05 +03:00
|
|
|
let mut where_clause = input.generics.where_clause.take();
|
2019-03-03 14:31:21 +03:00
|
|
|
cg::propagate_clauses_to_output_type(
|
|
|
|
&mut where_clause,
|
|
|
|
&input.generics,
|
2019-04-09 12:37:26 +03:00
|
|
|
&trait_path,
|
|
|
|
&output_type_name,
|
2019-03-03 14:31:21 +03:00
|
|
|
);
|
2018-03-10 01:29:05 +03:00
|
|
|
|
2020-03-26 16:04:20 +03:00
|
|
|
let moves = match bind_style {
|
|
|
|
BindStyle::Move | BindStyle::MoveMut => true,
|
|
|
|
BindStyle::Ref | BindStyle::RefMut => false,
|
|
|
|
};
|
2018-03-10 01:29:05 +03:00
|
|
|
|
2020-03-26 16:04:20 +03:00
|
|
|
let params = input.generics.type_params().collect::<Vec<_>>();
|
|
|
|
for param in ¶ms {
|
|
|
|
cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path));
|
|
|
|
}
|
2018-03-10 01:29:05 +03:00
|
|
|
|
Bug 1653339 - Teach style_derive's map_type_params about mapping self correctly. r=boris
Consider the following:
struct Complex<T> {
something: T,
#[compute(field_bound)]
something_else: Generic<Self, T>,
}
That will generate:
impl<T> ToComputedValue for Complex<T>
where
T: ToComputedValue,
Generic<Self, T>: ToComputedValue<ComputedValue = Generic<Self, <T as ToComputedValue>::ComputedValue>>,
{
// ...
}
That last clause is obviously incorrect. map_type_params correctly maps
the T, but it should know also about Self.
Ideally we could just do the same as for T and do:
<Self as ToComputedValue>::ComputedValue
But that doesn't quite work, because we are in that implementation of
the trait, and the compiler rightfully complains about we don't yet
knowing the computed type. So we need to pass it explicitly, which is
simple enough, if a bit annoying.
Differential Revision: https://phabricator.services.mozilla.com/D83816
2020-07-16 21:51:21 +03:00
|
|
|
let computed_value_type = cg::fmap_trait_output(&input, &trait_path, &output_type_name);
|
|
|
|
|
2020-03-26 16:04:20 +03:00
|
|
|
let mut add_field_bound = |binding: &BindingInfo| {
|
|
|
|
let ty = &binding.ast().ty;
|
|
|
|
|
|
|
|
let output_type = cg::map_type_params(
|
|
|
|
ty,
|
|
|
|
¶ms,
|
Bug 1653339 - Teach style_derive's map_type_params about mapping self correctly. r=boris
Consider the following:
struct Complex<T> {
something: T,
#[compute(field_bound)]
something_else: Generic<Self, T>,
}
That will generate:
impl<T> ToComputedValue for Complex<T>
where
T: ToComputedValue,
Generic<Self, T>: ToComputedValue<ComputedValue = Generic<Self, <T as ToComputedValue>::ComputedValue>>,
{
// ...
}
That last clause is obviously incorrect. map_type_params correctly maps
the T, but it should know also about Self.
Ideally we could just do the same as for T and do:
<Self as ToComputedValue>::ComputedValue
But that doesn't quite work, because we are in that implementation of
the trait, and the compiler rightfully complains about we don't yet
knowing the computed type. So we need to pass it explicitly, which is
simple enough, if a bit annoying.
Differential Revision: https://phabricator.services.mozilla.com/D83816
2020-07-16 21:51:21 +03:00
|
|
|
&computed_value_type,
|
2020-03-26 16:04:20 +03:00
|
|
|
&mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name),
|
|
|
|
);
|
|
|
|
|
|
|
|
cg::add_predicate(
|
|
|
|
&mut where_clause,
|
|
|
|
parse_quote!(
|
|
|
|
#ty: #trait_path<#output_type_name = #output_type>
|
|
|
|
),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
let (to_body, from_body) = if params.is_empty() {
|
|
|
|
let mut s = synstructure::Structure::new(&input);
|
|
|
|
s.variants_mut().iter_mut().for_each(|v| {
|
|
|
|
v.bind_with(|_| bind_style);
|
|
|
|
});
|
|
|
|
|
|
|
|
for variant in s.variants() {
|
|
|
|
for binding in variant.bindings() {
|
|
|
|
let attrs = binding_attrs(&binding);
|
|
|
|
assert!(
|
|
|
|
!attrs.field_bound,
|
|
|
|
"It is default on a non-generic implementation",
|
2018-03-10 01:29:05 +03:00
|
|
|
);
|
2020-03-26 16:04:20 +03:00
|
|
|
if !attrs.no_field_bound {
|
|
|
|
// Add field bounds to all bindings except the manually
|
|
|
|
// excluded. This ensures the correctness of the clone() /
|
|
|
|
// move based implementation.
|
|
|
|
add_field_bound(binding);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let to_body = if moves {
|
|
|
|
quote! { self }
|
|
|
|
} else {
|
|
|
|
quote! { std::clone::Clone::clone(self) }
|
|
|
|
};
|
|
|
|
|
|
|
|
let from_body = if moves {
|
|
|
|
quote! { from }
|
|
|
|
} else {
|
|
|
|
quote! { std::clone::Clone::clone(from) }
|
|
|
|
};
|
|
|
|
|
|
|
|
(to_body, from_body)
|
|
|
|
} else {
|
|
|
|
let to_body = cg::fmap_match(&input, bind_style, |binding| {
|
|
|
|
let attrs = binding_attrs(&binding);
|
2020-04-16 18:01:24 +03:00
|
|
|
assert!(
|
|
|
|
!attrs.no_field_bound,
|
|
|
|
"It doesn't make sense on a generic implementation"
|
|
|
|
);
|
2020-03-26 16:04:20 +03:00
|
|
|
if attrs.field_bound {
|
|
|
|
add_field_bound(&binding);
|
2018-03-10 01:29:05 +03:00
|
|
|
}
|
2019-04-09 12:37:26 +03:00
|
|
|
call_to(&binding)
|
2018-03-10 01:29:05 +03:00
|
|
|
});
|
2020-03-26 16:04:20 +03:00
|
|
|
|
2019-04-11 23:12:41 +03:00
|
|
|
let from_body = cg::fmap_match(&input, bind_style, |binding| call_from(&binding));
|
2018-03-10 01:29:05 +03:00
|
|
|
|
2020-04-16 18:01:24 +03:00
|
|
|
let self_ = if moves {
|
|
|
|
quote! { self }
|
|
|
|
} else {
|
|
|
|
quote! { *self }
|
|
|
|
};
|
|
|
|
let from_ = if moves {
|
|
|
|
quote! { from }
|
|
|
|
} else {
|
|
|
|
quote! { *from }
|
|
|
|
};
|
2020-03-26 16:04:20 +03:00
|
|
|
|
|
|
|
let to_body = quote! {
|
|
|
|
match #self_ {
|
|
|
|
#to_body
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let from_body = quote! {
|
|
|
|
match #from_ {
|
|
|
|
#from_body
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-03-10 01:29:05 +03:00
|
|
|
(to_body, from_body)
|
|
|
|
};
|
|
|
|
|
|
|
|
input.generics.where_clause = where_clause;
|
|
|
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
2017-05-21 16:48:10 +03:00
|
|
|
|
2019-04-09 12:37:26 +03:00
|
|
|
let impl_ = trait_impl(from_body, to_body);
|
|
|
|
|
2017-05-21 16:48:10 +03:00
|
|
|
quote! {
|
2019-04-09 12:37:26 +03:00
|
|
|
impl #impl_generics #trait_path for #name #ty_generics #where_clause {
|
|
|
|
type #output_type_name = #computed_value_type;
|
|
|
|
|
|
|
|
#impl_
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn derive(input: DeriveInput) -> TokenStream {
|
|
|
|
let trait_impl = |from_body, to_body| {
|
|
|
|
quote! {
|
2019-04-11 23:12:41 +03:00
|
|
|
#[inline]
|
2020-03-26 16:04:20 +03:00
|
|
|
fn from_computed_value(from: &Self::ComputedValue) -> Self {
|
|
|
|
#from_body
|
2019-04-11 23:12:41 +03:00
|
|
|
}
|
2017-05-21 16:48:10 +03:00
|
|
|
|
2019-04-11 23:12:41 +03:00
|
|
|
#[allow(unused_variables)]
|
|
|
|
#[inline]
|
|
|
|
fn to_computed_value(&self, context: &crate::values::computed::Context) -> Self::ComputedValue {
|
2020-03-26 16:04:20 +03:00
|
|
|
#to_body
|
2019-04-11 23:12:41 +03:00
|
|
|
}
|
|
|
|
}
|
2019-04-09 12:37:26 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
derive_to_value(
|
|
|
|
input,
|
|
|
|
parse_quote!(crate::values::computed::ToComputedValue),
|
|
|
|
parse_quote!(ComputedValue),
|
|
|
|
BindStyle::Ref,
|
2020-03-26 16:04:20 +03:00
|
|
|
|binding| {
|
|
|
|
let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
|
|
|
|
ToValueAttrs {
|
|
|
|
field_bound: attrs.field_bound,
|
|
|
|
no_field_bound: attrs.no_field_bound,
|
|
|
|
}
|
|
|
|
},
|
2019-04-09 12:37:26 +03:00
|
|
|
|binding| quote!(crate::values::computed::ToComputedValue::from_computed_value(#binding)),
|
|
|
|
|binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)),
|
|
|
|
trait_impl,
|
|
|
|
)
|
2017-05-21 16:48:10 +03:00
|
|
|
}
|
2017-08-28 18:13:13 +03:00
|
|
|
|
2020-03-26 16:04:20 +03:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct ToValueAttrs {
|
|
|
|
pub field_bound: bool,
|
|
|
|
pub no_field_bound: bool,
|
|
|
|
}
|
|
|
|
|
2017-08-28 18:13:13 +03:00
|
|
|
#[darling(attributes(compute), default)]
|
|
|
|
#[derive(Default, FromField)]
|
|
|
|
struct ComputedValueAttrs {
|
2018-03-10 01:29:05 +03:00
|
|
|
field_bound: bool,
|
2020-03-26 16:04:20 +03:00
|
|
|
no_field_bound: bool,
|
2017-08-28 18:13:13 +03:00
|
|
|
}
|