gather_all_code_from_crates/
reconstruct.rs1crate::ix!();
2
3pub fn reconstruct_code_from_filtered_items(items: &[ItemInfo], omit_bodies: bool) -> String {
4
5 let mut output = String::new();
8
9 for item in items {
10 match item {
11 ItemInfo::Function(f) => {
12 reconstruct_function(f, omit_bodies, &mut output, 0);
13 }
14 ItemInfo::Struct { attributes, is_public, signature, .. } => {
15 for attr in attributes {
16 output.push_str(attr);
17 output.push('\n');
18 }
19 if *is_public && !signature.starts_with("pub ") {
20 }
22 output.push_str(signature);
23 output.push('\n');
24 output.push('\n');
25 }
26 ItemInfo::Enum { attributes, is_public, signature, .. } => {
27 for attr in attributes {
28 output.push_str(attr);
29 output.push('\n');
30 }
31 if *is_public && !signature.starts_with("pub ") {
32 }
34 output.push_str(signature);
35 output.push('\n');
36 output.push('\n');
37 }
38 ItemInfo::TypeAlias { attributes, is_public, signature, .. } => {
39 for attr in attributes {
40 output.push_str(attr);
41 output.push('\n');
42 }
43 if *is_public && !signature.starts_with("pub ") {
44 }
46 output.push_str(signature);
47 output.push('\n');
48 output.push('\n');
49 }
50 ItemInfo::ImplBlock { attributes, signature, methods, .. } => {
51 for attr in attributes {
52 output.push_str(attr);
53 output.push('\n');
54 }
55 output.push_str(signature);
57 output.push_str(" {\n");
58 for m in methods {
59 reconstruct_function(m, omit_bodies, &mut output,4);
60 }
61 output.push_str("}\n\n");
62 }
63 }
64 }
65
66 output
67}
68
69
70pub fn reconstruct_function(f: &FunctionInfo, omit_bodies: bool, output: &mut String, indent_level: usize) {
71 let indent = " ".repeat(indent_level);
72
73 for attr in f.attributes() {
75 output.push_str(&format!("{}{}\n", indent, attr.trim()));
76 }
77
78 let mut sig_line = f.signature().trim().to_string();
80
81 if omit_bodies {
82 if !sig_line.ends_with(';') {
83 sig_line.push(';');
84 }
85 output.push_str(&format!("{}{}\n", indent, sig_line.trim()));
86 } else {
87 if let Some(body) = f.body() {
88 let sig_line = sig_line.trim_end().trim_end_matches(';').trim_end();
89 output.push_str(&format!("{}{} ", indent, sig_line));
90
91 let normalized_body = normalize_and_reindent_body(body, indent_level + 4);
93 output.push_str("{\n");
94 output.push_str(&normalized_body);
95 output.push_str(&format!("\n{}}}\n", indent)); } else {
97 if !sig_line.ends_with(';') {
98 sig_line.push(';');
99 }
100 output.push_str(&format!("{}{}\n", indent, sig_line.trim()));
101 }
102 }
103
104 output.push('\n');
106}
107
108
109fn normalize_and_reindent_body(body: &str, target_indent: usize) -> String {
110 let lines: Vec<&str> = body.lines().collect();
111
112 let (start, end) = if !lines.is_empty()
114 && lines.first().map(|l| l.trim()) == Some("{")
115 && lines.last().map(|l| l.trim()) == Some("}")
116 {
117 (1, lines.len() - 1)
118 } else {
119 (0, lines.len())
120 };
121
122 let relevant_lines = &lines[start..end];
123
124 let min_indent = relevant_lines.iter()
126 .filter(|line| !line.trim().is_empty())
127 .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
128 .min()
129 .unwrap_or(0);
130
131 let mut final_body = String::new();
132
133 for line in relevant_lines {
134 let trimmed_line = if line.trim().is_empty() {
135 "".to_string() } else {
137 let start_idx = min_indent.min(line.len());
138 line[start_idx..].to_string()
139 };
140
141 let indented_line = format!("{}{}", " ".repeat(target_indent), trimmed_line);
142 final_body.push_str(&indented_line);
143 final_body.push('\n');
144 }
145
146 final_body
147}
148
149
150#[cfg(test)]
151mod reconstruct_code_from_filtered_fns_tests {
152 use super::*;
153
154 #[test]
155 fn test_reconstruct_code_from_filtered_fns_with_bodies() {
156
157 let fns = vec![
158 ItemInfo::Function(FunctionInfoBuilder::default()
159 .name("foo".to_string())
160 .is_public(false)
161 .is_test(false)
162 .attributes(vec!["#[inline]".to_string()])
163 .signature("fn foo(x: i32) -> i32".to_string())
164 .body(Some("{ x + 1 }".to_string()))
165 .build()
166 .unwrap()),
167 ItemInfo::Function(FunctionInfoBuilder::default()
168 .name("bar".to_string())
169 .is_public(true)
170 .is_test(true)
171 .attributes(vec!["#[test]".to_string()])
172 .signature("pub fn bar()".to_string())
173 .body(Some("{ assert_eq!(2,2); }".to_string()))
174 .build()
175 .unwrap()),
176 ];
177
178 let code = reconstruct_code_from_filtered_items(&fns, false);
179 assert!(code.contains("#[inline]\nfn foo(x: i32) -> i32 { x + 1 }"));
180 assert!(code.contains("#[test]\npub fn bar() { assert_eq!(2,2); }"));
181 }
182
183 #[test]
184 fn test_reconstruct_code_from_filtered_fns_omit_bodies() {
185
186 let fns = vec![
187 ItemInfo::Function(FunctionInfoBuilder::default()
188 .name("foo".to_string())
189 .is_public(false)
190 .is_test(false)
191 .attributes(vec!["#[inline]".to_string()])
192 .signature("fn foo(x: i32) -> i32".to_string())
193 .body(Some("{ x + 1 }".to_string()))
194 .build()
195 .unwrap()),
196 ];
197
198 let code = reconstruct_code_from_filtered_items(&fns, true);
199 assert!(code.contains("#[inline]\nfn foo(x: i32) -> i32;"));
201 assert!(!code.contains("{ x + 1 }"));
202 }
203}