@@ -14,15 +14,15 @@ use quote::{quote, ToTokens};
1414
1515use crate :: context:: Context ;
1616use crate :: conv;
17- use crate :: models:: domain:: { ArgPassing , GodotTy , ModName , RustTy , TyName } ;
17+ use crate :: models:: domain:: { ArgPassing , FlowDirection , GodotTy , ModName , RustTy , TyName } ;
1818use crate :: special_cases:: is_builtin_type_scalar;
1919use crate :: util:: ident;
2020
2121// ----------------------------------------------------------------------------------------------------------------------------------------------
2222// Godot -> Rust types
2323
2424/// Returns `(identifier, is_copy)` for a hardcoded Rust type, if it exists.
25- fn to_hardcoded_rust_ident ( full_ty : & GodotTy ) -> Option < & str > {
25+ fn to_hardcoded_rust_ident ( full_ty : & GodotTy ) -> Option < Ident > {
2626 let ty = full_ty. ty . as_str ( ) ;
2727 let meta = full_ty. meta . as_deref ( ) ;
2828
@@ -53,7 +53,14 @@ fn to_hardcoded_rust_ident(full_ty: &GodotTy) -> Option<&str> {
5353 // Others
5454 ( "bool" , None ) => "bool" ,
5555 ( "String" , None ) => "GString" ,
56- ( "Array" , None ) => "VariantArray" ,
56+
57+ // Must remain "Array" because this is checked verbatim for later adjustments (e.g. to AnyArray).
58+ // Keep also in line with default-exprs e.g. `Array::new()`.
59+ ( "Array" , None ) => match full_ty. flow {
60+ Some ( FlowDirection :: RustToGodot ) => "AnyArray" ,
61+ Some ( FlowDirection :: GodotToRust ) => "VariantArray" ,
62+ None => "_unused__Array_must_not_appear_in_idents" ,
63+ } ,
5764
5865 // Types needed for native structures mapping
5966 ( "uint8_t" , None ) => "u8" ,
@@ -76,10 +83,10 @@ fn to_hardcoded_rust_ident(full_ty: &GodotTy) -> Option<&str> {
7683 _ => return None ,
7784 } ;
7885
79- Some ( result)
86+ Some ( ident ( result) )
8087}
8188
82- fn to_hardcoded_rust_enum ( ty : & str ) -> Option < & str > {
89+ fn to_hardcoded_rust_enum ( ty : & str ) -> Option < Ident > {
8390 // Some types like Vector2[i].Axis may not appear in Godot's current JSON, but they are encountered
8491 // in custom Godot builds, e.g. when extending PhysicsServer2D.
8592 let result = match ty {
@@ -92,7 +99,8 @@ fn to_hardcoded_rust_enum(ty: &str) -> Option<&str> {
9299 "enum::Vector3i.Axis" => "Vector3Axis" ,
93100 _ => return None ,
94101 } ;
95- Some ( result)
102+
103+ Some ( ident ( result) )
96104}
97105
98106/// Maps an input type to a Godot type with the same C representation. This is subtly different from [`to_rust_type`],
@@ -124,7 +132,7 @@ pub(crate) fn to_rust_type_abi(ty: &str, ctx: &mut Context) -> (RustTy, bool) {
124132 ty : ident ( "f64" ) ,
125133 arg_passing : ArgPassing :: ByValue ,
126134 } ,
127- _ => to_rust_type ( ty, None , ctx) ,
135+ _ => to_rust_temporary_type ( ty, ctx) ,
128136 } ;
129137
130138 ( ty, is_obj)
@@ -134,14 +142,28 @@ pub(crate) fn to_rust_type_abi(ty: &str, ctx: &mut Context) -> (RustTy, bool) {
134142///
135143/// Uses an internal cache (via `ctx`), as several types are ubiquitous.
136144// TODO take TyName as input
137- pub ( crate ) fn to_rust_type < ' a > ( ty : & ' a str , meta : Option < & ' a String > , ctx : & mut Context ) -> RustTy {
145+ pub ( crate ) fn to_rust_type < ' a > (
146+ json_ty : & ' a str ,
147+ meta : Option < & ' a String > ,
148+ flow : Option < FlowDirection > ,
149+ ctx : & mut Context ,
150+ ) -> RustTy {
151+ // Flow: don't-care for everything besides GDScript types Array or Array[Array].
152+ // Do not panic if not set (used in to_temporary_rust_type()).
153+ let flow = if json_ty == "Array" || json_ty == "typedarray::Array" {
154+ flow
155+ } else {
156+ None
157+ } ;
158+
138159 let full_ty = GodotTy {
139- ty : ty . to_string ( ) ,
160+ ty : json_ty . to_string ( ) ,
140161 meta : meta. cloned ( ) ,
162+ flow,
141163 } ;
142164
143- // Separate find + insert slightly slower, but much easier with lifetimes
144- // The insert path will be hit less often and thus doesn't matter
165+ // Separate find + insert slightly slower, but much easier with lifetimes.
166+ // The insert path will be hit less often and thus doesn't matter.
145167 if let Some ( rust_ty) = ctx. find_rust_type ( & full_ty) {
146168 rust_ty. clone ( )
147169 } else {
@@ -151,6 +173,17 @@ pub(crate) fn to_rust_type<'a>(ty: &'a str, meta: Option<&'a String>, ctx: &mut
151173 }
152174}
153175
176+ /// Converts a Godot type to a Rust type without caching, suitable for cases where only parts of the returned RustTy are needed.
177+ ///
178+ /// This is a lightweight alternative to [`to_rust_type()`] for scenarios where only parts of the returned `RustTy` are needed (e.g.
179+ /// just the identifier name).
180+ ///
181+ /// The returned type may have inaccuracies in fields that depend on metad or flow direction, so this should only be used when
182+ /// those fields are not needed. This allows for simpler call sites in code that doesn't require complete type information.
183+ pub ( crate ) fn to_rust_temporary_type ( ty : & str , ctx : & mut Context ) -> RustTy {
184+ to_rust_type ( ty, None , None , ctx)
185+ }
186+
154187fn to_rust_type_uncached ( full_ty : & GodotTy , ctx : & mut Context ) -> RustTy {
155188 let ty = full_ty. ty . as_str ( ) ;
156189
@@ -188,7 +221,7 @@ fn to_rust_type_uncached(full_ty: &GodotTy, ctx: &mut Context) -> RustTy {
188221
189222 // .trim() is necessary here, as Godot places a space between a type and the stars when representing a double pointer.
190223 // Example: "int*" but "int **".
191- let inner_type = to_rust_type ( ty. trim ( ) , None , ctx) ;
224+ let inner_type = to_rust_type ( ty. trim ( ) , None , None , ctx) ;
192225 return RustTy :: RawPointer {
193226 inner : Box :: new ( inner_type) ,
194227 is_const,
@@ -199,15 +232,15 @@ fn to_rust_type_uncached(full_ty: &GodotTy, ctx: &mut Context) -> RustTy {
199232 if !ty. starts_with ( "typedarray::" ) {
200233 if let Some ( hardcoded) = to_hardcoded_rust_ident ( full_ty) {
201234 return RustTy :: BuiltinIdent {
202- ty : ident ( hardcoded) ,
235+ ty : hardcoded,
203236 arg_passing : ctx. get_builtin_arg_passing ( full_ty) ,
204237 } ;
205238 }
206239 }
207240
208241 if let Some ( hardcoded) = to_hardcoded_rust_enum ( ty) {
209242 return RustTy :: EngineEnum {
210- tokens : ident ( hardcoded) . to_token_stream ( ) ,
243+ tokens : hardcoded. to_token_stream ( ) ,
211244 surrounding_class : None , // would need class passed in
212245 is_bitfield : false ,
213246 } ;
@@ -226,7 +259,7 @@ fn to_rust_type_uncached(full_ty: &GodotTy, ctx: &mut Context) -> RustTy {
226259 } ;
227260 }
228261 } else if let Some ( elem_ty) = ty. strip_prefix ( "typedarray::" ) {
229- let rust_elem_ty = to_rust_type ( elem_ty, full_ty. meta . as_ref ( ) , ctx) ;
262+ let rust_elem_ty = to_rust_type ( elem_ty, full_ty. meta . as_ref ( ) , full_ty . flow , ctx) ;
230263 return if ctx. is_builtin ( elem_ty) {
231264 RustTy :: BuiltinArray {
232265 elem_type : quote ! { Array <#rust_elem_ty> } ,
@@ -331,6 +364,9 @@ fn to_rust_expr_inner(expr: &str, ty: &RustTy, is_inner: bool) -> TokenStream {
331364 "true" => return quote ! { true } ,
332365 "false" => return quote ! { false } ,
333366 "[]" | "{}" if is_inner => return quote ! { } ,
367+ "[]" if matches ! ( ty, RustTy :: BuiltinIdent { ty, .. } if ty == "AnyArray" ) => {
368+ return quote ! { AnyArray :: new_untyped( ) }
369+ }
334370 "[]" => return quote ! { Array :: new( ) } , // VariantArray or Array<T>
335371 "{}" => return quote ! { Dictionary :: new( ) } ,
336372 "null" => {
0 commit comments