type_crawler/types/
mod.rs1mod 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 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}