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}