Skip to content

Commit 97ec8f1

Browse files
bors[bot]ttencatelilizoeyMercerenies
authored
Merge #252 #262 #266
252: Implement `#[func]` for static functions r=Bromeon a=lilizoey Takes over from #210 Adds support for static methods in classes. also replaces tabs with spaces in `signature.rs`. thanks a lot to `@ttencate!` it was very straightforward to make this work based on what they'd already done. from what i can tell, there are no static virtual methods. so we dont need to implement support for that. im not sure if there ever will be but it doesn't seem likely to me at least. it might be worth it to move more of this logic into procedural macros eventually. closes #175 262: Correct documentation on Array r=Bromeon a=Mercerenies Per #151, the struct `TypedArray` has been renamed. This MR updates stale documentation to reflect the new naming scheme. 266: Improve `cargo check` times for incremental changes to `godot-core` r=Bromeon a=lilizoey On my machine, this change makes the time `cargo check` takes to run go from 48 seconds to 11 seconds when making an incremental change to `godot-core`. in this case tested by adding/removing a single method to/from `Basis`. I've seen it be as low as 2 seconds sometimes but im not entirely sure why that happens. Co-authored-by: Thomas ten Cate <[email protected]> Co-authored-by: Lili Zoey <[email protected]> Co-authored-by: Silvio Mayolo <[email protected]>
4 parents 645673a + 422faba + bb004b5 + 78294a5 commit 97ec8f1

File tree

11 files changed

+340
-189
lines changed

11 files changed

+340
-189
lines changed

godot-codegen/src/class_generator.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
294294
#![doc = #module_doc]
295295

296296
use godot_ffi as sys;
297-
use crate::engine::*;
298297
use crate::engine::notify::*;
299298
use crate::builtin::*;
300299
use crate::obj::{AsArg, Gd};

