1use rustc_hash::FxHashMap as HashMap;
2
3use ecow::EcoString;
4
5use crate::ast::{
6 Annotation, EnumVariant, Generic, Literal, Span, StructFieldDefinition, StructKind,
7};
8use crate::types::Type;
9
10#[derive(Debug, Clone)]
11pub struct Definition {
12 pub visibility: Visibility,
13 pub ty: Type,
14 pub name: Option<EcoString>,
15 pub name_span: Option<Span>,
16 pub doc: Option<String>,
17 pub body: DefinitionBody,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum TypeAttribute {
23 Display,
24 ClosedDomain,
25 AnonStruct,
26 HiddenEmbed,
29}
30
31pub type Attributes = HashMap<TypeAttribute, ()>;
32
33#[derive(Debug, Clone)]
34pub enum DefinitionBody {
35 TypeAlias {
36 generics: Vec<Generic>,
37 annotation: Annotation,
38 methods: MethodSignatures,
39 attributes: Attributes,
40 },
41 Enum {
42 generics: Vec<Generic>,
43 variants: Vec<EnumVariant>,
44 methods: MethodSignatures,
45 attributes: Attributes,
46 },
47 Struct {
48 generics: Vec<Generic>,
49 fields: Vec<StructFieldDefinition>,
50 kind: StructKind,
51 methods: MethodSignatures,
52 constructor: Option<Type>,
53 attributes: Attributes,
54 },
55 Interface {
56 definition: Interface,
57 },
58 Value {
59 allowed_lints: Vec<String>,
60 go_hints: Vec<String>,
61 go_name: Option<String>,
62 const_value: Option<Literal>,
66 },
67}
68
69impl Definition {
70 pub fn ty(&self) -> &Type {
71 &self.ty
72 }
73
74 pub fn visibility(&self) -> &Visibility {
75 &self.visibility
76 }
77
78 pub fn name_span(&self) -> Option<Span> {
79 self.name_span
80 }
81
82 pub fn doc(&self) -> Option<&String> {
83 self.doc.as_ref()
84 }
85
86 pub fn is_newtype(&self) -> bool {
91 matches!(
92 &self.body,
93 DefinitionBody::Struct {
94 kind: StructKind::Tuple,
95 fields,
96 generics,
97 ..
98 } if fields.len() == 1 && generics.is_empty()
99 )
100 }
101
102 pub fn is_pointer_backed_newtype<F>(&self, is_alias: F) -> bool
103 where
104 F: Fn(&str) -> bool,
105 {
106 self.is_newtype()
107 && matches!(
108 &self.body,
109 DefinitionBody::Struct { fields, .. }
110 if crate::types::peel_alias(&fields[0].ty, is_alias).is_ref()
111 )
112 }
113
114 pub fn allowed_lints(&self) -> &[String] {
115 match &self.body {
116 DefinitionBody::Value { allowed_lints, .. } => allowed_lints,
117 _ => &[],
118 }
119 }
120
121 pub fn go_hints(&self) -> &[String] {
122 match &self.body {
123 DefinitionBody::Value { go_hints, .. } => go_hints,
124 _ => &[],
125 }
126 }
127
128 pub fn go_name(&self) -> Option<&str> {
129 match &self.body {
130 DefinitionBody::Value { go_name, .. } => go_name.as_deref(),
131 _ => None,
132 }
133 }
134
135 pub fn const_value(&self) -> Option<&Literal> {
136 match &self.body {
137 DefinitionBody::Value { const_value, .. } => const_value.as_ref(),
138 _ => None,
139 }
140 }
141
142 pub fn methods_mut(&mut self) -> Option<&mut MethodSignatures> {
143 match &mut self.body {
144 DefinitionBody::Struct { methods, .. } => Some(methods),
145 DefinitionBody::TypeAlias { methods, .. } => Some(methods),
146 DefinitionBody::Enum { methods, .. } => Some(methods),
147 _ => None,
148 }
149 }
150
151 pub fn attributes(&self) -> Option<&Attributes> {
152 match &self.body {
153 DefinitionBody::Struct { attributes, .. }
154 | DefinitionBody::Enum { attributes, .. }
155 | DefinitionBody::TypeAlias { attributes, .. } => Some(attributes),
156 _ => None,
157 }
158 }
159
160 pub fn is_display(&self) -> bool {
161 self.attributes()
162 .is_some_and(|a| a.contains_key(&TypeAttribute::Display))
163 }
164
165 pub fn is_closed_domain(&self) -> bool {
166 self.attributes()
167 .is_some_and(|a| a.contains_key(&TypeAttribute::ClosedDomain))
168 }
169
170 pub fn is_anon_struct(&self) -> bool {
171 self.attributes()
172 .is_some_and(|a| a.contains_key(&TypeAttribute::AnonStruct))
173 }
174
175 pub fn has_hidden_embed(&self) -> bool {
176 self.attributes()
177 .is_some_and(|a| a.contains_key(&TypeAttribute::HiddenEmbed))
178 }
179
180 pub fn is_type_definition(&self) -> bool {
181 matches!(
182 self.body,
183 DefinitionBody::Struct { .. }
184 | DefinitionBody::Enum { .. }
185 | DefinitionBody::TypeAlias { .. }
186 )
187 }
188
189 pub fn is_type_alias(&self) -> bool {
190 matches!(self.body, DefinitionBody::TypeAlias { .. })
191 }
192
193 pub fn is_value(&self, qualified_name: &str) -> bool {
194 matches!(self.body, DefinitionBody::Value { .. })
195 && self.ty.unwrap_forall().get_qualified_id() != Some(qualified_name)
196 }
197}
198
199pub type MethodSignatures = HashMap<EcoString, Type>;
200
201#[derive(Debug, Clone, PartialEq)]
202pub enum Visibility {
203 Public,
204 Private,
205 Local,
206}
207
208impl Visibility {
209 pub fn is_public(&self) -> bool {
210 matches!(self, Visibility::Public)
211 }
212}
213
214#[derive(Debug, Clone, PartialEq)]
215pub struct Interface {
216 pub name: EcoString,
217 pub generics: Vec<Generic>,
218 pub parents: Vec<Type>,
219 pub methods: HashMap<EcoString, Type>,
220}