Skip to main content

gdscript_api/
model.rs

1//! The normalized in-memory Godot engine model — the shape of `extension_api.json` after
2//! `xtask` has resolved its asymmetries (Playbook §4.1/§4.2).
3//!
4//! [`ApiData`] is the serializable root: a set of flat tables (classes, builtins, …) keyed
5//! by integer ids ([`ClassId`]/[`BuiltinId`]). It is what `xtask codegen-api` `rkyv`-encodes
6//! into the bundled blob, and what [`crate::EngineApi`] deserializes and indexes at load.
7//!
8//! Strings are owned (`String`) rather than interned here: the model is built once and
9//! `Arc`-shared, its names are read by reference and never cloned on a hot path, so interning
10//! buys nothing — `SmolStr` is reserved for `gdscript-hir`, where source names *are* cloned
11//! and compared. Keeping the archived form free of custom string/hash types also keeps the
12//! `rkyv` blob trivially portable.
13
14// `rkyv`'s derive emits public `Archived*` companion types we never name; allowing the
15// missing-Debug lint here keeps it on everywhere else. Our own owned types still derive Debug.
16#![allow(missing_debug_implementations)]
17
18use rkyv::{Archive, Deserialize, Serialize};
19
20/// Index of an engine class in [`ApiData::classes`].
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)]
22pub struct ClassId(pub u32);
23
24/// Index of a builtin (Variant) type in [`ApiData::builtins`].
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)]
26pub struct BuiltinId(pub u32);
27
28/// Index into the [`DocStore`] documentation table. A symbol with no doc text has `doc: None`;
29/// every populated handle addresses a non-empty Markdown entry (Playbook §4.6).
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)]
31pub struct DocId(pub u32);
32
33/// The engine documentation store: per-symbol Markdown doc text addressed by [`DocId`].
34///
35/// Encoded into a **separate** `engine_docs.bin` blob (deliberately *not* a field of [`ApiData`])
36/// and embedded native-only behind the `bundled-docs` feature. This keeps the doc prose out of the
37/// `engine_api.bin` blob the wasm playground `fetch`es — populating the `doc: Option<DocId>` fields
38/// is a fixed-size change to that blob, so the wasm download never grows with the docs (Playbook
39/// §4.6; `crates/gdscript-api/src/lib.rs`).
40#[derive(Debug, Archive, Serialize, Deserialize)]
41pub struct DocStore {
42    /// Markdown entries; `DocId(i)` addresses `entries[i]`. Every entry is non-empty — a symbol
43    /// with no documentation carries `doc: None`, never an index to an empty string.
44    pub entries: Vec<String>,
45}
46
47impl DocStore {
48    /// The Markdown for a doc handle, or `None` if the index is out of range.
49    #[must_use]
50    pub fn get(&self, id: DocId) -> Option<&str> {
51        self.entries.get(id.0 as usize).map(String::as_str)
52    }
53}
54
55/// The Godot version the model was generated from.
56#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
57pub struct ApiVersion {
58    /// Major version (e.g. `4`).
59    pub major: u32,
60    /// Minor version (e.g. `5`).
61    pub minor: u32,
62    /// Patch version (e.g. `0`).
63    pub patch: u32,
64    /// Release status (e.g. `stable`).
65    pub status: String,
66}
67
68/// Whether a symbol is part of the runtime API or editor-only (Playbook §4.2 — gate
69/// editor-only symbols out of runtime completion).
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Archive, Serialize, Deserialize)]
71pub enum ApiType {
72    /// Available at runtime.
73    Core,
74    /// Editor-only.
75    Editor,
76}
77
78/// The element type of a typed container. Non-recursive on purpose: Phase 2 does not track
79/// nested element types, so a nested typed container (`Array[Array[int]]`) collapses to its
80/// bare builtin (`Array`) here (Playbook §2). Keeping this flat also keeps the `rkyv` archive
81/// free of recursive `Box` bounds.
82#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
83pub enum ElemRef {
84    /// The dynamic `Variant` top type (a bare container's element).
85    Variant,
86    /// A builtin Variant type (includes bare `Array`/`Dictionary` collapsed from nesting).
87    Builtin(BuiltinId),
88    /// An engine class.
89    Class(ClassId),
90    /// `enum::…` / `bitfield::…` — kept qualified.
91    Enum {
92        /// The dotted name as written after `enum::`/`bitfield::`.
93        qualified: String,
94        /// Whether the source prefix was `bitfield::`.
95        bitfield: bool,
96    },
97}
98
99/// An unresolved API type reference, parsed from the `extension_api.json` type-string grammar
100/// (Playbook §4.2). `Builtin`/`Class` are already resolved to ids at codegen time (second
101/// pass, after the name tables are built); `Enum` keeps its qualified string for `gdscript-hir`
102/// to resolve against a class's / the global enum set.
103#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
104pub enum TyRef {
105    /// No value (`void` return).
106    Void,
107    /// The dynamic `Variant` top type.
108    Variant,
109    /// A builtin Variant type.
110    Builtin(BuiltinId),
111    /// An engine class.
112    Class(ClassId),
113    /// `typedarray::T` → `Array[T]`.
114    TypedArray(ElemRef),
115    /// `typeddictionary::K::V` → `Dictionary[K, V]`.
116    TypedDict(ElemRef, ElemRef),
117    /// `enum::Class.Enum`, `enum::GlobalEnum`, or `bitfield::…` — kept qualified.
118    Enum {
119        /// The dotted name as written after `enum::`/`bitfield::`.
120        qualified: String,
121        /// Whether the source prefix was `bitfield::`.
122        bitfield: bool,
123    },
124}
125
126/// A function/method parameter.
127#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
128pub struct Param {
129    /// The parameter name.
130    pub name: String,
131    /// The parameter type.
132    pub ty: TyRef,
133    /// The default-value **source string** (e.g. `"Vector2(0, 0)"`), displayed verbatim and
134    /// never evaluated (Playbook §4.2). `None` when the parameter is required.
135    pub default: Option<String>,
136}
137
138/// A method signature (engine class method, builtin method, or — without the receiver — a
139/// utility function shares the same shape via [`UtilityFn`]).
140// The four `is_*` flags faithfully mirror the engine's per-method flags; folding them into a
141// bitfield would only obscure that one-to-one mapping.
142#[allow(clippy::struct_excessive_bools)]
143#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
144pub struct MethodSig {
145    /// The method name.
146    pub name: String,
147    /// The parameters, in order.
148    pub params: Vec<Param>,
149    /// The return type (`Void` when the source had no return field).
150    pub return_ty: TyRef,
151    /// `const` (does not mutate the receiver).
152    pub is_const: bool,
153    /// A `static` method (callable on the type).
154    pub is_static: bool,
155    /// Accepts a variable number of trailing arguments.
156    pub is_vararg: bool,
157    /// A virtual method (a `_`-prefixed hook the user overrides).
158    pub is_virtual: bool,
159    /// Documentation handle, when the doc store is populated.
160    pub doc: Option<DocId>,
161}
162
163/// A class property. `enum_of` carries the qualified enum name recovered from the property's
164/// getter (Playbook §4.2 — the JSON reports an enum property's storage type as `int`, but its
165/// getter's return type is `enum::…`).
166#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
167pub struct PropertyInfo {
168    /// The property name.
169    pub name: String,
170    /// The storage type as reported by the JSON (`int` for enum properties).
171    pub ty: TyRef,
172    /// The setter method name, if any.
173    pub setter: Option<String>,
174    /// The getter method name, if any.
175    pub getter: Option<String>,
176    /// The qualified enum name when this property is actually enum-typed (from the getter).
177    pub enum_of: Option<String>,
178    /// Documentation handle, when the doc store is populated.
179    pub doc: Option<DocId>,
180}
181
182/// A signal declaration.
183#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
184pub struct SignalSig {
185    /// The signal name.
186    pub name: String,
187    /// The signal parameters, in order.
188    pub params: Vec<Param>,
189    /// Documentation handle, when the doc store is populated.
190    pub doc: Option<DocId>,
191}
192
193/// One named enum value.
194#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
195pub struct EnumValue {
196    /// The value name (e.g. `SIDE_LEFT`).
197    pub name: String,
198    /// The integer value.
199    pub value: i64,
200}
201
202/// An enum (class enum, builtin enum, or global enum).
203#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
204pub struct EnumInfo {
205    /// The enum name (unqualified).
206    pub name: String,
207    /// Whether the enum is a bitfield (flags).
208    pub is_bitfield: bool,
209    /// The enum values, in declaration order.
210    pub values: Vec<EnumValue>,
211    /// Documentation handle, when the doc store is populated.
212    pub doc: Option<DocId>,
213}
214
215/// A constant. Engine-class constants are integers (notification/flag values); builtin
216/// constants carry a typed source-literal expression (`Vector2(0, 0)`).
217#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
218pub struct ConstInfo {
219    /// The constant name.
220    pub name: String,
221    /// The constant type (`Builtin(int)` for engine-class integer constants).
222    pub ty: TyRef,
223    /// The integer value, for engine-class constants.
224    pub int_value: Option<i64>,
225    /// The source-literal expression, for builtin constants (displayed verbatim).
226    pub value_expr: Option<String>,
227    /// Documentation handle, when the doc store is populated.
228    pub doc: Option<DocId>,
229}
230
231/// An engine class and its members.
232#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
233pub struct ClassData {
234    /// The class name.
235    pub name: String,
236    /// The resolved base class, if any (only `Object` has none).
237    pub base: Option<ClassId>,
238    /// Whether instances are reference-counted (`RefCounted` subtree).
239    pub is_refcounted: bool,
240    /// Whether the class can be instantiated directly.
241    pub is_instantiable: bool,
242    /// Runtime vs. editor-only.
243    pub api_type: ApiType,
244    /// Declared methods (not including inherited).
245    pub methods: Vec<MethodSig>,
246    /// Declared properties.
247    pub properties: Vec<PropertyInfo>,
248    /// Declared signals.
249    pub signals: Vec<SignalSig>,
250    /// Nested enums.
251    pub enums: Vec<EnumInfo>,
252    /// Integer constants.
253    pub constants: Vec<ConstInfo>,
254    /// Documentation handle, when the doc store is populated.
255    pub doc: Option<DocId>,
256}
257
258/// One field of a builtin Variant type (e.g. `Vector2.x`).
259#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
260pub struct BuiltinMember {
261    /// The member name.
262    pub name: String,
263    /// The member type.
264    pub ty: TyRef,
265}
266
267/// A builtin-type operator overload. `right` is `None` for unary operators (`unary-`, `not`).
268#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
269pub struct OperatorSig {
270    /// The operator token as the JSON spells it (`+`, `==`, `unary-`, `and`, …).
271    pub op: String,
272    /// The right-hand operand type, or `None` for a unary operator.
273    pub right: Option<TyRef>,
274    /// The result type.
275    pub result: TyRef,
276}
277
278/// A builtin (Variant) type and its members.
279#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
280pub struct BuiltinData {
281    /// The builtin type name (`Vector2`, `String`, …).
282    pub name: String,
283    /// Named fields (`Vector2.x`).
284    pub members: Vec<BuiltinMember>,
285    /// Methods.
286    pub methods: Vec<MethodSig>,
287    /// Named constants (`Vector2.ZERO`).
288    pub constants: Vec<ConstInfo>,
289    /// Nested enums (`Vector2.Axis`).
290    pub enums: Vec<EnumInfo>,
291    /// Operator overloads.
292    pub operators: Vec<OperatorSig>,
293    /// The element type yielded by `[]` indexing, if the type is indexable.
294    pub indexing_return: Option<TyRef>,
295    /// Whether the type is keyed (dictionary-like indexing).
296    pub is_keyed: bool,
297    /// Documentation handle, when the doc store is populated.
298    pub doc: Option<DocId>,
299}
300
301/// A `@GlobalScope` utility function (`sin`, `print`, `range`, …).
302#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
303pub struct UtilityFn {
304    /// The function name.
305    pub name: String,
306    /// The parameters, in order.
307    pub params: Vec<Param>,
308    /// The return type.
309    pub return_ty: TyRef,
310    /// Accepts a variable number of trailing arguments.
311    pub is_vararg: bool,
312    /// The JSON `category` (`math`, `random`, `general`).
313    pub category: String,
314    /// Documentation handle, when the doc store is populated.
315    pub doc: Option<DocId>,
316}
317
318/// The serializable engine-model root: flat tables addressed by [`ClassId`]/[`BuiltinId`].
319/// `xtask codegen-api` builds this from `extension_api.json` and `rkyv`-encodes it; the name
320/// indices are rebuilt at load by [`crate::EngineApi`], so they are intentionally absent here.
321#[derive(Debug, Archive, Serialize, Deserialize)]
322pub struct ApiData {
323    /// The source Godot version.
324    pub version: ApiVersion,
325    /// All engine classes, in `extension_api.json` order (alphabetical).
326    pub classes: Vec<ClassData>,
327    /// All builtin Variant types.
328    pub builtins: Vec<BuiltinData>,
329    /// Singletons: `(symbol name, the class it is an instance of)`.
330    pub singletons: Vec<(String, ClassId)>,
331    /// `@GlobalScope` utility functions.
332    pub utilities: Vec<UtilityFn>,
333    /// Global (`@GlobalScope`) enums.
334    pub global_enums: Vec<EnumInfo>,
335}