godot-codegen/src/util.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,15 +283,15 @@ fn to_rust_type_uncached(ty: &str, ctx: &mut Context) -> RustTy {
283283
let enum_ty = make_enum_name(enum_);
284284

285285
RustTy::EngineEnum {
286-
tokens: quote! { #module::#enum_ty },
286+
tokens: quote! { crate::engine::#module::#enum_ty },
287287
surrounding_class: Some(class.to_string()),
288288
}
289289
} else {
290290
// Global enum
291291
let enum_ty = make_enum_name(qualified_enum);
292292

293293
RustTy::EngineEnum {
294-
tokens: quote! { global::#enum_ty },
294+
tokens: quote! { crate::engine::global::#enum_ty },
295295
surrounding_class: None,
296296
}
297297
};
@@ -323,7 +323,7 @@ fn to_rust_type_uncached(ty: &str, ctx: &mut Context) -> RustTy {
323323
} else {
324324
let ty = rustify_ty(ty);
325325
RustTy::EngineClass {
326-
tokens: quote! { Gd<#ty> },
326+
tokens: quote! { Gd<crate::engine::#ty> },
327327
class: ty.to_string(),
328328
}
329329
}

godot-core/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ fn main() {
1616
}
1717

1818
godot_codegen::generate_core_files(gen_path);
19+
println!("cargo:rerun-if-changed=build.rs");
1920
}

godot-core/src/builtin/array.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ use sys::{ffi_methods, interface_fn, GodotFfi};
2222
/// Godot's `Array` can be either typed or untyped.
2323
///
2424
/// An untyped array can contain any kind of [`Variant`], even different types in the same array.
25-
/// We represent this in Rust as `Array`, which is just a type alias for `TypedArray<Variant>`.
25+
/// We represent this in Rust as `VariantArray`, which is just a type alias for `Array<Variant>`.
2626
///
2727
/// Godot also supports typed arrays, which are also just `Variant` arrays under the hood, but with
2828
/// runtime checks that no values of the wrong type are put into the array. We represent this as
29-
/// `TypedArray<T>`, where the type `T` implements `VariantMetadata`, `FromVariant` and `ToVariant`.
29+
/// `Array<T>`, where the type `T` implements `VariantMetadata`, `FromVariant` and `ToVariant`.
3030
///
3131
/// # Reference semantics
3232
///

godot-core/src/builtin/meta/signature.rs

Lines changed: 73 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,7 @@ pub trait SignatureTuple {
2222
args_ptr: *const sys::GDExtensionConstVariantPtr,
2323
ret: sys::GDExtensionVariantPtr,
2424
err: *mut sys::GDExtensionCallError,
25-
func: fn(&C, Self::Params) -> Self::Ret,
26-
method_name: &str,
27-
);
28-
29-
unsafe fn varcall_mut<C: GodotClass>(
30-
instance_ptr: sys::GDExtensionClassInstancePtr,
31-
args_ptr: *const sys::GDExtensionConstVariantPtr,
32-
ret: sys::GDExtensionVariantPtr,
33-
err: *mut sys::GDExtensionCallError,
34-
func: fn(&mut C, Self::Params) -> Self::Ret,
25+
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
3526
method_name: &str,
3627
);
3728

@@ -41,18 +32,7 @@ pub trait SignatureTuple {
4132
instance_ptr: sys::GDExtensionClassInstancePtr,
4233
args_ptr: *const sys::GDExtensionConstTypePtr,
4334
ret: sys::GDExtensionTypePtr,
44-
func: fn(&C, Self::Params) -> Self::Ret,
45-
method_name: &str,
46-
call_type: sys::PtrcallType,
47-
);
48-
49-
// Note: this method imposes extra bounds on GodotFfi, which may not be implemented for user types.
50-
// We could fall back to varcalls in such cases, and not require GodotFfi categorically.
51-
unsafe fn ptrcall_mut<C: GodotClass>(
52-
instance_ptr: sys::GDExtensionClassInstancePtr,
53-
args_ptr: *const sys::GDExtensionConstTypePtr,
54-
ret: sys::GDExtensionTypePtr,
55-
func: fn(&mut C, Self::Params) -> Self::Ret,
35+
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
5636
method_name: &str,
5737
call_type: sys::PtrcallType,
5838
);
@@ -127,133 +107,104 @@ macro_rules! impl_signature_for_tuple {
127107

128108
#[inline]
129109
unsafe fn varcall<C : GodotClass>(
130-
instance_ptr: sys::GDExtensionClassInstancePtr,
131-
args_ptr: *const sys::GDExtensionConstVariantPtr,
132-
ret: sys::GDExtensionVariantPtr,
133-
err: *mut sys::GDExtensionCallError,
134-
func: fn(&C, Self::Params) -> Self::Ret,
135-
method_name: &str,
136-
) {
137-
$crate::out!("varcall: {}", method_name);
138-
139-
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
140-
let instance = storage.get();
141-
142-
let args = ( $(
143-
{
144-
let variant = unsafe { &*(*args_ptr.offset($n) as *mut Variant) }; // TODO from_var_sys
145-
let arg = <$Pn as FromVariant>::try_from_variant(variant)
146-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, variant));
147-
148-
arg
149-
},
150-
)* );
151-
152-
let ret_val = func(&*instance, args);
153-
let ret_variant = <$R as ToVariant>::to_variant(&ret_val); // TODO write_sys
154-
unsafe {
155-
*(ret as *mut Variant) = ret_variant;
156-
(*err).error = sys::GDEXTENSION_CALL_OK;
157-
}
158-
}
159-
160-
#[inline]
161-
unsafe fn varcall_mut<C : GodotClass>(
162-
instance_ptr: sys::GDExtensionClassInstancePtr,
110+
instance_ptr: sys::GDExtensionClassInstancePtr,
163111
args_ptr: *const sys::GDExtensionConstVariantPtr,
164112
ret: sys::GDExtensionVariantPtr,
165113
err: *mut sys::GDExtensionCallError,
166-
func: fn(&mut C, Self::Params) -> Self::Ret,
114+
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
167115
method_name: &str,
168116
) {
169-
$crate::out!("varcall: {}", method_name);
170-
171-
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
172-
let mut instance = storage.get_mut();
117+
$crate::out!("varcall: {}", method_name);
173118

174-
let args = ( $(
175-
{
176-
let variant = unsafe { &*(*args_ptr.offset($n) as *mut Variant) }; // TODO from_var_sys
177-
let arg = <$Pn as FromVariant>::try_from_variant(variant)
178-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, variant));
119+
let args = ($(
120+
unsafe { varcall_arg::<$Pn, $n>(args_ptr, method_name) },
121+
)*) ;
179122

180-
arg
181-
},
182-
)* );
183-
184-
let ret_val = func(&mut *instance, args);
185-
let ret_variant = <$R as ToVariant>::to_variant(&ret_val); // TODO write_sys
186-
unsafe {
187-
*(ret as *mut Variant) = ret_variant;
188-
(*err).error = sys::GDEXTENSION_CALL_OK;
189-
}
123+
varcall_return::<$R>(func(instance_ptr, args), ret, err)
190124
}
191125

192126
#[inline]
193127
unsafe fn ptrcall<C : GodotClass>(
194-
instance_ptr: sys::GDExtensionClassInstancePtr,
128+
instance_ptr: sys::GDExtensionClassInstancePtr,
195129
args_ptr: *const sys::GDExtensionConstTypePtr,
196130
ret: sys::GDExtensionTypePtr,
197-
func: fn(&C, Self::Params) -> Self::Ret,
131+
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
198132
method_name: &str,
199133
call_type: sys::PtrcallType,
200134
) {
201135
$crate::out!("ptrcall: {}", method_name);
202136

203-
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
204-
let instance = storage.get();
205-
206-
let args = ( $(
207-
unsafe {
208-
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
209-
sys::force_mut_ptr(*args_ptr.offset($n)),
210-
call_type
211-
)
212-
}
213-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
214-
)* );
137+
let args = ($(
138+
unsafe { ptrcall_arg::<$Pn, $n>(args_ptr, method_name, call_type) },
139+
)*) ;
215140

216-
let ret_val = func(&*instance, args);
217141
// SAFETY:
218142
// `ret` is always a pointer to an initialized value of type $R
219143
// TODO: double-check the above
220-
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
221-
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
144+
ptrcall_return::<$R>(func(instance_ptr, args), ret, method_name, call_type)
222145
}
146+
}
147+
};
148+
}
223149

