type_crawler/types/
struct_decl.rs1use std::fmt::Display;
2
3use crate::{
4 Env, Field, TypeKind, Types,
5 error::{
6 AlignofSnafu, InvalidAstSnafu, InvalidFieldsSnafu, OffsetofSnafu, ParseError, SizeofSnafu,
7 UnsupportedEntitySnafu, UnsupportedTypeSnafu,
8 },
9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct StructDecl {
13 pub(crate) name: Option<String>,
14 pub(crate) base_types: Vec<String>,
15 pub(crate) fields: Vec<StructField>,
16 size: usize,
17 alignment: usize,
18 is_class: bool,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct StructField {
23 offset: usize,
25 field: Field,
26}
27
28impl StructDecl {
29 pub fn new(
30 env: &Env,
31 types: &Types,
32 name: Option<String>,
33 ty: clang::Type,
34 ) -> Result<Self, ParseError> {
35 if ty.get_kind() != clang::TypeKind::Record {
36 return InvalidAstSnafu { message: format!("Expected Record, found: {ty:?}") }.fail();
37 }
38
39 let mut base_types = Vec::new();
40 let Some(node) = ty.get_declaration() else {
41 return InvalidAstSnafu { message: format!("Record type without declaration: {ty:?}") }
42 .fail();
43 };
44 for child in node.get_children() {
45 if child.get_kind() != clang::EntityKind::BaseSpecifier {
46 continue;
47 }
48 let base_type = child.get_type().ok_or_else(|| {
49 InvalidAstSnafu { message: format!("BaseSpecifier without type: {child:?}") }
50 .build()
51 })?;
52 let base_name = base_type.get_display_name();
53 base_types.push(base_name);
54 }
55
56 let is_class = node.get_kind() == clang::EntityKind::ClassDecl;
57
58 let display_name = name.as_deref().unwrap_or("<anon>");
59
60 let record_fields = ty.get_fields().ok_or_else(|| {
61 UnsupportedTypeSnafu { message: format!("Record type without fields: {ty:?}") }.build()
62 })?;
63 if record_fields.is_empty() {
64 let declaration = ty.get_declaration().ok_or_else(|| {
65 InvalidAstSnafu { message: format!("Record type without declaration: {ty:?}") }
66 .build()
67 })?;
68
69 let decl_children = declaration.get_children();
70 let invalid_fields = decl_children
71 .iter()
72 .enumerate()
73 .filter(|(_, c)| {
74 c.get_kind() == clang::EntityKind::FieldDecl && c.is_invalid_declaration()
75 })
76 .collect::<Vec<_>>();
77 if !invalid_fields.is_empty() {
78 return InvalidFieldsSnafu {
79 field_names: invalid_fields
80 .iter()
81 .map(|(i, c)| c.get_name().unwrap_or_else(|| format!("<index#{i}>")))
82 .collect::<Vec<_>>(),
83 struct_name: display_name.to_string(),
84 }
85 .fail();
86 }
87 }
88
89 let mut fields = Vec::<StructField>::new();
90 for field in &record_fields {
91 match field.get_kind() {
92 clang::EntityKind::FieldDecl => {
93 let offset = Self::get_offset_of_field(display_name, field)?;
94 fields.push(StructField { offset, field: Field::new(env, types, field)? });
95 }
96 _ => {
97 return UnsupportedEntitySnafu {
98 at: format!("struct/class {display_name}"),
99 message: format!(
100 "Unsupported entity kind in struct/class: {:?}",
101 field.get_kind()
102 ),
103 }
104 .fail();
105 }
106 }
107 }
108
109 let size = ty.get_sizeof().or_else(|e| {
110 if record_fields.is_empty() {
111 Ok(1)
112 } else {
113 SizeofSnafu { type_name: display_name.to_string(), error: e }.fail()
114 }
115 })?;
116 let alignment = ty.get_alignof().or_else(|e| {
117 if record_fields.is_empty() {
118 Ok(1)
119 } else {
120 AlignofSnafu { type_name: display_name.to_string(), error: e }.fail()
121 }
122 })?;
123
124 Ok(Self { name, base_types, fields, size, alignment, is_class })
125 }
126
127 fn get_offset_of_field(struct_name: &str, node: &clang::Entity) -> Result<usize, ParseError> {
128 node.get_offset_of_field().map_err(|e| {
129 OffsetofSnafu {
130 field_name: node.get_name().unwrap_or_default(),
131 struct_name: struct_name.to_string(),
132 error: e,
133 }
134 .build()
135 })
136 }
137
138 pub fn size(&self) -> usize {
139 self.size
140 }
141
142 pub fn alignment(&self) -> usize {
143 self.alignment
144 }
145
146 pub fn is_forward_decl(&self) -> bool {
147 self.fields.is_empty()
148 }
149
150 pub fn base_types(&self) -> &[String] {
151 &self.base_types
152 }
153
154 pub fn fields(&self) -> &[StructField] {
155 &self.fields
156 }
157
158 pub fn get_field<'a>(&'a self, types: &'a Types, name: &str) -> Option<&'a StructField> {
159 self.fields.iter().find(|f| f.name() == Some(name)).or_else(|| {
160 self.base_types
161 .iter()
162 .filter_map(|base| types.get(base))
163 .filter_map(|base| base.expand_named(types))
164 .filter_map(|base| match base {
165 TypeKind::Struct(struct_decl) => struct_decl.get_field(types, name),
166 TypeKind::Class(class_decl) => class_decl.get_field(types, name),
167 _ => None,
168 })
169 .next()
170 })
171 }
172
173 pub fn name(&self) -> Option<&str> {
174 self.name.as_deref()
175 }
176
177 pub fn is_class(&self) -> bool {
178 self.is_class
179 }
180}
181
182impl StructField {
183 pub fn offset_bytes(&self) -> usize {
184 self.offset / 8
185 }
186
187 pub fn offset_bits(&self) -> usize {
188 self.offset
189 }
190
191 pub fn name(&self) -> Option<&str> {
192 self.field.name()
193 }
194
195 pub fn kind(&self) -> &super::TypeKind {
196 self.field.kind()
197 }
198
199 pub fn constant(&self) -> bool {
200 self.field.constant()
201 }
202
203 pub fn volatile(&self) -> bool {
204 self.field.volatile()
205 }
206
207 pub fn bit_field_width(&self) -> Option<u8> {
208 self.field.bit_field_width()
209 }
210
211 pub fn size(&self, types: &Types) -> usize {
212 self.field.size(types)
213 }
214}
215
216impl Display for StructDecl {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 write!(f, "{}", self.name.as_deref().unwrap_or("<anon>"))?;
219 if !self.base_types.is_empty() {
220 write!(f, " : ")?;
221 let mut iter = self.base_types.iter();
222 write!(f, "{}", iter.next().unwrap())?;
223 for base in iter {
224 write!(f, ", {base}")?;
225 }
226 }
227 writeln!(f, " {{")?;
228 for field in &self.fields {
229 writeln!(f, " ({:#x}) {}", field.offset_bytes(), field.field)?;
230 }
231 write!(f, "}}")?;
232 Ok(())
233 }
234}