to_shmem_derive/
util.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use darling::{FromDeriveInput, FromField};
6use proc_macro2::{Span, TokenStream};
7use quote::{quote, TokenStreamExt};
8use syn::{self, parse_quote, DeriveInput, Field, Ident, WherePredicate};
9use synstructure::{self, BindStyle, BindingInfo, VariantInfo};
10
11pub(crate) fn parse_input_attrs<A>(input: &DeriveInput) -> A
12where
13    A: FromDeriveInput,
14{
15    match A::from_derive_input(input) {
16        Ok(attrs) => attrs,
17        Err(e) => panic!("failed to parse input attributes: {}", e),
18    }
19}
20
21pub(crate) fn parse_field_attrs<A>(field: &Field) -> A
22where
23    A: FromField,
24{
25    match A::from_field(field) {
26        Ok(attrs) => attrs,
27        Err(e) => panic!("failed to parse field attributes: {}", e),
28    }
29}
30
31pub(crate) fn add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate) {
32    where_clause
33        .get_or_insert(parse_quote!(where))
34        .predicates
35        .push(pred);
36}
37
38pub(crate) fn fmap2_match<F, G>(
39    input: &DeriveInput,
40    bind_style: BindStyle,
41    mut f: F,
42    mut g: G,
43) -> TokenStream
44where
45    F: FnMut(&BindingInfo) -> TokenStream,
46    G: FnMut(&BindingInfo) -> Option<TokenStream>,
47{
48    let mut s = synstructure::Structure::new(input);
49    s.variants_mut().iter_mut().for_each(|v| {
50        v.bind_with(|_| bind_style);
51    });
52    s.each_variant(|variant| {
53        let (mapped, mapped_fields) = value(variant, "mapped");
54        let fields_pairs = variant.bindings().iter().zip(mapped_fields.iter());
55        let mut computations = quote!();
56        computations.append_all(fields_pairs.map(|(field, mapped_field)| {
57            let expr = f(field);
58            quote! { let #mapped_field = #expr; }
59        }));
60        computations.append_all(
61            mapped_fields
62                .iter()
63                .map(|mapped_field| match g(mapped_field) {
64                    Some(expr) => quote! { let #mapped_field = #expr; },
65                    None => quote!(),
66                }),
67        );
68        computations.append_all(mapped);
69        Some(computations)
70    })
71}
72
73fn value<'a>(variant: &'a VariantInfo, prefix: &str) -> (TokenStream, Vec<BindingInfo<'a>>) {
74    let mut v = variant.clone();
75    v.bindings_mut().iter_mut().for_each(|b| {
76        b.binding = Ident::new(&format!("{}_{}", b.binding, prefix), Span::call_site())
77    });
78    v.bind_with(|_| BindStyle::Move);
79    (v.pat(), v.bindings().to_vec())
80}