How to add a function to a module with a macro [SOLVED]

Hello,

Can someone help me to complete this code to add a new function via a macro to an existing module ?

here is a purified version of the Macro code :

extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote};
use syn::{parse_macro_input};


#[proc_macro_attribute]
pub fn my_macro(
    _attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let input = parse_macro_input!(item as syn::ItemMod);

   // here, the magic code to add the new function to the module :D (which I am still looking for)

    let code = quote!(
          #input
    );

    TokenStream::from(code)
}

Should I use this method ? :
input.content.insert( XXXXX )

I searched a lot but I could not find an example showing how to do it for a module with syn and quote!

Here is a simplified example of how this macro will be used :


#[my_macro()]
pub mod service {
    pub fn function_a() {
    }

    pub fn function_b() {
    }


}

the macro must add a new function to the module, to give this result :


#[my_macro()]
pub mod service {
    pub fn function_a() {
    }

    pub fn function_b() {
    }


    pub fn added_function() {   // <-------------------------------------------
    }

}

thank you in advance for your help.

I don't know the complexity of your proc-macro, but you could use the quote! macro to create the function and just interpolate it into the TokenStream you return:

#[proc_macro_attribute]
pub fn my_macro(
    _attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let input = parse_macro_input!(item as syn::ItemMod);

    // here, the magic code to add the new function to the module :D (which I am still looking for)
    let function = quote!( ... );

    let code = quote!(
          #input
          #function
    );

    TokenStream::from(code)
}

I tried that too, it only creates the function outside the module, but not inside,
it gives this result :

#[my_macro()]
pub mod service {
    pub fn function_a() {
    }

    pub fn function_b() {
    }
}

    pub fn added_function() {   //  out of module !!!
    }

Ah yes of course. Then you could probably push the function as a TokenStream onto the vector inside the content field of your ItemMod input. Something like this, I reckon:

#[proc_macro_attribute]
pub fn my_macro(
    _attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let mut input = parse_macro_input!(item as syn::ItemMod);

    // here, the magic code to add the new function to the module :D (which I am still looking for)
    let function = quote!( ... );
    
    input.content.as_mut().unwrap().1.push(syn::Item::Verbatim(function));

    let code = quote!(
          #input
    );

    TokenStream::from(code)
}

I don't know that method, do you have a reference for me? It may be easier than what I did in the snippet above.

1 Like

I tried your proposal, it works perfectly, thank you very much for your precious help

input.content.insert( XXXXX )

for the insert method of "content", here is the signature :
fn insert(&mut self, value: (Brace, Vec<Item, Global>)) -> &mut (Brace, Vec<Item, Global>)

(I think that insert modify the internal value of the Option<>)

I didn't know how to use it. but your proposal works perfectly :+1:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.