workspacer_syntax/
generate_struct_signature.rs1crate::ix!();
3
4#[derive(Debug, Clone)]
5pub struct StructSignatureGenerator(ast::Struct);
6
7impl GenerateSignature for ast::Struct {
8 fn generate_signature_with_opts(&self, opts: &SignatureOptions) -> String {
9 trace!("Generating signature for ast::Struct with opts: {:?}", opts);
10
11 let doc_text = if *opts.include_docs() {
12 extract_docs(&self.syntax())
13 .map(|d| format!("{}\n", d))
14 .unwrap_or_default()
15 } else {
16 "".to_string()
17 };
18
19 let vis_str = self
20 .visibility()
21 .map(|v| format!("{} ", v.syntax().text()))
22 .unwrap_or_default();
23
24 let name_str = self
25 .name()
26 .map(|n| n.to_string())
27 .unwrap_or_else(|| "<unknown_struct>".to_string());
28
29 let generic_params_raw = self
30 .generic_param_list()
31 .map(|g| g.syntax().text().to_string())
32 .unwrap_or_default();
33
34 let where_clause = full_clean_where_clause(&self.where_clause());
35
36 let fields_text = {
38 if let Some(fl) = self.field_list() {
39 match fl {
40 ast::FieldList::RecordFieldList(rfl) => {
41 align_record_fields(&rfl)
42 }
43 ast::FieldList::TupleFieldList(tfl) => {
44 align_tuple_fields(&tfl)
45 }
46 }
47 } else {
48 ";".to_string()
50 }
51 };
52
53 let core = format!("{vis_str}struct {name_str}{generic_params_raw} {where_clause} {fields_text}");
54
55 let final_sig = format!("{doc_text}{core}");
56 post_process_spacing(&final_sig)
57 }
58}
59
60fn align_record_fields(rfl: &ast::RecordFieldList) -> String {
69 let mut fields_info = Vec::new();
71 for field in rfl.fields() {
72 let fname = field
73 .name()
74 .map(|n| n.text().to_string())
75 .unwrap_or_default();
76 let fty = field
77 .ty()
78 .map(|t| t.syntax().text().to_string())
79 .unwrap_or_default();
80
81 fields_info.push((fname, fty));
82 }
83
84 if fields_info.is_empty() {
85 return "{ }".to_string();
86 }
87
88 let max_name_len = fields_info.iter().map(|(n, _)| n.len()).max().unwrap_or(0);
90
91 let mut lines = Vec::new();
93 for (name, ftype) in fields_info {
94 let space_count = if max_name_len > name.len() {
95 max_name_len - name.len()
96 } else {
97 0
98 };
99 let spacing = " ".repeat(space_count);
100 let line = format!(" {name}:{spacing} {ftype},");
102 lines.push(line);
103 }
104
105 let joined = lines.join("\n");
106 format!("{{\n{}\n}}", joined)
107}
108
109fn align_tuple_fields(tfl: &ast::TupleFieldList) -> String {
118 let mut fields_info = Vec::new();
120 for field in tfl.fields() {
121 let vis = field
122 .visibility()
123 .map(|v| format!("{} ", v.syntax().text()))
124 .unwrap_or_default();
125 let fty = field
126 .ty()
127 .map(|t| t.syntax().text().to_string())
128 .unwrap_or_default();
129
130 let combined = format!("{}{}", vis, fty);
132 fields_info.push(combined);
133 }
134
135 if fields_info.is_empty() {
136 return "();".to_string();
137 }
138
139 let max_field_len = fields_info.iter().map(|s| s.len()).max().unwrap_or(0);
141
142 let mut lines = Vec::new();
144 for combined in fields_info {
145 let space_count = if max_field_len > combined.len() {
146 max_field_len - combined.len()
147 } else {
148 0
149 };
150 let spacing = " ".repeat(space_count);
151 let line = format!(" {combined}{spacing},");
153 lines.push(line);
154 }
155
156 let joined = lines.join("\n");
157 format!("(\n{}\n);", joined)
158}
159
160fn post_process_spacing(sig: &str) -> String {
162 sig.to_string()
165}