1use std::fmt::Display;
2
3use crate::{
4 EnumDecl, Env, StructDecl, Typedef, Types, UnionDecl,
5 error::{AlignofSnafu, ParseError, SizeofSnafu, UnsupportedEntitySnafu, UnsupportedTypeSnafu},
6};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum TypeKind {
10 USize {
11 size: usize,
12 },
13 SSize {
14 size: usize,
15 },
16 U64,
17 U32,
18 U16,
19 U8,
20 S64,
21 S32,
22 S16,
23 S8,
24 F32,
25 F64,
26 LongDouble {
27 size: usize,
28 alignment: usize,
29 },
30 Char16,
31 Char32,
32 WChar {
33 size: usize,
34 },
35 Bool,
36 Void,
37 Reference {
38 size: usize,
39 referenced_type: Box<TypeKind>,
40 },
41 Pointer {
42 size: usize,
43 pointee_type: Box<TypeKind>,
44 },
45 MemberPointer {
46 size: usize,
47 pointee_type: Box<TypeKind>,
48 record_name: String,
49 },
50 Array {
51 element_type: Box<TypeKind>,
52 size: Option<usize>, },
54 Function {
55 return_type: Box<TypeKind>,
56 parameters: Vec<TypeKind>,
57 },
58 Struct(StructDecl),
59 Class(StructDecl),
60 Union(UnionDecl),
61 Enum(EnumDecl),
62 Typedef(Box<Typedef>),
63 Named(String),
64}
65
66impl TypeKind {
67 pub fn new(env: &Env, types: &Types, ty: clang::Type) -> Result<Self, ParseError> {
68 let kind = ty.get_kind();
69 match kind {
70 clang::TypeKind::ULong => Ok(TypeKind::USize { size: env.word_size().bytes() }),
71 clang::TypeKind::Long => Ok(TypeKind::SSize { size: env.word_size().bytes() }),
72 clang::TypeKind::ULongLong => Ok(TypeKind::U64),
73 clang::TypeKind::UInt => Ok(TypeKind::U32),
74 clang::TypeKind::UShort => Ok(TypeKind::U16),
75 clang::TypeKind::UChar => Ok(TypeKind::U8),
76 clang::TypeKind::LongLong => Ok(TypeKind::S64),
77 clang::TypeKind::Int => Ok(TypeKind::S32),
78 clang::TypeKind::Short => Ok(TypeKind::S16),
79 clang::TypeKind::CharS => Ok(TypeKind::S8),
80 clang::TypeKind::CharU => Ok(TypeKind::U8),
81 clang::TypeKind::Float => Ok(TypeKind::F32),
82 clang::TypeKind::Double => Ok(TypeKind::F64),
83 clang::TypeKind::LongDouble => Ok(TypeKind::LongDouble {
84 size: ty.get_sizeof().map_err(|e| {
85 SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
86 })?,
87 alignment: ty.get_alignof().map_err(|e| {
88 AlignofSnafu { type_name: ty.get_display_name(), error: e }.build()
89 })?,
90 }),
91 clang::TypeKind::Char16 => Ok(TypeKind::Char16),
92 clang::TypeKind::Char32 => Ok(TypeKind::Char32),
93 clang::TypeKind::WChar => Ok(TypeKind::WChar {
94 size: ty.get_sizeof().map_err(|e| {
95 SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
96 })?,
97 }),
98 clang::TypeKind::Bool => Ok(TypeKind::Bool),
99 clang::TypeKind::Void => Ok(TypeKind::Void),
100 clang::TypeKind::LValueReference | clang::TypeKind::Pointer => {
101 let pointee_type = ty.get_pointee_type().ok_or_else(|| {
102 UnsupportedTypeSnafu {
103 message: format!("Pointer type without pointee type: {ty:?}"),
104 }
105 .build()
106 })?;
107 let inner_type = TypeKind::new(env, types, pointee_type)?;
108 let size = ty.get_sizeof().map_err(|e| {
109 SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
110 })?;
111 let pointee_type = Box::new(inner_type);
112
113 if kind == clang::TypeKind::LValueReference {
114 Ok(TypeKind::Reference { size, referenced_type: pointee_type })
115 } else {
116 Ok(TypeKind::Pointer { size, pointee_type })
117 }
118 }
119 clang::TypeKind::MemberPointer => {
120 let pointee_type = ty.get_pointee_type().ok_or_else(|| {
121 UnsupportedTypeSnafu {
122 message: format!("MemberPointer type without pointee type: {ty:?}"),
123 }
124 .build()
125 })?;
126 let inner_type = TypeKind::new(env, types, pointee_type)?;
127 let size = ty.get_sizeof().map_err(|e| {
128 SizeofSnafu { type_name: ty.get_display_name(), error: e }.build()
129 })?;
130 let pointee_type = Box::new(inner_type);
131
132 let record_name = ty
133 .get_class_type()
134 .ok_or_else(|| {
135 UnsupportedTypeSnafu {
136 message: format!("MemberPointer type without class type: {ty:?}"),
137 }
138 .build()
139 })?
140 .get_display_name();
141
142 Ok(TypeKind::MemberPointer { size, pointee_type, record_name })
143 }
144 clang::TypeKind::IncompleteArray => {
145 let element_type = ty.get_element_type().ok_or_else(|| {
146 UnsupportedTypeSnafu {
147 message: format!("IncompleteArray type without element type: {ty:?}"),
148 }
149 .build()
150 })?;
151 let inner_type = TypeKind::new(env, types, element_type)?;
152 Ok(TypeKind::Array { element_type: Box::new(inner_type), size: None })
153 }
154 clang::TypeKind::ConstantArray => {
155 let element_type = ty.get_element_type().ok_or_else(|| {
156 UnsupportedTypeSnafu {
157 message: format!("ConstantArray type without element type: {ty:?}"),
158 }
159 .build()
160 })?;
161 let size = ty.get_size().ok_or_else(|| {
162 UnsupportedTypeSnafu { message: format!("ConstantArray without size: {ty:?}") }
163 .build()
164 })?;
165 let inner_type = TypeKind::new(env, types, element_type)?;
166 Ok(TypeKind::Array { element_type: Box::new(inner_type), size: Some(size) })
167 }
168 clang::TypeKind::FunctionPrototype => {
169 let return_type = ty.get_result_type().ok_or_else(|| {
170 UnsupportedTypeSnafu {
171 message: format!("FunctionPrototype without return type: {ty:?}"),
172 }
173 .build()
174 })?;
175 let parameters = ty.get_argument_types().ok_or_else(|| {
176 UnsupportedTypeSnafu {
177 message: format!("FunctionPrototype without parameters: {ty:?}"),
178 }
179 .build()
180 })?;
181 let return_type = TypeKind::new(env, types, return_type)?;
182 let parameters = parameters
183 .into_iter()
184 .map(|param| TypeKind::new(env, types, param))
185 .collect::<Result<Vec<_>, _>>()?;
186 Ok(TypeKind::Function { return_type: Box::new(return_type), parameters })
187 }
188 clang::TypeKind::Elaborated => {
189 let elaborated_type = ty.get_elaborated_type().ok_or_else(|| {
190 UnsupportedTypeSnafu {
191 message: format!("Elaborated type without type: {ty:?}"),
192 }
193 .build()
194 })?;
195 let elaborated_decl = elaborated_type.get_declaration().ok_or_else(|| {
196 UnsupportedTypeSnafu {
197 message: format!("Elaborated type without declaration: {ty:?}"),
198 }
199 .build()
200 })?;
201 if elaborated_decl.is_anonymous() {
202 TypeKind::new(env, types, elaborated_type)
203 } else {
204 let name = elaborated_decl.get_name().ok_or_else(|| {
205 UnsupportedTypeSnafu {
206 message: format!("Elaborated type declaration without name: {ty:?}"),
207 }
208 .build()
209 })?;
210 match name.as_str() {
211 "bool" => Ok(TypeKind::Bool), _ => Ok(TypeKind::Named(name)),
213 }
214 }
215 }
216 clang::TypeKind::Record => {
217 let node = ty.get_declaration().ok_or_else(|| {
218 UnsupportedTypeSnafu {
219 message: format!("Record type without declaration: {ty:?}"),
220 }
221 .build()
222 })?;
223 match node.get_kind() {
224 clang::EntityKind::StructDecl => {
225 let struct_decl = StructDecl::new(env, types, None, ty)?;
226 Ok(TypeKind::Struct(struct_decl))
227 }
228 clang::EntityKind::ClassDecl => {
229 let struct_decl = StructDecl::new(env, types, None, ty)?;
230 Ok(TypeKind::Class(struct_decl))
231 }
232 clang::EntityKind::UnionDecl => {
233 let union_decl = UnionDecl::new(env, types, None, ty)?;
234 Ok(TypeKind::Union(union_decl))
235 }
236 _ => UnsupportedEntitySnafu {
237 at: "struct/union".to_string(),
238 message: format!(
239 "Unsupported entity kind in record: {:?}",
240 node.get_kind()
241 ),
242 }
243 .fail(),
244 }
245 }
246 clang::TypeKind::Enum => {
247 let decl = ty.get_declaration().ok_or_else(|| {
248 UnsupportedTypeSnafu {
249 message: format!("Enum type without declaration: {ty:?}"),
250 }
251 .build()
252 })?;
253 let name = decl.get_name();
254 Ok(TypeKind::Enum(EnumDecl::new(name, &decl)?))
255 }
256 _ => {
257 panic!("Unsupported type: {:?} for name: {}", ty.get_kind(), ty.get_display_name())
258 }
259 }
260 }
261
262 pub fn size(&self, types: &Types) -> usize {
263 match self {
264 TypeKind::USize { size } | TypeKind::SSize { size } => *size,
265 TypeKind::U64 | TypeKind::S64 => 8,
266 TypeKind::U32 | TypeKind::S32 => 4,
267 TypeKind::U16 | TypeKind::S16 => 2,
268 TypeKind::U8 | TypeKind::S8 => 1,
269 TypeKind::F32 => 4,
270 TypeKind::F64 => 8,
271 TypeKind::LongDouble { size, .. } => *size,
272 TypeKind::Char16 => 2,
273 TypeKind::Char32 => 4,
274 TypeKind::WChar { size } => *size,
275 TypeKind::Bool => 1,
276 TypeKind::Void => 0,
277 TypeKind::Reference { size, .. } => *size,
278 TypeKind::Pointer { size, .. } => *size,
279 TypeKind::MemberPointer { size, .. } => *size,
280 TypeKind::Array { element_type, size } => {
281 if let Some(size) = size {
282 let stride =
283 element_type.size(types).next_multiple_of(element_type.alignment(types));
284 size * stride
285 } else {
286 0
287 }
288 }
289 TypeKind::Function { .. } => 0,
290 TypeKind::Struct(struct_decl) => struct_decl.size(),
291 TypeKind::Class(class_decl) => class_decl.size(),
292 TypeKind::Union(union_decl) => union_decl.size(),
293 TypeKind::Enum(enum_decl) => enum_decl.size(),
294 TypeKind::Typedef(typedef) => typedef.underlying_type().size(types),
295 TypeKind::Named(name) => types.get(name).map(|ty| ty.size(types)).unwrap_or(0),
296 }
297 }
298
299 pub fn alignment(&self, types: &Types) -> usize {
300 match self {
301 TypeKind::USize { size } | TypeKind::SSize { size } => *size,
302 TypeKind::U64 | TypeKind::S64 => 8,
303 TypeKind::U32 | TypeKind::S32 => 4,
304 TypeKind::U16 | TypeKind::S16 => 2,
305 TypeKind::U8 | TypeKind::S8 => 1,
306 TypeKind::F32 => 4,
307 TypeKind::F64 => 8,
308 TypeKind::LongDouble { alignment, .. } => *alignment,
309 TypeKind::Char16 => 2,
310 TypeKind::Char32 => 4,
311 TypeKind::WChar { size } => *size,
312 TypeKind::Bool => 1,
313 TypeKind::Void => 0,
314 TypeKind::Reference { size, .. } => *size,
315 TypeKind::Pointer { size, .. } => *size,
316 TypeKind::MemberPointer { size, .. } => *size,
317 TypeKind::Array { element_type, .. } => element_type.alignment(types),
318 TypeKind::Function { .. } => 0,
319 TypeKind::Struct(struct_decl) => struct_decl.alignment(),
320 TypeKind::Class(class_decl) => class_decl.alignment(),
321 TypeKind::Union(union_decl) => union_decl.alignment(),
322 TypeKind::Enum(enum_decl) => enum_decl.alignment(),
323 TypeKind::Typedef(typedef) => typedef.underlying_type().alignment(types),
324 TypeKind::Named(name) => types.get(name).map(|ty| ty.alignment(types)).unwrap_or(0),
325 }
326 }
327
328 pub fn stride(&self, types: &Types) -> usize {
329 let size = self.size(types);
330 let alignment = self.alignment(types);
331 size.next_multiple_of(alignment)
332 }
333
334 pub fn name(&self) -> Option<&str> {
335 match self {
336 TypeKind::Struct(struct_decl) => struct_decl.name(),
337 TypeKind::Class(class_decl) => class_decl.name(),
338 TypeKind::Union(union_decl) => union_decl.name(),
339 TypeKind::Enum(enum_decl) => enum_decl.name(),
340 TypeKind::Typedef(typedef) => Some(typedef.name()),
341 TypeKind::Named(name) => Some(name),
342 _ => None,
343 }
344 }
345
346 pub fn expand_named<'a>(&'a self, types: &'a Types) -> Option<&'a TypeKind> {
347 match self {
348 TypeKind::Named(name) => types.get(name),
349 _ => Some(self),
350 }
351 }
352
353 pub fn is_forward_decl(&self) -> bool {
354 match self {
355 TypeKind::Struct(struct_decl) => struct_decl.is_forward_decl(),
356 TypeKind::Class(class_decl) => class_decl.is_forward_decl(),
357 _ => false,
358 }
359 }
360
361 pub fn as_struct<'a>(&'a self, types: &'a Types) -> Option<&'a StructDecl> {
362 match self {
363 TypeKind::Struct(struct_decl) => Some(struct_decl),
364 TypeKind::Class(class_decl) => Some(class_decl),
365 TypeKind::Named(name) => types.get(name)?.as_struct(types),
366 _ => None,
367 }
368 }
369}
370
371impl Display for TypeKind {
372 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
373 match self {
374 TypeKind::USize { size } => write!(f, "usize({size})"),
375 TypeKind::SSize { size } => write!(f, "ssize({size})"),
376 TypeKind::U64 => write!(f, "u64"),
377 TypeKind::U32 => write!(f, "u32"),
378 TypeKind::U16 => write!(f, "u16"),
379 TypeKind::U8 => write!(f, "u8"),
380 TypeKind::S64 => write!(f, "s64"),
381 TypeKind::S32 => write!(f, "s32"),
382 TypeKind::S16 => write!(f, "s16"),
383 TypeKind::S8 => write!(f, "s8"),
384 TypeKind::F32 => write!(f, "f32"),
385 TypeKind::F64 => write!(f, "f64"),
386 TypeKind::LongDouble { size, .. } => write!(f, "long double({size})"),
387 TypeKind::Char16 => write!(f, "char16"),
388 TypeKind::Char32 => write!(f, "char32"),
389 TypeKind::WChar { size } => write!(f, "wchar({size})"),
390 TypeKind::Bool => write!(f, "bool"),
391 TypeKind::Void => write!(f, "void"),
392 TypeKind::Reference { referenced_type, .. } => {
393 write!(f, "{}&", referenced_type)
394 }
395 TypeKind::Pointer { pointee_type, .. } => {
396 write!(f, "{}*", pointee_type)
397 }
398 TypeKind::MemberPointer { pointee_type, record_name, .. } => {
399 write!(f, "{} {}::*", pointee_type, record_name)
400 }
401 TypeKind::Array { element_type, size } => {
402 if let Some(size) = size {
403 write!(f, "{}[{}]", element_type, size)
404 } else {
405 write!(f, "{}[]", element_type)
406 }
407 }
408 TypeKind::Function { return_type, parameters } => {
409 let params =
410 parameters.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(", ");
411 write!(f, "{return_type} function({params})")
412 }
413 TypeKind::Struct(struct_decl) => write!(f, "struct {struct_decl}"),
414 TypeKind::Class(class_decl) => write!(f, "class {class_decl}"),
415 TypeKind::Union(union_decl) => write!(f, "union {union_decl}"),
416 TypeKind::Enum(enum_decl) => write!(f, "enum {enum_decl}"),
417 TypeKind::Typedef(typedef) => write!(f, "{typedef}"),
418 TypeKind::Named(name) => write!(f, "{name}"),
419 }
420 }
421}