1use std::{
3 fs::File,
4 path::{Path, PathBuf},
5};
6
7use bon::builder;
8use proc_macro2::{Span, TokenStream};
9use quote::{quote, ToTokens};
10use syn::Ident;
11pub fn calling_crate_dir() -> &'static Path {
15 let out_dir = Path::new(env!("OUT_DIR"));
17 let calling_crate_dir = out_dir
19 .parent()
20 .expect("Failed to get parent of out directory")
21 .parent()
22 .unwrap()
23 .parent()
24 .unwrap()
25 .parent()
26 .unwrap()
27 .parent()
28 .unwrap();
29 calling_crate_dir
30}
31
32#[builder]
34pub fn folder_iso_struct(
35 name: &str,
36 pre: &TokenStream,
37 folder: &str,
38 from_crate: &str,
40 #[builder(default = false)] log_enabled: bool,
41) {
42 use build_print::*;
43 use stringcase::*;
44 macro_rules! log {
45 ($($arg:tt)+) => {
46 if log_enabled {
47 custom_println!("folder_iso_struct", green, $($arg)+)
48 }
49 };
50 }
51
52 let ccd = calling_crate_dir();
53 let mods_folder_path = ccd.join(from_crate).join("src").join(folder);
54 let paths = std::fs::read_dir(mods_folder_path).unwrap();
55 let struct_mod_folder_id = parse_id_maybe_raw(folder);
56 let fields = paths
57 .into_iter()
58 .filter(|path| {
59 let module_path = path.as_ref().unwrap().path();
60 let struct_folder_file_stem = module_path.file_stem().unwrap().to_str().unwrap();
61 struct_folder_file_stem != "mod"
62 })
63 .map(|path| {
64 let module_path = path.unwrap().path();
65 let struct_folder_file_stem = module_path.file_stem().unwrap().to_str().unwrap();
66 let opts = stringcase::Options {
67 separate_before_non_alphabets: true,
68 separate_after_non_alphabets: true,
69 separators: "_",
70 keep: "",
71 };
72 let field_ty_name = pascal_case_with_options(struct_folder_file_stem, &opts);
73 let struct_mod_id = parse_id_maybe_raw(struct_folder_file_stem);
74 let import_path = quote! {crate::#struct_mod_folder_id::#struct_mod_id};
75 let field_ty_id = parse_id_maybe_raw(&field_ty_name);
76 let field_ty_path = quote! {
77 #import_path::#field_ty_id
78 };
79 log!("{} -> {}", name, field_ty_path.to_string());
80 quote! {
81 #struct_mod_id: #field_ty_path
82 }
83 })
84 .collect::<Vec<_>>();
85 let name_id = parse_id_maybe_raw(name);
86 let output = quote! {
87 #pre
88 pub struct #name_id {
89 #(#fields),*
90 }
91 }
92 .to_token_stream()
93 .to_string();
94 generate_file(format!("{name}.rs"), output.as_bytes());
95}
96
97fn parse_id_maybe_raw(s: &str) -> Ident {
98 syn::parse_str::<Ident>(s).unwrap_or_else(|_| Ident::new_raw(s, Span::call_site()))
99}
100
101pub fn generate_file<P: AsRef<Path>>(path: P, text: &[u8]) {
106 use std::io::Write;
107 let out_dir = std::env::var("OUT_DIR").unwrap();
108 let out_path = PathBuf::from(&out_dir);
109 let dest_path = out_path.join(&path);
110 let mut f = File::create(dest_path).unwrap();
111 f.write_all(text).unwrap();
112}
113pub fn package_src_folder() -> PathBuf {
117 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
118 PathBuf::from(manifest_dir).join("src")
119}