type_crawler/types/
field.rs1use std::fmt::Display;
2
3use crate::{
4 Env, TypeKind, Types,
5 error::{InvalidAstSnafu, ParseError},
6};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Field {
10 name: Option<String>,
11 kind: TypeKind,
12 constant: bool,
13 volatile: bool,
14 bit_field_width: Option<u8>,
15}
16
17impl Field {
18 pub fn new(env: &Env, types: &Types, field: &clang::Entity) -> Result<Self, ParseError> {
19 if field.get_kind() != clang::EntityKind::FieldDecl {
20 return InvalidAstSnafu { message: format!("Expected FieldDecl, found: {field:?}") }
21 .fail();
22 }
23
24 let name = if field.is_anonymous() {
25 None
26 } else {
27 let name = field.get_name().ok_or_else(|| {
28 InvalidAstSnafu { message: format!("FieldDecl without name: {field:?}") }.build()
29 })?;
30 Some(name)
31 };
32 let ty = field.get_type().ok_or_else(|| {
33 InvalidAstSnafu { message: format!("Field without type: {field:?}") }.build()
34 })?;
35
36 let kind = TypeKind::new(env, types, ty)?;
37 let constant = ty.is_const_qualified();
38 let volatile = ty.is_volatile_qualified();
39 let bit_field_width = field.get_bit_field_width().map(|w| w as u8);
40 Ok(Self { name, kind, constant, volatile, bit_field_width })
41 }
42
43 pub fn name(&self) -> Option<&str> {
44 self.name.as_deref()
45 }
46
47 pub fn kind(&self) -> &TypeKind {
48 &self.kind
49 }
50
51 pub fn constant(&self) -> bool {
52 self.constant
53 }
54
55 pub fn volatile(&self) -> bool {
56 self.volatile
57 }
58
59 pub fn bit_field_width(&self) -> Option<u8> {
60 self.bit_field_width
61 }
62
63 pub fn size(&self, types: &Types) -> usize {
64 self.bit_field_width()
65 .map(|w| w.div_ceil(8) as usize)
66 .unwrap_or_else(|| self.kind.size(types))
67 }
68}
69
70impl Display for Field {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 let name = self.name.as_deref().unwrap_or("<anon>");
73 write!(
74 f,
75 "{}: {}{}{:?}",
76 name,
77 if self.constant { "const " } else { "" },
78 if self.volatile { "volatile " } else { "" },
79 self.kind
80 )
81 }
82}