Derive Macro Partial Implementation

#1

I’m writing a derive macro that implement a trait but I want to leave one method of this trait for user implementation. If the macro not write the method the user receive a compilation error pointing the missing implementation but…

is there a better way to achieve this behaviour?

extern crate proc_macro;
extern crate proxy_interceptors_contracts;

use crate::proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

#[proc_macro_derive(RequestInterceptor)]
pub fn request_interceptor_derive(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    let debug_impl = impl_debug(&input);
    let request_impl = impl_request_interceptor(&input);

    let tokens = quote! {
        #debug_impl
        #request_impl
    };

    tokens.into()
}

fn impl_debug(ast: &syn::DeriveInput) -> impl quote::ToTokens {
    let struct_name = &ast.ident;
    quote! {
        impl std::fmt::Debug for #struct_name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "Request {}", stringify!(#struct_name))
            }
        }
    }
}

fn impl_request_interceptor(ast: &syn::DeriveInput) -> impl quote::ToTokens {
    let struct_name = &ast.ident;
    quote! {
        impl proxy_interceptors_contracts::request::RequestInterceptor for #struct_name {}

        impl proxy_interceptors_contracts::common::Interceptor<proxy_interceptors_contracts::request::Request> for #struct_name {
            /*
            fn exec(&self, request: &mut proxy_interceptors_contracts::request::Request) {}
            */
        }
    }
}

The commented exec function is the one I want to leave for the macro user.

0 Likes

#2

You have to implement an entire trait at once. In this case, I’d probably make two traits:

trait UserImpl {
    // user-defined methods go here
}

trait DeriveImpl: UserImpl {
    // derived methods go here
}

#[derive(DeriveImpl)]
struct MyStruct;

impl UserImpl for MyStruct {
    // ...
}
1 Like