Skip to main content

patchable_macro/
lib.rs

1//! # Patchable Macro
2//!
3//! Procedural macros for the `patchable` crate: `Patchable` and `Patch` derives.
4//!
5//! See `context` for details about the generated patch struct and trait implementations.
6
7use 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}