224-
#[inline]
225-
unsafe fn ptrcall_mut<C : GodotClass>(
226-
instance_ptr: sys::GDExtensionClassInstancePtr,
227-
args_ptr: *const sys::GDExtensionConstTypePtr,
228-
ret: sys::GDExtensionTypePtr,
229-
func: fn(&mut C, Self::Params) -> Self::Ret,
230-
method_name: &str,
231-
call_type: sys::PtrcallType,
232-
) {
233-
$crate::out!("ptrcall: {}", method_name);
150+
/// Convert the `N`th argument of `args_ptr` into a value of type `P`.
151+
///
152+
/// # Safety
153+
/// - It must be safe to dereference the pointer at `args_ptr.offset(N)` .
154+
unsafe fn varcall_arg<P: FromVariant, const N: isize>(
155+
args_ptr: *const sys::GDExtensionConstVariantPtr,
156+
method_name: &str,
157+
) -> P {
158+
let variant = &*(*args_ptr.offset(N) as *mut Variant); // TODO from_var_sys
159+
P::try_from_variant(variant)
160+
.unwrap_or_else(|_| param_error::<P>(method_name, N as i32, variant))
161+
}
234162

235-
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
236-
let mut instance = storage.get_mut();
163+
/// Moves `ret_val` into `ret`.
164+
///
165+
/// # Safety
166+
/// - `ret` must be a pointer to an initialized `Variant`.
167+
/// - It must be safe to write a `Variant` once to `ret`.
168+
/// - It must be safe to write a `sys::GDExtensionCallError` once to `err`.
169+
unsafe fn varcall_return<R: ToVariant>(
170+
ret_val: R,
171+
ret: sys::GDExtensionConstVariantPtr,
172+
err: *mut sys::GDExtensionCallError,
173+
) {
174+
let ret_variant = ret_val.to_variant(); // TODO write_sys
175+
*(ret as *mut Variant) = ret_variant;
176+
(*err).error = sys::GDEXTENSION_CALL_OK;
177+
}
237178

238-
let args = ( $(
239-
unsafe {
240-
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
241-
sys::force_mut_ptr(*args_ptr.offset($n)),
242-
call_type
243-
)
244-
}
245-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
246-
)* );
179+
/// Convert the `N`th argument of `args_ptr` into a value of type `P`.
180+
///
181+
/// # Safety
182+
/// - It must be safe to dereference the address at `args_ptr.offset(N)` .
183+
/// - The pointer at `args_ptr.offset(N)` must follow the safety requirements as laid out in
184+
/// [`GodotFuncMarshal::try_from_arg`][sys::GodotFuncMarshal::try_from_arg].
185+
unsafe fn ptrcall_arg<P: sys::GodotFuncMarshal, const N: isize>(
186+
args_ptr: *const sys::GDExtensionConstTypePtr,
187+
method_name: &str,
188+
call_type: sys::PtrcallType,
189+
) -> P {
190+
P::try_from_arg(sys::force_mut_ptr(*args_ptr.offset(N)), call_type)
191+
.unwrap_or_else(|e| param_error::<P>(method_name, N as i32, &e))
192+
}
247193

248-
let ret_val = func(&mut *instance, args);
249-
// SAFETY:
250-
// `ret` is always a pointer to an initialized value of type $R
251-
// TODO: double-check the above
252-
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
253-
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
254-
}
255-
}
256-
};
194+
/// Moves `ret_val` into `ret`.
195+
///
196+
/// # Safety
197+
/// `ret_val`, `ret`, and `call_type` must follow the safety requirements as laid out in
198+
/// [`GodotFuncMarshal::try_return`](sys::GodotFuncMarshal::try_return).
199+
unsafe fn ptrcall_return<R: sys::GodotFuncMarshal + std::fmt::Debug>(
200+
ret_val: R,
201+
ret: sys::GDExtensionTypePtr,
202+
method_name: &str,
203+
call_type: sys::PtrcallType,
204+
) {
205+
ret_val
206+
.try_return(ret, call_type)
207+
.unwrap_or_else(|ret_val| return_error::<R>(method_name, &ret_val))
257208
}
258209

259210
fn param_error<P>(method_name: &str, index: i32, arg: &impl Debug) -> ! {

0 commit comments

Comments
 (0)