use crate::EngineApi;
use crate::gdscript_layer::{BuiltinFn, GlobalConst};
use crate::model::{
BuiltinData, BuiltinId, ClassData, ClassId, ConstInfo, EnumInfo, MethodSig, OperatorSig,
PropertyInfo, SignalSig, UtilityFn,
};
use rustc_hash::FxHashSet;
#[derive(Debug, Clone, Copy)]
pub enum MemberRef<'a> {
Method(&'a MethodSig),
Property(&'a PropertyInfo),
Signal(&'a SignalSig),
Const(&'a ConstInfo),
Enum(&'a EnumInfo),
}
impl MemberRef<'_> {
#[must_use]
pub fn name(&self) -> &str {
match self {
Self::Method(m) => &m.name,
Self::Property(p) => &p.name,
Self::Signal(s) => &s.name,
Self::Const(c) => &c.name,
Self::Enum(e) => &e.name,
}
}
}
impl EngineApi {
#[must_use]
pub fn classes(&self) -> &[ClassData] {
&self.data.classes
}
#[must_use]
pub fn builtins(&self) -> &[BuiltinData] {
&self.data.builtins
}
#[must_use]
pub fn class(&self, id: ClassId) -> &ClassData {
&self.data.classes[id.0 as usize]
}
#[must_use]
pub fn builtin(&self, id: BuiltinId) -> &BuiltinData {
&self.data.builtins[id.0 as usize]
}
#[must_use]
pub fn class_by_name(&self, name: &str) -> Option<ClassId> {
self.class_by_name.get(name).copied()
}
#[must_use]
pub fn builtin_by_name(&self, name: &str) -> Option<BuiltinId> {
self.builtin_by_name.get(name).copied()
}
#[must_use]
pub fn int_builtin(&self) -> Option<BuiltinId> {
self.int_builtin
}
#[must_use]
pub fn singleton(&self, name: &str) -> Option<ClassId> {
self.singleton_by_name.get(name).copied()
}
#[must_use]
pub fn utility(&self, name: &str) -> Option<&UtilityFn> {
let i = *self.utility_by_name.get(name)?;
self.data.utilities.get(i as usize)
}
#[must_use]
pub fn global_enum(&self, name: &str) -> Option<&EnumInfo> {
let i = *self.global_enum_by_name.get(name)?;
self.data.global_enums.get(i as usize)
}
#[must_use]
pub fn global_const(&self, name: &str) -> Option<&GlobalConst> {
self.global_consts.iter().find(|c| c.name == name)
}
#[must_use]
pub fn gdscript_builtin(&self, name: &str) -> Option<&BuiltinFn> {
self.gdscript_builtins.iter().find(|f| f.name == name)
}
#[must_use]
pub fn lookup_member(&self, class: ClassId, name: &str) -> Option<MemberRef<'_>> {
let mut cur = Some(class);
while let Some(cid) = cur {
let c = self.class(cid);
if let Some(m) = c.methods.iter().find(|m| m.name == name) {
return Some(MemberRef::Method(m));
}
if let Some(p) = c.properties.iter().find(|p| p.name == name) {
return Some(MemberRef::Property(p));
}
if let Some(s) = c.signals.iter().find(|s| s.name == name) {
return Some(MemberRef::Signal(s));
}
if let Some(k) = c.constants.iter().find(|k| k.name == name) {
return Some(MemberRef::Const(k));
}
if let Some(e) = c.enums.iter().find(|e| e.name == name) {
return Some(MemberRef::Enum(e));
}
cur = c.base;
}
None
}
#[must_use]
pub fn is_subclass(&self, sub: ClassId, sup: ClassId) -> bool {
let mut cur = Some(sub);
while let Some(cid) = cur {
if cid == sup {
return true;
}
cur = self.class(cid).base;
}
false
}
#[must_use]
pub fn members_of(&self, class: ClassId) -> Vec<MemberRef<'_>> {
let mut seen: FxHashSet<&str> = FxHashSet::default();
let mut out = Vec::new();
let mut cur = Some(class);
while let Some(cid) = cur {
let c = self.class(cid);
for m in &c.methods {
if seen.insert(&m.name) {
out.push(MemberRef::Method(m));
}
}
for p in &c.properties {
if seen.insert(&p.name) {
out.push(MemberRef::Property(p));
}
}
for s in &c.signals {
if seen.insert(&s.name) {
out.push(MemberRef::Signal(s));
}
}
for k in &c.constants {
if seen.insert(&k.name) {
out.push(MemberRef::Const(k));
}
}
for e in &c.enums {
if seen.insert(&e.name) {
out.push(MemberRef::Enum(e));
}
}
cur = c.base;
}
out
}
#[must_use]
pub fn builtin_member(&self, builtin: BuiltinId, name: &str) -> Option<&crate::BuiltinMember> {
self.builtin(builtin)
.members
.iter()
.find(|m| m.name == name)
}
#[must_use]
pub fn builtin_method(&self, builtin: BuiltinId, name: &str) -> Option<&MethodSig> {
self.builtin(builtin)
.methods
.iter()
.find(|m| m.name == name)
}
#[must_use]
pub fn builtin_operators(&self, builtin: BuiltinId) -> &[OperatorSig] {
&self.builtin(builtin).operators
}
}