1use crate::EngineApi;
7use crate::gdscript_layer::{BuiltinFn, GlobalConst};
8use crate::model::{
9 BuiltinData, BuiltinId, ClassData, ClassId, ConstInfo, EnumInfo, MethodSig, OperatorSig,
10 PropertyInfo, SignalSig, UtilityFn,
11};
12use rustc_hash::FxHashSet;
13
14#[derive(Debug, Clone, Copy)]
16pub enum MemberRef<'a> {
17 Method(&'a MethodSig),
19 Property(&'a PropertyInfo),
21 Signal(&'a SignalSig),
23 Const(&'a ConstInfo),
25 Enum(&'a EnumInfo),
27 EnumValue {
32 class: &'a str,
34 decl: &'a EnumInfo,
36 value: &'a crate::model::EnumValue,
38 },
39}
40
41impl MemberRef<'_> {
42 #[must_use]
44 pub fn name(&self) -> &str {
45 match self {
46 Self::Method(m) => &m.name,
47 Self::Property(p) => &p.name,
48 Self::Signal(s) => &s.name,
49 Self::Const(c) => &c.name,
50 Self::Enum(e) => &e.name,
51 Self::EnumValue { value, .. } => &value.name,
52 }
53 }
54}
55
56impl EngineApi {
57 #[must_use]
61 pub fn classes(&self) -> &[ClassData] {
62 &self.data.classes
63 }
64
65 #[must_use]
67 pub fn builtins(&self) -> &[BuiltinData] {
68 &self.data.builtins
69 }
70
71 #[must_use]
73 pub fn class(&self, id: ClassId) -> &ClassData {
74 &self.data.classes[id.0 as usize]
75 }
76
77 #[must_use]
79 pub fn builtin(&self, id: BuiltinId) -> &BuiltinData {
80 &self.data.builtins[id.0 as usize]
81 }
82
83 #[must_use]
87 pub fn class_by_name(&self, name: &str) -> Option<ClassId> {
88 self.class_by_name.get(name).copied()
89 }
90
91 #[must_use]
93 pub fn builtin_by_name(&self, name: &str) -> Option<BuiltinId> {
94 self.builtin_by_name.get(name).copied()
95 }
96
97 #[must_use]
99 pub fn int_builtin(&self) -> Option<BuiltinId> {
100 self.int_builtin
101 }
102
103 #[must_use]
105 pub fn singleton(&self, name: &str) -> Option<ClassId> {
106 self.singleton_by_name.get(name).copied()
107 }
108
109 #[must_use]
111 pub fn utility(&self, name: &str) -> Option<&UtilityFn> {
112 let i = *self.utility_by_name.get(name)?;
113 self.data.utilities.get(i as usize)
114 }
115
116 #[must_use]
118 pub fn global_enum(&self, name: &str) -> Option<&EnumInfo> {
119 let i = *self.global_enum_by_name.get(name)?;
120 self.data.global_enums.get(i as usize)
121 }
122
123 #[must_use]
127 pub fn global_enum_value(&self, name: &str) -> Option<(&EnumInfo, &crate::model::EnumValue)> {
128 let (ei, vi) = *self.global_enum_value_by_name.get(name)?;
129 let e = self.data.global_enums.get(ei as usize)?;
130 Some((e, e.values.get(vi as usize)?))
131 }
132
133 #[must_use]
135 pub fn global_const(&self, name: &str) -> Option<&GlobalConst> {
136 self.global_consts.iter().find(|c| c.name == name)
137 }
138
139 #[must_use]
141 pub fn gdscript_builtin(&self, name: &str) -> Option<&BuiltinFn> {
142 self.gdscript_builtins.iter().find(|f| f.name == name)
143 }
144
145 #[must_use]
149 pub fn lookup_member(&self, class: ClassId, name: &str) -> Option<MemberRef<'_>> {
150 let mut cur = Some(class);
151 while let Some(cid) = cur {
152 let c = self.class(cid);
153 if let Some(m) = c.methods.iter().find(|m| m.name == name) {
154 return Some(MemberRef::Method(m));
155 }
156 if let Some(p) = c.properties.iter().find(|p| p.name == name) {
157 return Some(MemberRef::Property(p));
158 }
159 if let Some(s) = c.signals.iter().find(|s| s.name == name) {
160 return Some(MemberRef::Signal(s));
161 }
162 if let Some(k) = c.constants.iter().find(|k| k.name == name) {
163 return Some(MemberRef::Const(k));
164 }
165 if let Some(e) = c.enums.iter().find(|e| e.name == name) {
166 return Some(MemberRef::Enum(e));
167 }
168 if let Some((e, v)) = c
171 .enums
172 .iter()
173 .find_map(|e| e.values.iter().find(|v| v.name == name).map(|v| (e, v)))
174 {
175 return Some(MemberRef::EnumValue {
176 class: &c.name,
177 decl: e,
178 value: v,
179 });
180 }
181 cur = c.base;
182 }
183 None
184 }
185
186 #[must_use]
188 pub fn is_subclass(&self, sub: ClassId, sup: ClassId) -> bool {
189 let mut cur = Some(sub);
190 while let Some(cid) = cur {
191 if cid == sup {
192 return true;
193 }
194 cur = self.class(cid).base;
195 }
196 false
197 }
198
199 #[must_use]
202 pub fn members_of(&self, class: ClassId) -> Vec<MemberRef<'_>> {
203 let mut seen: FxHashSet<&str> = FxHashSet::default();
204 let mut out = Vec::new();
205 let mut cur = Some(class);
206 while let Some(cid) = cur {
207 let c = self.class(cid);
208 for m in &c.methods {
209 if seen.insert(&m.name) {
210 out.push(MemberRef::Method(m));
211 }
212 }
213 for p in &c.properties {
214 if seen.insert(&p.name) {
215 out.push(MemberRef::Property(p));
216 }
217 }
218 for s in &c.signals {
219 if seen.insert(&s.name) {
220 out.push(MemberRef::Signal(s));
221 }
222 }
223 for k in &c.constants {
224 if seen.insert(&k.name) {
225 out.push(MemberRef::Const(k));
226 }
227 }
228 for e in &c.enums {
229 if seen.insert(&e.name) {
230 out.push(MemberRef::Enum(e));
231 }
232 for v in &e.values {
235 if seen.insert(&v.name) {
236 out.push(MemberRef::EnumValue {
237 class: &c.name,
238 decl: e,
239 value: v,
240 });
241 }
242 }
243 }
244 cur = c.base;
245 }
246 out
247 }
248
249 #[must_use]
253 pub fn builtin_member(&self, builtin: BuiltinId, name: &str) -> Option<&crate::BuiltinMember> {
254 self.builtin(builtin)
255 .members
256 .iter()
257 .find(|m| m.name == name)
258 }
259
260 #[must_use]
262 pub fn builtin_method(&self, builtin: BuiltinId, name: &str) -> Option<&MethodSig> {
263 self.builtin(builtin)
264 .methods
265 .iter()
266 .find(|m| m.name == name)
267 }
268
269 #[must_use]
271 pub fn builtin_operators(&self, builtin: BuiltinId) -> &[OperatorSig] {
272 &self.builtin(builtin).operators
273 }
274}