1use proc_macro::TokenStream;
8
9use proc_macro2::TokenStream as TokenStream2;
10use quote::quote;
11use syn::{self, DeriveInput};
12
13mod context;
14
15#[proc_macro_derive(Patchable, attributes(patchable))]
16pub fn derive_patchable(input: TokenStream) -> TokenStream {
17 derive_with(input, |ctx| {
18 let patch_struct_def = ctx.build_patch_struct();
19 let patchable_trait_impl = ctx.build_patchable_trait_impl();
20 let from_struct_impl = cfg!(feature = "impl_from").then(|| {
21 let from_struct_impl = ctx.build_from_trait_impl();
22 quote! {
23 #[automatically_derived]
24 #from_struct_impl
25 }
26 });
27
28 quote! {
29 const _: () = {
30 #[automatically_derived]
31 #patch_struct_def
32 #[automatically_derived]
33 #patchable_trait_impl
34 #from_struct_impl
35 };
36 }
37 })
38}
39
40#[proc_macro_derive(Patch, attributes(patchable))]
41pub fn derive_patch(input: TokenStream) -> TokenStream {
42 derive_with(input, |ctx| {
43 let patch_trait_impl = ctx.build_patch_trait_impl();
44
45 quote! {
46 const _: () = {
47 #[automatically_derived]
48 #patch_trait_impl
49 };
50 }
51 })
52}
53
54fn derive_with<F>(input: TokenStream, f: F) -> TokenStream
55where
56 F: FnOnce(&context::MacroContext) -> TokenStream2,
57{
58 let input: DeriveInput = syn::parse_macro_input!(input as DeriveInput);
59 match context::MacroContext::new(&input) {
60 Ok(ctx) => f(&ctx).into(),
61 Err(e) => e.to_compile_error().into(),
62 }
63}