1use std::collections::HashSet;
15
16use crate::fields_dict::{FieldsDict, StructDef, StructMemberInfo};
17use crate::intern::{InternedStr, StringInterner};
18use crate::rust_decl::RustDeclDict;
19use crate::type_repr::{CDerivedType, TypeRepr};
20
21const SKIP_NAMES_KEYWORDS: &[&str] = &[
25 "as", "async", "await", "break", "const", "continue", "crate", "dyn",
26 "else", "enum", "extern", "fn", "for", "if", "impl", "in",
27 "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return",
28 "self", "Self", "static", "struct", "super", "trait", "type",
29 "unsafe", "use", "where", "while",
30 "abstract", "become", "box", "do", "final", "gen", "macro", "override",
31 "priv", "try", "typeof", "unsized", "virtual", "yield",
32];
33
34pub fn missing_struct_defs<'a>(
39 fields_dict: &'a FieldsDict,
40 rust_decl_dict: Option<&RustDeclDict>,
41 interner: &StringInterner,
42) -> Vec<(InternedStr, &'a StructDef)> {
43 let bindings_struct_names: HashSet<String> = rust_decl_dict
44 .map(|d| d.structs.keys().cloned().collect())
45 .unwrap_or_default();
46
47 let mut result: Vec<(InternedStr, &StructDef)> = fields_dict
48 .iter_struct_defs()
49 .filter(|(name, _)| {
50 let n = interner.get(**name);
51 !bindings_struct_names.contains(n) && !SKIP_NAMES_KEYWORDS.contains(&n)
52 })
53 .map(|(n, d)| (*n, d))
54 .collect();
55 result.sort_by(|a, b| interner.get(a.0).cmp(interner.get(b.0)));
57 result
58}
59
60pub fn format_struct(def: &StructDef, interner: &StringInterner) -> (String, HashSet<String>) {
68 let mut buf = String::new();
69 let mut bitfield_accessors: HashSet<String> = HashSet::new();
70 buf.push_str("#[repr(C)]\n");
71 buf.push_str("#[derive(Copy, Clone)]\n");
72 buf.push_str(&format!(
73 "pub {} {} {{\n",
74 if def.is_union { "union" } else { "struct" },
75 interner.get(def.name)
76 ));
77
78 let mut bitfield_groups: Vec<(usize, &'static str, Vec<(String, u32, u32)>)> = Vec::new();
80
81 let mut i = 0;
83 let mut bitfield_group_idx = 0;
84 while i < def.members.len() {
85 let m = &def.members[i];
86 if m.bitfield_width.is_some() {
87 let group_start = i;
89 let mut total_width = 0u32;
90 while i < def.members.len() && def.members[i].bitfield_width.is_some() {
91 total_width += def.members[i].bitfield_width.unwrap();
92 i += 1;
93 }
94 let pack_ty: &'static str = if total_width <= 8 { "u8" }
96 else if total_width <= 16 { "u16" }
97 else if total_width <= 32 { "u32" }
98 else { "u64" };
99 let names: Vec<&str> = def.members[group_start..i]
101 .iter().map(|m| interner.get(m.name)).collect();
102 buf.push_str(&format!(
103 " /// packed bitfields ({} bit total): {}\n",
104 total_width, names.join(", ")
105 ));
106 buf.push_str(&format!(
107 " pub _bitfield_{}: {},\n",
108 bitfield_group_idx, pack_ty
109 ));
110 let mut shift = 0u32;
112 let mut entries: Vec<(String, u32, u32)> = Vec::new();
113 for bm in &def.members[group_start..i] {
114 let w = bm.bitfield_width.unwrap();
115 entries.push((interner.get(bm.name).to_string(), shift, w));
116 shift += w;
117 }
118 bitfield_groups.push((bitfield_group_idx, pack_ty, entries));
119 bitfield_group_idx += 1;
120 } else {
121 buf.push_str(&format_member_line(m, interner));
122 i += 1;
123 }
124 }
125
126 buf.push_str("}\n");
127
128 if !bitfield_groups.is_empty() {
132 buf.push_str(&format!("impl {} {{\n", interner.get(def.name)));
133 for (gidx, pack_ty, entries) in &bitfield_groups {
134 for (name, shift, width) in entries {
135 if SKIP_NAMES_KEYWORDS.contains(&name.as_str()) {
137 continue;
138 }
139 let mask = if *width >= 64 { u64::MAX } else { (1u64 << width) - 1 };
140 buf.push_str(&format!(
142 " #[inline]\n pub const fn {name}(&self) -> {pack_ty} {{\n\
143 \x20 ((self._bitfield_{gidx} >> {shift}) & {mask}) as {pack_ty}\n\
144 \x20 }}\n",
145 name = name, pack_ty = pack_ty, gidx = gidx,
146 shift = shift, mask = mask
147 ));
148 buf.push_str(&format!(
150 " #[inline]\n pub fn set_{name}(&mut self, val: {pack_ty}) {{\n\
151 \x20 self._bitfield_{gidx} = (self._bitfield_{gidx} & !(({mask} as {pack_ty}) << {shift}))\n\
152 \x20 | ((val & {mask} as {pack_ty}) << {shift});\n\
153 \x20 }}\n",
154 name = name, pack_ty = pack_ty, gidx = gidx,
155 shift = shift, mask = mask
156 ));
157 bitfield_accessors.insert(name.clone());
158 }
159 }
160 buf.push_str("}\n");
161 }
162
163 (buf, bitfield_accessors)
164}
165
166fn format_member_line(m: &StructMemberInfo, interner: &StringInterner) -> String {
168 let ty_str = type_repr_to_rust_struct_field(&m.type_repr, interner);
169 format!(" pub {}: {},\n", interner.get(m.name), ty_str)
170}
171
172pub fn type_repr_to_rust_struct_field(ty: &TypeRepr, interner: &StringInterner) -> String {
175 if let TypeRepr::CType { derived, .. } = ty {
177 if let Some(CDerivedType::Array { size }) = derived.last() {
178 if matches!(size, None | Some(0) | Some(1)) {
179 let mut without_last = (*ty).clone();
181 if let TypeRepr::CType { derived: d, .. } = &mut without_last {
182 d.pop();
183 }
184 let elem = without_last.to_rust_string(interner);
185 return format!("[{}; 0]", elem);
186 }
187 }
188 }
189 ty.to_rust_string(interner)
190}
191
192pub struct EmittedStructs {
194 pub source: String,
195 pub emitted_struct_names: HashSet<String>,
197 pub emitted_typedef_names: HashSet<String>,
199 pub bitfield_methods: std::collections::HashMap<String, HashSet<String>>,
203}
204
205pub fn emit_missing_structs(
208 fields_dict: &FieldsDict,
209 rust_decl_dict: Option<&RustDeclDict>,
210 interner: &StringInterner,
211) -> EmittedStructs {
212 let defs = missing_struct_defs(fields_dict, rust_decl_dict, interner);
213 let mut emitted_struct_names: HashSet<String> = HashSet::new();
214 let mut emitted_typedef_names: HashSet<String> = HashSet::new();
215 let mut bitfield_methods: std::collections::HashMap<String, HashSet<String>> =
216 std::collections::HashMap::new();
217 if defs.is_empty() {
218 return EmittedStructs {
219 source: String::new(),
220 emitted_struct_names,
221 emitted_typedef_names,
222 bitfield_methods,
223 };
224 }
225 let mut buf = String::new();
226 buf.push_str("// === Auto-generated struct definitions ===\n");
227 buf.push_str("// Structs/unions declared in C headers but absent from bindings.rs\n");
228 buf.push_str("// (typically static-inline-only headers like sv_inline.h).\n\n");
229 for (name, def) in defs {
230 let (formatted, accessors) = format_struct(def, interner);
231 if syn::parse_str::<syn::File>(&formatted).is_ok() {
234 buf.push_str(&formatted);
235 buf.push('\n');
236 let struct_name = interner.get(name).to_string();
237 emitted_struct_names.insert(struct_name.clone());
238 if !accessors.is_empty() {
239 bitfield_methods.insert(struct_name, accessors);
240 }
241 } else {
242 buf.push_str(&format!(
243 "// [SKIPPED] struct/union {} — failed to format as valid Rust\n\n",
244 interner.get(name)
245 ));
246 }
247 }
248
249 let bindings_struct_names: HashSet<String> = rust_decl_dict
253 .map(|d| d.structs.keys().cloned().collect())
254 .unwrap_or_default();
255 let bindings_type_names: HashSet<String> = rust_decl_dict
256 .map(|d| d.types.keys().cloned().collect())
257 .unwrap_or_default();
258 let mut typedef_aliases: Vec<(String, String)> = fields_dict
259 .iter_typedefs()
260 .map(|(td, st)| (interner.get(*td).to_string(), interner.get(*st).to_string()))
261 .filter(|(td, st)| {
262 !bindings_struct_names.contains(td)
263 && !bindings_type_names.contains(td)
264 && bindings_struct_names.contains(st)
265 })
266 .collect();
267 typedef_aliases.sort();
268 if !typedef_aliases.is_empty() {
269 buf.push_str("// === Auto-generated typedef aliases ===\n");
270 buf.push_str("// `typedef struct foo NAME;` where struct foo is in bindings.rs\n");
271 buf.push_str("// but the typedef name NAME is not (e.g. XPVHV_WITH_AUX).\n\n");
272 for (td, st) in typedef_aliases {
273 buf.push_str(&format!("#[allow(non_camel_case_types)] pub type {} = {};\n", td, st));
274 emitted_typedef_names.insert(td);
275 }
276 buf.push('\n');
277 }
278 EmittedStructs { source: buf, emitted_struct_names, emitted_typedef_names, bitfield_methods }
279}