title: use Rust proc macros to generate dynamically named struct instance methods
body: <p>I'm trying to write a procedural macro that generates methods for doubling all fields that are <code>f64</code>.  I have it working for a single field with ./src/main.rs</p>
  <pre><code>use attr_macro::DoubleF64;
  
  #[derive(DoubleF64)]
  struct MyStruct {
      my_string: String,
      my_number: f64,
      my_other_number: f64,
  }
  
  
  fn main() {
      let mystruct = MyStruct {
          my_string: &quot;some str&quot;.to_string(),
          my_number: 2.0,
          my_other_number: 2.0,
      };
      println!(&quot;my_number * 2: {}&quot;, mystruct.double_my_number());
  }
  
  </code></pre>
  <p>and ./proc_macro/src/lib.rs:</p>
  <pre><code>extern crate proc_macro;
  use proc_macro::TokenStream;
  use quote::{format_ident, quote};
  use syn::{parse_macro_input, DeriveInput, FieldsNamed};
  
  #[proc_macro_derive(DoubleF64)]
  pub fn double_f64(input: TokenStream) -&gt; TokenStream {
      let DeriveInput { ident, data, .. } = parse_macro_input!(input);
  
      let (func_name, fident) = if let syn::Data::Struct(s) = data {
          if let syn::Fields::Named(FieldsNamed { named, .. }) = s.fields {
              let f = named[1].ident.clone().unwrap();
              (format_ident!(&quot;double_{}&quot;, f), f)
          } else {
              (format_ident!(&quot;&quot;), format_ident!(&quot;&quot;))
          }
      } else {
          (format_ident!(&quot;&quot;), format_ident!(&quot;&quot;))
      };
  
      let output = quote! {
          impl #ident {
              // func_str.parse.unwrap();
              // fn double_f64(&amp;self) -&gt; f64 {
              //     self.my_number * 2.
              // }
              fn #func_name(&amp;self) -&gt; f64 { self.#fident * 2. }
          }
      };
  
      output.into()
  }
  </code></pre>
  <p>but I'm struggling to figure out how to construct a loop that generates a valid <code>TokenStream</code> to extend this to all the fields.  Here's what I've tried:</p>
  <pre><code>#[proc_macro_derive(DoubleF64)]
  pub fn double_f64(input: TokenStream) -&gt; TokenStream {
      let DeriveInput { ident, data, .. } = parse_macro_input!(input);
  
      let mut func_stream_vec: Vec&lt;TokenStream&gt; = Vec::new();
  
      if let syn::Data::Struct(s) = data {
          if let syn::Fields::Named(FieldsNamed { named, .. }) = s.fields {
              let fields = named.iter().map(|f| &amp;f.ident);
              let ftypes = named.iter().map(|f| &amp;f.ty);
  
              for (field, ftype) in fields.into_iter().zip(ftypes) {
                  if stringify!(#ftype) == &quot;f64&quot; {
                      let fname = format_ident!(&quot;double_{}&quot;, field.clone().unwrap());
                      func_stream_vec
                          .push(quote! { fn #fname(&amp;self) -&gt; f64 { self.#field * 2.0 } }.into());
                  }
              }
          }
      };
  
      let output = quote! {
          impl #ident {
              #(#func_stream_vec)*
          }
      };
  
      output.into()
  }
  </code></pre>