fieldwork/
lib.rs

1#![forbid(unsafe_code, future_incompatible)]
2#![deny(
3    missing_debug_implementations,
4    nonstandard_style,
5    missing_copy_implementations,
6    unused_qualifications,
7    missing_docs,
8    rustdoc::missing_crate_level_docs
9)]
10#![warn(clippy::pedantic)]
11#![doc = include_str!("../docs.md")]
12
13use proc_macro::TokenStream;
14use proc_macro2::TokenStream as TokenStream2;
15use quote::quote;
16
17mod common_settings;
18mod copy_detection;
19mod deref_handling;
20mod errors;
21mod field;
22mod field_attributes;
23mod field_method_attributes;
24mod method;
25mod option_handling;
26mod query;
27mod resolved;
28mod r#struct;
29mod struct_attributes;
30mod struct_method_attributes;
31
32#[cfg(test)]
33mod coverage_tests;
34
35pub(crate) use common_settings::{CommonSettings, with_common_settings};
36pub(crate) use field::Field;
37pub(crate) use field_attributes::FieldAttributes;
38pub(crate) use field_method_attributes::FieldMethodAttributes;
39pub(crate) use method::{Method, MethodSettings, with_methods};
40pub(crate) use query::Query;
41pub(crate) use resolved::Resolved;
42pub(crate) use r#struct::Struct;
43pub(crate) use struct_attributes::StructAttributes;
44pub(crate) use struct_method_attributes::StructMethodAttributes;
45use syn::Attribute;
46
47/// see crate-level documentation
48#[proc_macro_derive(Fieldwork, attributes(fieldwork, field))]
49pub fn derive_fieldwork(input: TokenStream) -> TokenStream {
50    derive_fieldwork_internal(input.into()).into()
51}
52fn derive_fieldwork_internal(input: TokenStream2) -> TokenStream2 {
53    let Struct {
54        ident,
55        fields,
56        attributes,
57        generics,
58    } = match syn::parse2(input) {
59        Ok(ok) => ok,
60        Err(e) => return e.to_compile_error(),
61    };
62
63    let impls = fields
64        .iter()
65        .flat_map(|field| {
66            Method::all()
67                .iter()
68                .filter_map(|method| Query::new(method, field, &attributes).resolve())
69        })
70        .map(|resolved| resolved.build())
71        .collect::<TokenStream2>();
72
73    let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
74    quote! {
75        impl #impl_generics #ident #type_generics #where_clause {
76            #impls
77        }
78    }
79}
80
81pub(crate) fn is_fieldwork_attr(attr: &Attribute) -> bool {
82    let path = attr.path();
83    path.is_ident("fieldwork") || path.is_ident("field")
84}