Last active
August 22, 2022 13:33
-
-
Save sahandevs/125344a08ed97cda1091f384769a3e2f to your computer and use it in GitHub Desktop.
proc_macro_demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [package] | |
| name = "proc_macro_demo_1" | |
| version = "0.1.0" | |
| edition = "2021" | |
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
| [lib] | |
| proc-macro = true | |
| [dependencies] | |
| walkdir = "2" | |
| syn = { version = "*", features = ["full"] } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use proc_macro_demo_1::add_describe; | |
| fn main() { | |
| let a = MyStruct { a: 0, b: String::new() }; | |
| a.describe(); // a: 0, b: "" | |
| } | |
| struct MyStruct { | |
| pub a: u32, | |
| pub b: String, | |
| } | |
| add_describe!(MyStruct); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use proc_macro::TokenStream; | |
| use walkdir::WalkDir; | |
| #[proc_macro] | |
| pub fn add_describe(input: TokenStream) -> TokenStream { | |
| let struct_name = input.to_string(); | |
| let current_dir = std::env::current_dir().unwrap(); | |
| let src_dir = current_dir.join("src"); | |
| let mut fields = Vec::new(); | |
| 'outer: for item in WalkDir::new(src_dir) { | |
| let item = item.unwrap(); | |
| if item | |
| .file_name() | |
| .to_str() | |
| .unwrap_or_default() | |
| .ends_with(".rs") | |
| { | |
| let content = std::fs::read_to_string(item.path()).unwrap(); | |
| let result = syn::parse_str::<syn::File>(&content).unwrap(); | |
| for item in result.items { | |
| match item { | |
| syn::Item::Struct(x) => { | |
| if x.ident.to_string() == struct_name { | |
| fields.extend(x.fields.into_iter()); | |
| break 'outer; | |
| } | |
| } | |
| _ => {} | |
| } | |
| } | |
| } | |
| } | |
| if fields.is_empty() { | |
| panic!("undefined struct {}", struct_name) | |
| }; | |
| /* | |
| struct MyStruct { | |
| a: u32, | |
| b: String, | |
| } | |
| impl MyStruct { | |
| pub fn describe(&self) { | |
| let mut result = String::from("MyStruct:"); | |
| result.push_str("\ta:u32"); | |
| result.push_str("\tb:String"); | |
| println!("{}", result); | |
| } | |
| } | |
| */ | |
| let mut describe_inner = String::new(); | |
| describe_inner.push_str(&format!( | |
| "let mut result = String::from(\"{}:\\n\");", | |
| struct_name | |
| )); | |
| for field in fields { | |
| let ty = match field.ty { | |
| syn::Type::Path(x) => x | |
| .path | |
| .segments | |
| .iter() | |
| .map(|x| x.ident.to_string()) | |
| .collect::<Vec<_>>() | |
| .join("::"), | |
| _ => todo!(), | |
| }; | |
| describe_inner.push_str(&format!( | |
| "result.push_str(\"\\t{}:{}\\n\");", | |
| field.ident.unwrap().to_string(), | |
| ty | |
| )); | |
| } | |
| let result = format!( | |
| r#" | |
| impl {} {{ | |
| pub fn describe(&self) {{ | |
| {} | |
| println!("{{}}", result); | |
| }} | |
| }} | |
| "#, | |
| struct_name, describe_inner | |
| ); | |
| let result: TokenStream = result.parse().unwrap(); | |
| result | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment