1
2mod codeblocks;
3pub use codeblocks::{TextBlock, MatchBlock};
4mod enumdecl;
5
6mod propfns;
7
8mod utils;
9
10mod trait_impl;
11
12mod testblock;
13
14use std::fs;
15use std::path::{PathBuf, Path};
16
17mod fragments;
18
19mod gen_error;
20use gen_error::GenError;
21
22use super::reader::write_lines_to_file;
23
24use self::enumdecl::{generate_enum_decl, generate_get_all_variants_fn, generate_variant_str_fns};
25
26use self::propfns::generate_property_fns;
27
28use self::testblock::generate_testblock;
29use self::trait_impl::{generate_impl_block, generate_impl_fmt_display};
30
31use super::{EnumTable, RTypeTrait};
32
33use super::EnumOptions;
34
35
36pub struct EnumModule<'a> {
37 pub options: &'a EnumOptions,
38 pub enumname: String,
39 pub properties: Vec<String>,
40pub imports: Vec<String>,
42pub enumdeclaration: TextBlock,
44pub get_all_variants_fn: TextBlock,
46pub variants_as_str_module: TextBlock,
48pub propfn_blocks: Vec<(String, TextBlock)>,
50pub impl_block: TextBlock,
52pub fmt_block: TextBlock,
54pub test_block: TextBlock,
56}
57
58impl <'a> EnumModule<'a> {
59 pub fn new(et: &EnumTable, options: &'a EnumOptions) -> Self {
60 let make_variant_str_fns = options.gen_variant_str_fns;
61 let mut imports: Vec<String> = vec![];
62 for types in &et.parsed_types {
63 if types.to_typestr_no_ref() == "Regex" {
64 imports.push("extern crate regex;".to_string());
65 imports.push("use regex::Regex;".to_string());
66 imports.push("use std::sync::OnceLock;".to_string());
67
68 break;
69 }
70 }
71
72
73 EnumModule {
74 options,
75 enumname: et.get_name().to_string(),
77 properties: et.get_properties().to_vec(),
78 imports,
79 enumdeclaration: generate_enum_decl(et),
80 get_all_variants_fn: generate_get_all_variants_fn(et),
81 variants_as_str_module: if make_variant_str_fns {generate_variant_str_fns(et)} else {TextBlock::new()},
82 propfn_blocks: generate_property_fns(et),
83 impl_block: if options.gen_impl_links {generate_impl_block(et, make_variant_str_fns)} else {TextBlock::new()},
84 fmt_block: generate_impl_fmt_display(et),
85 test_block: generate_testblock(et),
86 }
87 }
88 pub fn to_lines(&self) -> Vec<String> {
90 let mut lines = vec![];
91
92
93 for imp in &self.imports {
94 lines.push(imp.to_string());
95 }
96 self.enumdeclaration.collect_lines_into(&mut lines);
97 self.get_all_variants_fn.collect_lines_into(&mut lines);
98 self.variants_as_str_module.collect_lines_into(&mut lines);
99
100 for blk in &self.propfn_blocks {
101 blk.1.collect_lines_into(&mut lines);
102 }
103 self.impl_block.collect_lines_into(&mut lines);
104 self.fmt_block.collect_lines_into(&mut lines);
105 self.test_block.collect_lines_into(&mut lines);
106 lines
107 }
108
109 pub fn print_configured_to_file(&mut self) -> Result<(), Box<dyn std::error::Error>> {
110
111 let filepath = &self.options.path_to_outfile;
113 let enum_lc = self.enumname.to_ascii_lowercase();
114 let def_file_name = format!("{}.rs",enum_lc);
115
116 let mut parentpath: PathBuf = filepath.to_owned();
117 let mut printfile: PathBuf = parentpath.join(def_file_name);
118
119 if let Some(extension) = filepath.extension() {
121 if extension == "rs" {
122 parentpath = filepath.parent().unwrap().to_path_buf();
124 printfile = filepath.to_path_buf();
125 } else {
126 let new_filename = Path::new(filepath.file_stem().unwrap())
128 .with_extension("rs")
129 .to_owned();
130
131 parentpath = filepath.parent().unwrap().to_path_buf();
132 printfile = filepath.with_file_name(new_filename);
133 }
134 }
135 if !parentpath.exists() {
136 fs::create_dir_all(&parentpath)?;
137 }
138
139 let mainfile = printfile.to_str().unwrap();
140 if self.options.split_files {
144
145 let mut nested_path = parentpath.clone();
147 nested_path.push(enum_lc);
148
149 if !nested_path.exists() {
151 fs::create_dir_all(&nested_path)?;
152 }
153
154
155 for prop_block in &self.propfn_blocks {
156 let prop = &prop_block.0;
157 let prop_lc = prop.to_ascii_lowercase();
158 let prop_file = format!("{}.rs", prop_lc);
159 self.imports.push(format!("mod {};", prop_lc));
160 self.imports.push(format!("use {}::*;", prop_lc));
161 let prop_file = nested_path.join(prop_file);
162 let prop_file = prop_file.to_str().unwrap();
163
164 let mut lines = vec![format!("use super::{};", &self.enumname)];
165 prop_block.1.collect_lines_into(&mut lines);
166 write_lines_to_file(prop_file, lines)?;
168 }
169 self.propfn_blocks = vec![];
170
171 if self.options.gen_variant_str_fns {
172 let var_file = "variantstr.rs";
173 self.imports.push("mod variantstr;".to_string());
174 self.imports.push("use variantstr::*;".to_string());
175 let var_file = nested_path.join(var_file);
176 let var_file = var_file.to_str().unwrap();
177 let mut lines = vec![format!("use super::{};", &self.enumname)];
178 self.variants_as_str_module.collect_lines_into(&mut lines);
179 write_lines_to_file(var_file, lines)?;
180 self.variants_as_str_module = TextBlock::new();
181 }
182 }
183
184 let mut full_lines: Vec<String> = self.imports.clone();
185 self.enumdeclaration.collect_lines_into(&mut full_lines);
186
187 if self.options.gen_impl_links {
188 self.impl_block.collect_lines_into(&mut full_lines);
189 }
190
191 if self.options.gen_variant_str_fns {
192 self.fmt_block.collect_lines_into(&mut full_lines);
193 }
194
195 self.get_all_variants_fn.collect_lines_into(&mut full_lines);
196 self.variants_as_str_module.collect_lines_into(&mut full_lines);
197 for blk in &self.propfn_blocks {
198 blk.1.collect_lines_into(&mut full_lines);
199 }
200
201 if self.options.gen_impl_links {
202 self.test_block.collect_lines_into(&mut full_lines);
203 }
204 write_lines_to_file(mainfile, full_lines)?;
205
206 println!("Successfully generated @ {}", mainfile);
207 Ok(())
208 }
209
210}
211
212impl <'a> std::fmt::Display for EnumModule<'a> {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214
215 writeln!(f, "Main file: {}", self.enumname)?;
216 writeln!(f, "Imports: ")?;
217 for imp in &self.imports {
218 writeln!(f, "{}", imp)?;
219 }
220 write!(f,"{}", self.enumdeclaration)?;
221 write!(f,"{}", self.get_all_variants_fn)?;
222 write!(f,"{}", self.variants_as_str_module)?;
223 for blk in &self.propfn_blocks {
224 writeln!(f, "{}", blk.1)?;
225 }
226 write!(f,"{}", self.impl_block)?;
227 write!(f,"{}", self.fmt_block)?;
228 write!(f,"{}", self.test_block)?;
229 Ok(())
230 }
231}
232
233
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn test_make_enummodule() {
241 use crate::parser::TableParser;
242 let rows: Vec<&str> = vec![
244 "TYPES, &str, (usize,f64), &str",
245 "MyEnumName, Property1, Property2, Property3",
246 "Variant1, standard, (0, 3.14), cheap",
247 "Variant2, medium, (0, 9.82), pricey",
248 ];
249
250 let table_parser = TableParser::from_csv_lines(rows).unwrap();
251 let enumtable = table_parser.to_enumtable().unwrap();
252 assert_eq!(enumtable.get_col_of_property("Property1"), Some(0));
253
254 let options = EnumOptions::default();
255
256 let enummodule = EnumModule::new(&enumtable, &options);
257
258 println!("{}", enummodule);
259
260 }
261
262}