Procedural macros in Rust allow developers to extend the language and automate code generation. They are often used to create custom derive attributes or other annotations that modify or add to Rust's functionality.
In this challenge, you'll implement a procedural macro to derive a custom trait called Describe. The Describe trait should provide a method, describe, that returns a string containing the name of the struct and its fields with their values. This macro should generate an implementation of the trait automatically when applied to a struct.
Your task is to create a procedural macro named derive_describe that can be used to generate the Describe trait implementation for any struct. The generated describe method should return a string representation of the struct, including its name and all its fields with their respective values.
For example, applying the macro to a struct like:
#[derive(Describe)]
struct Point {
x: i32,
y: i32,
}Should generate a Describe implementation such that:
let p = Point { x: 1, y: 2 };
assert_eq!(p.describe(), "Point { x: 1, y: 2 }");The derive_describe macro should:
Describe trait implementation for the struct it is applied to.The describe method should return a properly formatted string, including the struct name and fields with their values.
Procedural macros must be defined in a separate crate from the one where they are used. This is because procedural macros are compiled to a shared library that is loaded by the Rust compiler at compile time. The shared library must be compiled before the crate that uses the macro.
In your Cargo.toml, you should define a new crate for the procedural macro:
[lib]
proc-macro = trueThis is already done for this challenge, but it's important to understand the setup.
syn crate to parse the input TokenStream into an Abstract Syntax Tree (AST).quote crate to generate Rust code as a TokenStream.use proc_macro::TokenStream;use syn::{parse_macro_input, DeriveInput, Data};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast = syn::parse_macro_input!(input as syn::DeriveInput); let name = &ast.ident; let fields = match &ast.data { syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(fields), .. }) => &fields.named, _ => { return syn::Error::new_spanned( &ast, "Describe only supports structs with named fields" ) .to_compile_error() .into(); } }; let field_descriptions: Vec<_> = fields .iter() .map(|f| { let field_name = &f.ident; let field_name_ident = field_name.as_ref().unwrap(); quote::quote! { format!("{}: {:?}", stringify!(#field_name_ident), self.#field_name_ident) } }) .collect(); let expanded = quote::quote! { impl Describe for #name { fn describe(&self) -> String { let fields: Vec<String> = vec![ #(#field_descriptions),* ]; format!("{} {{ {} }}", stringify!(#name), fields.join(", ")) } } }; TokenStream::from(expanded)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{Data, DeriveInput, Fields, parse_macro_input};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; let fields = match &ast.data { Data::Struct(r#struct) => match &r#struct.fields { Fields::Named(field) => &field.named, _ => panic!("Describe only supports named fields"), }, _ => panic!("Describe only supports structs"), }; let field_identifier = fields.iter().map(|field| field.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#name)) #( .field(stringify!(#field_identifier), &self.#field_identifier) )* .finish() } } impl Describe for #name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let dinput = parse_macro_input!(input as DeriveInput); let name = &dinput.ident; let formatted_fields = match &dinput.data { Data::Struct(data_struct) => match &data_struct.fields { Fields::Named(fields) => { let idents: Vec<_> = fields.named.iter().map(|f| { let field_name = &f.ident.as_ref().unwrap() ; let field_name_str = field_name.to_string(); quote! { format!("{}: {:?}", #field_name_str, &self.#field_name) } }).collect::<Vec<_>>(); idents }, Fields::Unnamed(_) => Vec::new(), Fields::Unit => Vec::new(), } &Data::Enum(_) | &Data::Union(_) => unimplemented!() }; let description = quote!( format!("{} {{ {} }}", stringify!(#name), [#(#formatted_fields),*].join(", ") ) ); let expanded = quote! { impl Describe for #name { fn describe(&self) -> String{ #description } } }; expanded.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; let fields = match &ast.data { Data::Struct(r#struct) => match &r#struct.fields { Fields::Named(field) => &field.named, _ => panic!("Describe only supports named fields"), }, _ => panic!("Describe only supports structs"), }; let field_identifier = fields.iter().map(|field| field.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#name)) #( .field(stringify!(#field_identifier), &self.#field_identifier) )* .finish() } } impl Describe for #name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data, Fields, FieldsNamed};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; if let Data::Struct(data_struct) = &input.data { if let Fields::Named(FieldsNamed { named, .. }) = &data_struct.fields { let field_names = named.iter().map(|f| &f.ident); let field_accessors = named.iter().map(|f| &f.ident); return quote! { impl Describe for #name { fn describe(&self) -> String { format!("{} {{ {} }}", stringify!(#name), [#(format!("{}: {:?}", stringify!(#field_names), self.#field_accessors)), *].join(", ") ) } } }.into(); } } quote! { impl Describe for #name { fn describe(&self) -> String { format!("{} {{ ... }}", stringify!(#name)) } } }.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DataStruct, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; let fields = match &ast.data { syn::Data::Struct(DataStruct { struct_token: _, fields: Fields::Named(field), semi_token: _, }) => &field.named, _ => panic!("Only for structs"), }; let fields = fields.iter().map(|field| field.ident.as_ref().unwrap()); let generated = quote! { impl std::fmt::Display for #name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#name)) #( .field(stringify!(#fields), &self.#fields) )* .finish() } } impl Describe for #name { fn describe(&self) -> String { format!("{}", &self) } } }; generated.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{ parse_macro_input, Data::Struct as DataStruct, DeriveInput, Fields::Named as NamedFields,};#[proc_macro_derive(Describe)]pub fn derive_describe(raw_input: TokenStream) -> TokenStream { let input = parse_macro_input!(raw_input as DeriveInput); let fields = match input.data { DataStruct(data_struct) => match data_struct.fields { NamedFields(field_names) => field_names.named, _ => panic!("only named fields"), }, _ => panic!("only structs with named fields"), }; let field_idents: Vec<_> = fields .iter() .map(|field| field.ident.as_ref().unwrap()) .collect(); let parts = field_idents .iter() .map(|field| format!("{}: {{:?}}", field)) .collect::<Vec<_>>() .join(", "); let ident = input.ident; let expanded = quote! { impl Describe for #ident { fn describe(&self) -> String { format!( concat!(stringify!(#ident), " {{ ", #parts, " }}"), #( self.#field_idents, )* ) } } }; expanded.into()}use proc_macro::TokenStream;use quote::quote;use syn::{self, parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // 1. Parse the input code into a syntax tree let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; // 2. Extract the field names from the struct let fields = match &ast.data { Data::Struct(s) => match &s.fields { Fields::Named(fields) => &fields.named, _ => panic!("This macro only works on structs with named fields."), }, _ => panic!("This macro only works on structs."), }; // Create an iterator for the field identifiers (e.g., `name`, `age`) let field_idents = fields.iter().map(|f| &f.ident); // 3. Generate the trait implementation using `quote!` let gen = quote! { // This is the code that will be generated for the user's struct impl Describe for #name { fn describe(&self) -> ::std::string::String { // Create a vector of "key: value" strings for each field let fields_str = ::std::vec![ // This is the "repetition" part of the macro. // It will run the format!() for each field identifier. #( ::std::format!( "{}: {:?}", ::core::stringify!(#field_idents), // Turns the field name into a string "name" self.#field_idents // Accesses the field's value, e.g., self.name ) ),* ]; // Join all the parts into the final string: "StructName { ... }" ::std::format!("{} {{ {} }}", ::core::stringify!(#name), fields_str.join(", ")) } } }; gen.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // Parse the input tokens into a syntax tree let ast: DeriveInput = parse(input).unwrap(); let fields = match &ast.data { Data::Struct(data_struct) => match &data_struct.fields { Fields::Named(fields_named) => &fields_named.named, _ => panic!("Only named fields supported"), }, _ => panic!("Only structs supported"), }; // Generate the impl let name = &ast.ident; let field_descriptions = fields.iter().map(|f| { let field_name = f.ident.as_ref().unwrap(); quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }); let expanded = quote! { impl Describe for #name { fn describe(&self) -> String { let descriptions = vec![#(#field_descriptions),*]; format!("{} {{ {} }}", stringify!(#name), descriptions.join(", ")) } } }; // Return as TokenStream TokenStream::from(expanded)}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let input_data = parse_macro_input!(input as DeriveInput); let name = input_data.ident; let fields = match input_data.data { syn::Data::Struct(data_struct) => match data_struct.fields { syn::Fields::Named(fields_named) => fields_named.named, _ => panic!("Only named fields"), }, _ => panic!("Only struct with named fields"), }; let field_names: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect(); let field_string: Vec<_> = field_names.iter().map(|ident| ident.to_string()).collect(); let parts = field_string.iter() .map(|field| format!("{}: {{:?}}", field)) .collect::<Vec<_>>() .join(", "); let expanded = quote! { impl Describe for #name { fn describe(&self) -> String { format!( concat!(stringify!(#name), " {{ ", #parts, " }}"), #( self.#field_names, )* ) } } }; expanded.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenStream;use quote::quote;use syn;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let description = match &ast.data { syn::Data::Struct(data_struct) => { let fields = data_struct.fields.iter().map(|f| { let field_name = &f.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }); quote!{ format!("{} {{ {} }}", stringify!(#name), vec![#(#fields),*].join(", ")) } }, _ => unimplemented!(), }; let gens = quote! { impl #name { pub fn describe(&self) -> String { #description } } }; gens.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenStream;use quote::quote;use syn;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let description = match &ast.data { syn::Data::Struct(data_struct) => { let fields = data_struct.fields.iter().map(|f| { let field_name = &f.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }); quote! { format!("{} {{ {} }}", stringify!(#name), vec![#(#fields),*].join(", ")) } } _ => unimplemented!(), }; let gens = quote! { impl #name { pub fn describe(&self) -> String { #description } } }; gens.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenStream;use quote::quote;use syn;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let description = match &ast.data { syn::Data::Struct(data_struct) => { let fields = data_struct.fields.iter().map(|f| { let field_name = &f.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }); quote! { format!("{} {{ {} }}", stringify!(#name), vec![#(#fields),*].join(", ")) } } _ => unimplemented!(), }; let gens = quote! { impl #name { pub fn describe(&self) -> String { #description } } }; gens.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenStream;use quote::quote;use syn::parse;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast: syn::DeriveInput = parse(input).unwrap(); let name = &ast.ident; let description = match &ast.data { syn::Data::Struct(s) => { let fields = s.fields.iter().map(|f| { let field_name = &f.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }); quote! { format!("{} {{ {} }}", stringify!(#name), vec![#(#fields),*].join(", ")) } } _ => unimplemented!(), }; let code = quote! { impl #name { pub fn describe(&self) -> String { #description } } }; code.into()}// Example Test// #[test]// fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }// let person = Person {// name: "Alice".to_string(),// age: 30,// };// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");// }use proc_macro::TokenStream;use quote::quote;use syn;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let rewrite = match &ast.data { syn::Data::Struct(data) => { let fields = data.fields.iter().map(|f| { let name2 = &f.ident; quote! { format!("{}: {:?}", stringify!(#name2), self.#name2) } }); quote! { format!("{} {{ {} }}", stringify!(#name), vec![#(#fields),*].join(", ")) } } _ => unimplemented!(), }; let code = quote! { impl #name { pub fn describe(&self) -> String { #rewrite } } }; code.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}// src/lib.rs (proc-macro crate)use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Error, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let ident = input.ident; let generics = input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); // Only named-field structs let field_idents: Vec<_> = match &input.data { Data::Struct(ds) => match &ds.fields { Fields::Named(named) => named .named .iter() .map(|f| f.ident.as_ref().unwrap().clone()) .collect(), _ => { let err = Error::new_spanned(&ident, "Describe only supports structs with named fields"); return TokenStream::from(err.to_compile_error()); } }, _ => { let err = Error::new_spanned(&ident, "Describe can only be derived for structs"); return TokenStream::from(err.to_compile_error()); } }; // Generate: pieces like `format!("name: {:?}", &self.name)` then join with ", " let pieces = field_idents.iter().map(|fid| { quote! { ::std::format!(concat!(stringify!(#fid), ": {:?}"), &self.#fid) } }); let expanded = quote! { impl #impl_generics Describe for #ident #ty_generics #where_clause { fn describe(&self) -> ::std::string::String { let parts: ::std::vec::Vec<::std::string::String> = ::std::vec![ #(#pieces),* ]; let mut s = ::std::string::String::from(stringify!(#ident)); s.push_str(" {"); if !parts.is_empty() { s.push(' '); s.push_str(&parts.join(", ")); s.push(' '); } s.push('}'); s } } }; TokenStream::from(expanded)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let struct_name = input.ident; // Only proceed if the struct has named fields let fields = if let Data::Struct(data_struct) = input.data { if let Fields::Named(named_fields) = data_struct.fields { named_fields.named } else { return TokenStream::new(); // Ignore non-named fields } } else { return TokenStream::new(); // Ignore non-struct data }; let field_names = fields.iter().map(|f| f.ident.as_ref().unwrap()); let field_names_as_strings = field_names.clone().map(|name| name.to_string()); let generated = quote! { impl Describe for #struct_name { fn describe(&self) -> String { let fields: Vec<String> = vec![ #(format!("{}: {:?}", #field_names_as_strings, self.#field_names)),* ]; format!("{} {{ {} }}", stringify!(#struct_name), fields.join(", ")) } } }; generated.into()}// Example Test// #[test]// fn test_example() {// #[derive(Describe)]// pub struct Person {// pub name: String,// pub age: u32,// }// let person = Person {// name: "Alice".to_string(),// age: 30,// };// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");// }use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let fields = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Named(ref fields_named) => &fields_named.named, _ => panic!("Describe only supports named fields"), }, _ => panic!("Describe only supports structs"), }; let field_prints = fields.iter().map(|f| { let field_name = f.ident.as_ref().unwrap().to_string(); let value = f.ident.as_ref().unwrap(); quote! { format!("{}: {:?}", #field_name, &self.#value) } }); let expanded = quote!{ impl Describe for #name { fn describe(&self) -> String { let info = vec![#(#field_prints),*].join(", "); format!("{} {{ {} }}", stringify!(#name), info) } } }; TokenStream::from(expanded)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); let name = &input.ident; let fields = match &input.data { syn::Data::Struct(data) => &data.fields, _ => panic!("Describe can only be derived for structs"), }; let field_names: Vec<_> = fields.iter().map(|f| &f.ident).collect(); let field_idents: Vec<_> = fields.iter().map(|f| &f.ident).collect(); let expanded = quote! { impl Describe for #name { fn describe(&self) -> String { let fields = vec![ #( (stringify!(#field_names), format!("{:?}", self.#field_idents)) ),* ]; let field_str = fields .iter() .map(|(name, value)| format!("{}: {}", name, value)) .collect::<Vec<_>>() .join(", "); format!("{} {{ {} }}", stringify!(#name), field_str) } } }; TokenStream::from(expanded)}use proc_macro::TokenStream;use syn::{parse_macro_input, Data, Fields, DeriveInput};use quote::quote;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_name = &ast.ident; let fields = match &ast.data { Data::Struct(data) => match &data.fields{ Fields::Named(fields) => &fields.named, _ => panic!("This macro is only for structs with named fields"), }, _ => panic!("This macro is only for structs"), }; let (format_parts, field_names): (Vec<_>, Vec<_>) = fields.iter().map(|f| { let name = f.ident.as_ref().unwrap(); let format_part = format!("{}: {{:?}}", name); (format_part, name) }).unzip(); let fields_format = format_parts.join(", "); let out = quote! { impl Describe for #struct_name { fn describe(&self)-> String { format!( "{} {{ {} }}", stringify!(#struct_name), format!(#fields_format, #(&self.#field_names),*) ) } } }; out.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use syn::{parse_macro_input, Data, Fields, DeriveInput};use quote::quote;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_name = &ast.ident; let fields = match &ast.data { Data::Struct(data) => match &data.fields{ Fields::Named(fields) => &fields.named, _ => panic!("This macro is only for structs with named fields"), }, _ => panic!("This macro is only for structs"), }; let (format_parts, field_names): (Vec<_>, Vec<_>) = fields.iter().map(|f| { let name = f.ident.as_ref().unwrap(); let format_part = format!("{}: {{:?}}", name); (format_part, name) }).unzip(); let fields_format = format_parts.join(", "); let out = quote! { impl Describe for #struct_name { fn describe(&self)-> String { format!( "{} {{ {} }}", stringify!(#struct_name), format!(#fields_format, #(&self.#field_names),*) ) } } }; out.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_name = &ast.ident; let fields = match &ast.data { Data::Struct(r#struct) => match &r#struct.fields { Fields::Named(field) => &field.named, _ => panic!("This macro is only for structs with named fields"), }, _ => panic!("This macro is only for structs"), }; let field_identifier = fields.iter().map(|field| field.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #( .field(stringify!(#field_identifier), &self.#field_identifier) )* .finish() } } impl Describe for #struct_name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data};#[proc_macro_derive(Describe, attributes(describe_value))]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = ast.ident; let field_descriptions = if let syn::Data::Struct(data_struct) = &ast.data { data_struct.fields.iter().map(|field| { let field_name = field.ident.as_ref().unwrap(); quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }).collect::<Vec<_>>() } else { Vec::new() }; let expanded = quote! { impl Describe for #name { fn describe(&self) -> String { let field_descriptions = vec![ #(#field_descriptions),* ]; format!("{} {{ {} }}", stringify!(#name), field_descriptions.join(", ")) } } }; TokenStream::from(expanded)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data};#[proc_macro_derive(Describe, attributes(describe_value))]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = ast.ident; let field_descriptions = if let syn::Data::Struct(data_struct) = &ast.data { data_struct.fields.iter().map(|field| { let field_name = field.ident.as_ref().unwrap(); quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }).collect::<Vec<_>>() } else { Vec::new() }; let expanded = quote! { impl Describe for #name { fn describe(&self) -> String { let field_descriptions = vec![ #(#field_descriptions),* ]; format!("{} {{ {} }}", stringify!(#name), field_descriptions.join(", ")) } } }; TokenStream::from(expanded)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use syn::{parse_macro_input, DeriveInput, Data, Fields};use quote::quote;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_name = &ast.ident; let fields = match &ast.data { Data::Struct(r#struct) => match &r#struct.fields { Fields::Named(field) => &field.named, _ => panic!("Describe only supports named fields"), }, _ => panic!("Describe only supports structs"), }; let field_identifier = fields.iter().map(|field| field.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #( .field(stringify!(#field_identifier), &self.#field_identifier) )* .finish() } } impl Describe for #struct_name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use syn::{parse_macro_input, Data, Fields};use quote::quote;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as syn::DeriveInput); let struct_name = &ast.ident; let fields = match &ast.data { Data::Struct(r#struct) => match &r#struct.fields { Fields::Named(field) => &field.named, _ => panic!("Describe only supports named fields"), }, _ => panic!("Describe only supports structs"), }; let field_identifier = fields.iter().map(|field| field.ident.as_ref().unwrap()); quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #( .field(stringify!(#field_identifier), &self.#field_identifier) )* .finish() } } impl Describe for #struct_name { fn describe(&self) -> String { format!("{:?}", self) } } }.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use quote::quote;use proc_macro::TokenStream;use syn::{Data, Fields, DeriveInput};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast: DeriveInput = syn::parse(input).unwrap(); //parse_macro_input!(input as DeriveInput); let name = &ast.ident; let fields = match &ast.data { Data::Struct(data_struct) => match &data_struct.fields { Fields::Named(fields) => fields.named.iter().map(|f| f.ident.as_ref().unwrap()), _ => panic!("Describe only supports named fields"), }, _ => panic!("Describe only supports structs"), }; let gen = quote! { impl std::fmt::Debug for #name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct(stringify!()) #(.field(stringify!(#fields), &self.#fields))* .finish() } } impl Describe for #name { fn describe(&self) -> String { format!("{}{:?}", stringify!(#name), self) } } }; gen.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input };#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let input = parse_macro_input!(input as syn::DeriveInput); let struct_name = &input.ident; let impl_derive = if let syn::Data::Struct(data) = input.data { if let syn::Fields::Named(fields) = &data.fields { fields.named.iter().map( |field| { let name = &field.ident; quote! { format!("{}: {:?}", stringify!(#name), self.#name) } } ).collect::<Vec<_>>() } else { vec![] } } else { vec![] }; let impl_describe = quote! { impl Describe for #struct_name { fn describe(&self) -> String{ let fields = vec![#(#impl_derive),*]; format!("{} {{ {} }}", stringify!(#struct_name), fields.join(", ")) } } }; impl_describe.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro:: TokenStream;use quote::quote;use syn::{self, DeriveInput, Fields, Data};fn impl_describe_macro(ast: &DeriveInput) -> TokenStream { let name = &ast.ident; let fields_writer = match &ast.data { Data::Struct(data_struct) => match &data_struct.fields { Fields::Named(named_fields) => { let field_writers = named_fields.named.iter().enumerate().map(|(i, f)| { let field_name = f.ident.as_ref().expect("Named field must have a name"); // Add a comma *before* the item if it's not the first one if i > 0 { quote! { write!(&mut s, ", {}: {:?}", stringify!(#field_name), self.#field_name).unwrap(); } } else { quote! { write!(&mut s, "{}: {:?}", stringify!(#field_name), self.#field_name).unwrap(); } } }); quote! { #(#field_writers)* } }, _ => unimplemented!() }, _ => unimplemented!() }; let generated = quote! { impl Describe for #name { fn describe(&self) -> String { use std::fmt::Write; let mut s = String::new(); write!(&mut s, "{} {{ ", stringify!(#name)).unwrap(); #fields_writer write!(&mut s, " }}").unwrap(); s } } }; generated.into()}#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = syn::parse(input).unwrap(); impl_describe_macro(&ast)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenTree::{Ident, Punct};use proc_macro::{TokenStream, TokenTree};// use quote::{format_ident, quote};use quote::format_ident;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let items = input.into_iter().collect::<Vec<_>>(); let struct_name = items.get(1).unwrap(); let struct_name = format_ident!("{}", format!("{}", struct_name)); let members = items.get(2).unwrap(); // panic!("members: {:?}", &members); let members = match members { TokenTree::Group(g) => g.stream().into_iter().collect::<Vec<_>>(), _ => Vec::new(), }; // retrieve description of all members let mut member_names = Vec::new(); for w in members.windows(2) { match (w[0].clone(), w[1].clone()) { (Ident(label), Punct(c)) if c.as_char() == ':' => { member_names.push(format!("{label}")); } _ => continue, } } // panic!("{:?}", member_names); let mut final_string = format!("format!(\"{struct_name} {{{{ "); let addition = member_names .iter() .map(|m| format!("{m}: {{:?}}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push_str(" }}\", "); let addition = member_names .iter() .map(|m| format!("self.{m}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push(')'); // let final_string = format_ident!("{}", final_string); let ret = [ format!("impl Describe for {struct_name} {{"), "fn describe(&self) -> String {".into(), final_string, "}\n}".into(), ] .join("\n"); //panic!("{}", ret.parse::<TokenStream>().unwrap()); ret.parse().unwrap()}extern crate proc_macro;use proc_macro::TokenTree::{Ident, Punct};use proc_macro::{TokenStream, TokenTree};// use quote::{format_ident, quote};use quote::format_ident;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let items = input.into_iter().collect::<Vec<_>>(); let struct_name = items.get(1).unwrap(); let struct_name = format_ident!("{}", format!("{}", struct_name)); let members = items.get(2).unwrap(); // panic!("members: {:?}", &members); let members = match members { TokenTree::Group(g) => g.stream().into_iter().collect::<Vec<_>>(), _ => Vec::new(), }; // retrieve description of all members let mut member_names = Vec::new(); for w in members.windows(2) { match (w[0].clone(), w[1].clone()) { (Ident(label), Punct(c)) if c.as_char() == ':' => { member_names.push(format!("{label}")); } _ => continue, } } // panic!("{:?}", member_names); let mut final_string = format!("format!(\"{struct_name} {{{{ "); let addition = member_names .iter() .map(|m| format!("{m}: {{:?}}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push_str(" }}\", "); let addition = member_names .iter() .map(|m| format!("self.{m}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push(')'); // let final_string = format_ident!("{}", final_string); let ret = [ format!("impl Describe for {struct_name} {{"), "fn describe(&self) -> String {".into(), final_string, "}\n}".into(), ] .join("\n"); //panic!("{}", ret.parse::<TokenStream>().unwrap()); ret.parse().unwrap()}extern crate proc_macro;use proc_macro::TokenTree::{Ident, Punct};use proc_macro::{TokenStream, TokenTree};// use quote::{format_ident, quote};use quote::format_ident;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let items = input.into_iter().collect::<Vec<_>>(); let struct_name = items.get(1).unwrap(); let struct_name = format_ident!("{}", format!("{}", struct_name)); let members = items.get(2).unwrap(); // panic!("members: {:?}", &members); let members = match members { TokenTree::Group(g) => g.stream().into_iter().collect::<Vec<_>>(), _ => Vec::new(), }; // retrieve description of all members let mut member_names = Vec::new(); for w in members.windows(2) { match (w[0].clone(), w[1].clone()) { (Ident(label), Punct(c)) if c.as_char() == ':' => { member_names.push(format!("{label}")); } _ => continue, } } // panic!("{:?}", member_names); let mut final_string = format!("format!(\"{struct_name} {{{{ "); let addition = member_names .iter() .map(|m| format!("{m}: {{:?}}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push_str(" }}\", "); let addition = member_names .iter() .map(|m| format!("self.{m}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push(')'); // let final_string = format_ident!("{}", final_string); let ret = [ format!("impl Describe for {struct_name} {{"), "fn describe(&self) -> String {".into(), final_string, "}\n}".into(), ] .join("\n"); //panic!("{}", ret.parse::<TokenStream>().unwrap()); ret.parse().unwrap()}use proc_macro::TokenStream;use quote::quote;use syn::DeriveInput;trait Describe { fn describe(&self) -> String;}#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast: DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let data = if let syn::Data::Struct(data) = &ast.data { data } else { unimplemented!() }; let fields = &data .fields .iter() .map(|field| { let field_name = &field.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }) .collect::<Vec<_>>(); let generated = quote! { impl Describe for #name { fn describe(&self) -> String { format!("{} {{ {} }}", stringify!(#name), vec![#(#fields),*].join(", ")) } } }; generated.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenTree::{Ident, Punct};use proc_macro::{TokenStream, TokenTree};// use quote::{format_ident, quote};use quote::format_ident;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let items = input.into_iter().collect::<Vec<_>>(); let struct_name = items.get(1).unwrap(); let struct_name = format_ident!("{}", format!("{}", struct_name)); let members = items.get(2).unwrap(); // panic!("members: {:?}", &members); let members = match members { TokenTree::Group(g) => g.stream().into_iter().collect::<Vec<_>>(), _ => Vec::new(), }; // retrieve description of all members let mut member_names = Vec::new(); for w in members.windows(2) { match (w[0].clone(), w[1].clone()) { (Ident(label), Punct(c)) if c.as_char() == ':' => { member_names.push(format!("{label}")); } _ => continue, } } // panic!("{:?}", member_names); let mut final_string = format!("format!(\"{struct_name} {{{{ "); let addition = member_names .iter() .map(|m| format!("{m}: {{:?}}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push_str(" }}\", "); let addition = member_names .iter() .map(|m| format!("self.{m}")) .collect::<Vec<_>>() .join(", "); final_string.push_str(&addition); final_string.push(')'); // let final_string = format_ident!("{}", final_string); let ret = [ format!("impl Describe for {struct_name} {{"), "fn describe(&self) -> String {".into(), final_string, "}\n}".into(), ] .join("\n"); //panic!("{}", ret.parse::<TokenStream>().unwrap()); ret.parse().unwrap()}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data, DataStruct};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_identifier = &ast.ident; match &ast.data { Data::Struct(DataStruct { fields, .. }) => { let mut implementation = quote! { f.debug_struct(stringify!(#struct_identifier)) }; for field in fields { let identifier = field.ident.as_ref().unwrap(); implementation.extend(quote! { .field(stringify!(#identifier), &self.#identifier) }); } implementation.extend(quote! { .finish() }); quote! { impl core::fmt::Debug for #struct_identifier { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { #implementation } } impl Describe for #struct_identifier { fn describe(&self) -> String { format!("{:?}", self) } } } } _ => unimplemented!(), } .into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let struct_name = &input.ident; let debug_fields = if let Data::Struct(data_struct) = &input.data { if let Fields::Named(name_field) = &data_struct.fields { name_field.named.iter().map(|f| { let name = f.ident.as_ref().unwrap(); quote! { .field(stringify!(#name), &self.#name) } }) } else { unimplemented!() } } else { unimplemented!() } .collect::<Vec<_>>(); quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #(#debug_fields)* .finish() } } impl #struct_name { fn describe(&self) -> String { format!("{:?}", &self) } } } .into()}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let derive_input = parse_macro_input!(input as DeriveInput); let struct_name = &derive_input.ident; let fields = match &derive_input.data { Data::Struct(s) => match &s.fields { Fields::Named(f) => &f.named, _ => panic!("Describe only supports structs with named fields."), }, _ => panic!("Describe can only be derived for structs."), }; let field_idents = fields.iter().map(|f| f.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #( .field(stringify!(#field_idents), &self.#field_idents) )* .finish() } } impl Describe for #struct_name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); match &input.data { syn::Data::Struct(data) => match &data.fields { syn::Fields::Named(fields_named) => { let struct_name = &input.ident; let fields_formats = fields_named .named .iter() .map(|f| { let field_name = &f.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }) .collect::<Vec<_>>(); let expanded = quote! { impl Describe for #struct_name { fn describe(&self) -> String { let fields = vec![#(#fields_formats),*]; format!("{} {{ {} }}", stringify!(#struct_name), fields.join(", ")) } } }; TokenStream::from(expanded) } _ => panic!("Only structs with named fields are supported"), }, _ => panic!("Only structs are supported"), }}// Example Test// #[test]// fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }// let person = Person {// name: "Alice".to_string(),// age: 30,// };// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");// }use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let struct_name = &input.ident; let fields = match &input.data { syn::Data::Struct(data_struct) => match &data_struct.fields { syn::Fields::Named(fields_named) => &fields_named.named, _ => panic!("Only strucs with named fields are supported"), }, _ => panic!("Only structs are supported"), }; let field_formats: Vec<_> = fields .iter() .map(|field| { let field_name = &field.ident; quote! { format!("{}: {:?}", stringify!(#field_name), self.#field_name) } }) .collect(); let expanded = quote! { impl Describe for #struct_name { fn describe(&self) -> String { let fields = vec![#(#field_formats),*]; format!("{} {{ {} }}", stringify!(#struct_name), fields.join(", ")) } } }; TokenStream::from(expanded)}// Example Test// #[test]// fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }// let person = Person {// name: "Alice".to_string(),// age: 30,// };// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");// }use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let derive_input = parse_macro_input!(input as DeriveInput); let struct_name = &derive_input.ident; // This part is now correct! let fields = match &derive_input.data { Data::Struct(s) => match &s.fields { Fields::Named(f) => &f.named, _ => panic!("Describe only supports structs with named fields."), }, _ => panic!("Describe can only be derived for structs."), }; let field_idents = fields.iter().map(|f| f.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #( .field(stringify!(#field_idents), &self.#field_idents) )* .finish() } } impl Describe for #struct_name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let derive_input = parse_macro_input!(input as DeriveInput); let struct_name = &derive_input.ident; let struct_name_str = struct_name.to_string(); let fields = match &derive_input.data { Data::Struct(s) => match &s.fields { Fields::Named(f) => &f.named, _ => panic!("Describe only supports structs with named fields."), }, _ => panic!("Describe can only be derived for structs."), }; let field_idents: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect(); let output = quote! { impl Describe for #struct_name { fn describe(&self) -> String { let fields = vec![ #( format!("{}: {:?}", stringify!(#field_idents), self.#field_idents) ),* ]; format!("{} {{ {} }}", #struct_name_str, fields.join(", ")) } } }; output.into()}// Example Test// #[test]// fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }// let person = Person {// name: "Alice".to_string(),// age: 30,// };// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");// }use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let derive_input = parse_macro_input!(input as DeriveInput); let struct_name = &derive_input.ident; let struct_name_str = struct_name.to_string(); let fields = match &derive_input.data { Data::Struct(s) => match &s.fields { Fields::Named(f) => &f.named, _ => panic!("Describe only supports structs with named fields."), }, _ => panic!("Describe can only be derived for structs."), }; let field_idents: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect(); let output = quote! { impl Describe for #struct_name { fn describe(&self) -> String { let fields = vec![ #( format!("{}: {:?}", stringify!(#field_idents), self.#field_idents) ),* ]; format!("{} {{ {} }}", #struct_name_str, fields.join(", ")) } } }; output.into()}// Example Test// #[test]// fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }// let person = Person {// name: "Alice".to_string(),// age: 30,// };// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");// }use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as syn::DeriveInput); let name = &ast.ident; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); let fields = match &ast.data { Data::Struct(s) => &s.fields, _ => { return syn::Error::new_spanned(&ast, "Describe can only be derived for structs") .to_compile_error() .into(); } }; let named_fields = match fields { syn::Fields::Named(fields) => &fields.named, _ => { return syn::Error::new_spanned( fields, "Describe can only derived for structs with named fields", ) .to_compile_error() .into(); } }; let name_str = name.to_string(); let format_specifiers = named_fields.iter().map(|f| { let field_name = f.ident.as_ref().unwrap(); format!("{}: {{:?}}", field_name) }); let full_format_str = format!( "{} {{{{ {} }}}}", name_str, format_specifiers.collect::<Vec<_>>().join(", ") ); println!("{}", full_format_str); let field_accessors = named_fields.iter().map(|f| { let field_name = f.ident.as_ref().unwrap(); quote! { &self.#field_name } }); let expanded = quote! { impl #impl_generics Describe for #name #ty_generics #where_clause { fn describe(&self) -> String { format!( #full_format_str, #( #field_accessors ),* ) } } }; TokenStream::from(expanded)}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput, Fields};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let derive_input = parse_macro_input!(input as DeriveInput); let struct_name = &derive_input.ident; // This part is now correct! let fields = match &derive_input.data { Data::Struct(s) => match &s.fields { Fields::Named(f) => &f.named, _ => panic!("Describe only supports structs with named fields."), }, _ => panic!("Describe can only be derived for structs."), }; let field_idents = fields.iter().map(|f| f.ident.as_ref().unwrap()); let output = quote! { impl std::fmt::Debug for #struct_name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(stringify!(#struct_name)) #( .field(stringify!(#field_idents), &self.#field_idents) )* .finish() } } impl Describe for #struct_name { fn describe(&self) -> String { format!("{:?}", self) } } }; output.into()}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, Data, DeriveInput};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); if let Data::Struct(data) = input.data { let struct_name = &input.ident; let fields = data.fields.members(); let expanded = quote! { impl Describe for #struct_name { fn describe(&self) -> String { let fields = vec![ #(format!("{}: {:?}", stringify!(#fields), self.#fields)),* ].join(", "); format!( "{} {{ {} }}", stringify!(#struct_name), fields ) } } }; TokenStream::from(expanded) } else { panic!("Only Structs are supported.") }}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data, DataStruct};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_identifier = &ast.ident; match &ast.data { Data::Struct(DataStruct { fields, ..}) => { let mut implementation = quote! { f.debug_struct(stringify!(#struct_identifier)) }; for field in fields { let identifier = field.ident.as_ref().unwrap(); implementation.extend(quote! { .field(stringify!(#identifier), &self.#identifier) }); } implementation.extend(quote! { . finish() }); quote! { impl std::fmt::Debug for #struct_identifier { fn fmt(&self, f: &mut core::fmt::Formatter<'_> ) -> core::fmt::Result { #implementation } } impl Describe for #struct_identifier{ fn describe(&self) -> String { format!("{:?}", self) } } } } _ => unimplemented!(), } .into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::Data::Struct;use syn::Fields::{Named, Unit};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let fields: Vec<_> = match ast.data { Struct(my_struct) => { match my_struct.fields { Named(fields) => { fields.named.iter().map(|field| { field.ident.as_ref().unwrap().clone() }).collect() }, _ => unreachable!() } }, _ => unreachable!() }; let generated = quote! { impl Describe for #name { fn describe(&self) -> String { let mut string = String::from(stringify!(#name)); string.push_str(" { "); let mut parts = Vec::new(); #( parts.push(format!("{}: {:?}", stringify!(#fields), &self.#fields)); )* string.push_str(&parts.join(", ")); string.push_str(" }"); string } } }; generated.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let mut inner = quote! { }; match &ast.data { syn::Data::Struct(syn::DataStruct { fields, ..}) => { for field in fields { let identifier = field.ident.as_ref().unwrap(); inner.extend(quote! { format!("{}: {:?}", stringify!(#identifier), &self.#identifier), }); } }, _ => unimplemented!(), } quote! { impl Describe for #name { fn describe(&self) -> String { let v = vec![ #inner ]; format!("{} {{ {} }}", stringify!(#name), v.join(", ")) } } }.into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data, DataStruct};#[proc_macro_derive(Describe)]pub fn derive_describe(input: TokenStream) -> TokenStream { // TODO: Implement the procedural macro here let ast = parse_macro_input!(input as DeriveInput); let struct_identifier = &ast.ident; match &ast.data { Data::Struct(DataStruct { fields, ..}) => { let mut implementation = quote! { f.debug_struct(stringify!(#struct_identifier)) }; for field in fields { let identifier = field.ident.as_ref().unwrap(); implementation.extend(quote! { .field(stringify!(#identifier), &self.#identifier) }); } implementation.extend(quote! { . finish() }); quote! { impl std::fmt::Debug for #struct_identifier { fn fmt(&self, f: &mut core::fmt::Formatter<'_> ) -> core::fmt::Result { #implementation } } impl Describe for #struct_identifier{ fn describe(&self) -> String { format!("{:?}", self) } } } } _ => unimplemented!(), } .into()}// Example Test//#[test]//fn test_example() {// #[derive(Describe)]// struct Person {// name: String,// age: u32,// }//// let person = Person {// name: "Alice".to_string(),// age: 30,// };//// assert_eq!(person.describe(), "Person { name: \"Alice\", age: 30 }");//}extern crate proc_macro;use proc_macro::TokenStream;use quote::quote;use syn::{parse_macro_input, DeriveInput, Data, Fields};#[proc_macro_derive(Describe)]pub fn describe_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; let fields = match &input.data { Data::Struct(data_struct) => match &data_struct.fields { Fields::Named(fields_named) => &fields_named.named, _ => unimplemented!("Only named fields are supported"), }, _ => unimplemented!("Only structs are supported"), }; let field_idents: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect(); let field_names: Vec<_> = field_idents.iter().map(|ident| ident.to_string()).collect(); // Build format parts with commas only between fields, no trailing comma let mut format_parts = Vec::new(); for (i, name) in field_names.iter().enumerate() { if i == field_names.len() - 1 { format_parts.push(format!("{}: {{:?}}", name)); } else { format_parts.push(format!("{}: {{:?}}, ", name)); } } let fields_format = format_parts.concat(); let expanded = quote! { impl #name { pub fn describe(&self) -> String { // Use stringify!(#name) as the struct name string literal, // so it doesn't confuse the formatter format!( "{} {{ {} }}", stringify!(#name), format!(#fields_format, #( &self.#field_idents ),* ) ) } } }; TokenStream::from(expanded)}