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