Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  to_computed_value.rs   Sprache: unbekannt

 
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

/* 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 crate::cg;
use proc_macro2::TokenStream;
use syn::{DeriveInput, Ident, Path};
use synstructure::{BindStyle, BindingInfo};

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.
    mut binding_attrs: impl FnMut(&BindingInfo) -> ToValueAttrs,
    // 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 {
    let name = &input.ident;

    let mut where_clause = input.generics.where_clause.take();
    cg::propagate_clauses_to_output_type(
        &mut where_clause,
        &input.generics,
        &trait_path,
        &output_type_name,
    );

    let moves = match bind_style {
        BindStyle::Move | BindStyle::MoveMut => true,
        BindStyle::Ref | BindStyle::RefMut => false,
    };

    let params = input.generics.type_params().collect::<Vec<_>>();
    for param in ¶ms {
        cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path));
    }

    let computed_value_type = cg::fmap_trait_output(&input, &trait_path, &output_type_name);

    let mut add_field_bound = |binding: &BindingInfo| {
        let ty = &binding.ast().ty;

        let output_type = cg::map_type_params(
            ty,
            ¶ms,
            &computed_value_type,
            &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",
                );
                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);
            assert!(
                !attrs.no_field_bound,
                "It doesn't make sense on a generic implementation"
            );
            if attrs.field_bound {
                add_field_bound(&binding);
            }
            call_to(&binding)
        });

        let from_body = cg::fmap_match(&input, bind_style, |binding| call_from(&binding));

        let self_ = if moves {
            quote! { self }
        } else {
            quote! { *self }
        };
        let from_ = if moves {
            quote! { from }
        } else {
            quote! { *from }
        };

        let to_body = quote! {
            match #self_ {
                #to_body
            }
        };

        let from_body = quote! {
            match #from_ {
                #from_body
            }
        };

        (to_body, from_body)
    };

    input.generics.where_clause = where_clause;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let impl_ = trait_impl(from_body, to_body);

    quote! {
        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! {
             #[inline]
             fn from_computed_value(from: &Self::ComputedValue) -> Self {
                 #from_body
             }

             #[allow(unused_variables)]
             #[inline]
             fn to_computed_value(&self, context: &crate::values::computed::Context) -> Self::ComputedValue {
                 #to_body
             }
        }
    };

    derive_to_value(
        input,
        parse_quote!(crate::values::computed::ToComputedValue),
        parse_quote!(ComputedValue),
        BindStyle::Ref,
        |binding| {
            let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
            ToValueAttrs {
                field_bound: attrs.field_bound,
                no_field_bound: attrs.no_field_bound,
            }
        },
        |binding| quote!(crate::values::computed::ToComputedValue::from_computed_value(#binding)),
        |binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)),
        trait_impl,
    )
}

#[derive(Default)]
pub struct ToValueAttrs {
    pub field_bound: bool,
    pub no_field_bound: bool,
}

#[derive(Default, FromField)]
#[darling(attributes(compute), default)]
struct ComputedValueAttrs {
    field_bound: bool,
    no_field_bound: bool,
}

[ Dauer der Verarbeitung: 0.47 Sekunden  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge