Skip to main content

type_crawler/types/
mod.rs

1mod enum_decl;
2mod field;
3mod struct_decl;
4mod type_kind;
5mod typedef;
6mod union_decl;
7
8use indexmap::IndexMap;
9
10pub use enum_decl::{EnumConstant, EnumDecl};
11pub use field::Field;
12use snafu::Snafu;
13pub use struct_decl::{StructDecl, StructField};
14pub use type_kind::TypeKind;
15pub use typedef::Typedef;
16pub use union_decl::UnionDecl;
17
18#[derive(Default)]
19pub struct Types {
20    types: IndexMap<String, TypeKind>,
21}
22
23#[derive(Debug, Snafu)]
24pub enum ExtendTypesError {
25    #[snafu(display("Type with the same name but different definitions:\n{left}\nand\n{right}"))]
26    ConflictingTypes { left: Box<TypeKind>, right: Box<TypeKind> },
27}
28
29impl Types {
30    pub fn new() -> Self {
31        Default::default()
32    }
33
34    pub fn add_type(&mut self, kind: TypeKind) -> Result<bool, ExtendTypesError> {
35        if let TypeKind::Typedef(typedef) = &kind
36            && let TypeKind::Named(name) = typedef.underlying_type()
37            && typedef.name() == name
38        {
39            // Avoid adding a typedef that has the same name as its underlying type
40            // Example: typedef struct MyStruct {...} MyStruct;
41            return Ok(false);
42        };
43        if let Some(name) = kind.name().map(String::from) {
44            match self.types.entry(name) {
45                indexmap::map::Entry::Occupied(mut entry) => {
46                    let current = entry.get();
47                    if current.is_forward_decl() {
48                        entry.insert(kind);
49                    } else if !kind.is_forward_decl() && current != &kind {
50                        return ConflictingTypesSnafu {
51                            left: Box::new(current.clone()),
52                            right: Box::new(kind),
53                        }
54                        .fail();
55                    }
56                }
57                indexmap::map::Entry::Vacant(entry) => {
58                    entry.insert(kind);
59                }
60            }
61            Ok(true)
62        } else {
63            Ok(false)
64        }
65    }
66
67    pub fn types(&self) -> impl Iterator<Item = &TypeKind> {
68        self.types.values()
69    }
70
71    pub fn len(&self) -> usize {
72        self.types.len()
73    }
74
75    pub fn is_empty(&self) -> bool {
76        self.len() == 0
77    }
78
79    pub fn get(&self, name: &str) -> Option<&TypeKind> {
80        self.types.get(name)
81    }
82
83    pub fn extend(&mut self, other: Types) -> Result<(), ExtendTypesError> {
84        for (name, value) in other.types {
85            match self.types.entry(name.clone()) {
86                indexmap::map::Entry::Occupied(mut entry) => {
87                    let current = entry.get();
88                    if current.is_forward_decl() {
89                        entry.insert(value);
90                    } else if !value.is_forward_decl() && current != &value {
91                        return ConflictingTypesSnafu {
92                            left: Box::new(current.clone()),
93                            right: Box::new(value),
94                        }
95                        .fail();
96                    }
97                }
98                indexmap::map::Entry::Vacant(entry) => {
99                    entry.insert(value);
100                }
101            }
102        }
103        Ok(())
104    }
105}