Skip to content

Commit a8eb3da

Browse files
committed
Add cargo features to configure safety checks
1 parent 97259b6 commit a8eb3da

File tree

20 files changed

+102
-45
lines changed

20 files changed

+102
-45
lines changed

godot-bindings/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ api-custom = ["dep:bindgen", "dep:regex", "dep:which"]
3232
api-custom-json = ["dep:nanoserde", "dep:bindgen", "dep:regex", "dep:which"]
3333
api-custom-extheader = []
3434

35+
debug-checks-balanced = []
36+
release-checks-fast = []
37+
3538
[dependencies]
3639
gdextension-api = { workspace = true }
3740

godot-bindings/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// It's the only purpose of this build.rs file. If a better solution is found, this file can be removed.
1111

1212
#[rustfmt::skip]
13-
fn main() {
13+
fn main() {
1414
let mut count = 0;
1515
if cfg!(feature = "api-custom") { count += 1; }
1616
if cfg!(feature = "api-custom-json") { count += 1; }

godot-bindings/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,21 @@ pub fn before_api(major_minor: &str) -> bool {
267267
pub fn since_api(major_minor: &str) -> bool {
268268
!before_api(major_minor)
269269
}
270+
271+
pub fn emit_checks_mode() {
272+
let check_modes = ["fast-unsafe", "balanced", "paranoid"];
273+
let mut checks_level = if cfg!(debug_assertions) { 2 } else { 1 };
274+
#[cfg(debug_assertions)]
275+
if cfg!(feature = "debug-checks-balanced") {
276+
checks_level = 1;
277+
}
278+
#[cfg(not(debug_assertions))]
279+
if cfg!(feature = "release-checks-fast") {
280+
checks_level = 0;
281+
}
282+
283+
for checks in check_modes.iter().take(checks_level + 1) {
284+
println!(r#"cargo:rustc-check-cfg=cfg(checks_at_least, values("{checks}"))"#);
285+
println!(r#"cargo:rustc-cfg=checks_at_least="{checks}""#);
286+
}
287+
}

godot-codegen/src/generator/native_structures.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ fn make_native_structure_field_and_accessor(
219219

220220
let obj = #snake_field_name.upcast();
221221

222+
#[cfg(checks_at_least = "balanced")]
222223
assert!(obj.is_instance_valid(), "provided node is dead");
223224

224225
let id = obj.instance_id().to_u64();

godot-core/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ api-4-3 = ["godot-ffi/api-4-3"]
3737
api-4-4 = ["godot-ffi/api-4-4"]
3838
# ]]
3939

40+
debug-checks-balanced = ["godot-ffi/debug-checks-balanced"]
41+
release-checks-fast = ["godot-ffi/release-checks-fast"]
42+
4043
[dependencies]
4144
godot-ffi = { path = "../godot-ffi", version = "=0.3.5" }
4245

godot-core/build.rs

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

1919
godot_bindings::emit_godot_version_cfg();
2020
godot_bindings::emit_wasm_nothreads_cfg();
21+
godot_bindings::emit_checks_mode();
2122
}

godot-core/src/builtin/collections/array.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ impl<T: ArrayElement> Array<T> {
979979
}
980980

981981
/// Validates that all elements in this array can be converted to integers of type `T`.
982-
#[cfg(debug_assertions)]
982+
#[cfg(checks_at_least = "paranoid")]
983983
pub(crate) fn debug_validate_int_elements(&self) -> Result<(), ConvertError> {
984984
// SAFETY: every element is internally represented as Variant.
985985
let canonical_array = unsafe { self.assume_type_ref::<Variant>() };
@@ -1001,7 +1001,7 @@ impl<T: ArrayElement> Array<T> {
10011001
}
10021002

10031003
// No-op in Release. Avoids O(n) conversion checks, but still panics on access.
1004-
#[cfg(not(debug_assertions))]
1004+
#[cfg(not(checks_at_least = "paranoid"))]
10051005
pub(crate) fn debug_validate_int_elements(&self) -> Result<(), ConvertError> {
10061006
Ok(())
10071007
}
@@ -1244,7 +1244,7 @@ impl<T: ArrayElement> Clone for Array<T> {
12441244
let copy = unsafe { self.clone_unchecked() };
12451245

12461246
// Double-check copy's runtime type in Debug mode.
1247-
if cfg!(debug_assertions) {
1247+
if cfg!(checks_at_least = "paranoid") {
12481248
copy.with_checked_type()
12491249
.expect("copied array should have same type as original array")
12501250
} else {

godot-core/src/classes/class_runtime.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
//! Runtime checks and inspection of Godot classes.
99
1010
use crate::builtin::{GString, StringName, Variant, VariantType};
11-
#[cfg(debug_assertions)]
11+
#[cfg(checks_at_least = "paranoid")]
1212
use crate::classes::{ClassDb, Object};
1313
use crate::meta::CallContext;
14-
#[cfg(debug_assertions)]
14+
#[cfg(checks_at_least = "paranoid")]
1515
use crate::meta::ClassId;
1616
use crate::obj::{bounds, Bounds, Gd, GodotClass, InstanceId, RawGd, Singleton};
1717
use crate::sys;
@@ -191,6 +191,7 @@ where
191191
Gd::<T>::from_obj_sys(object_ptr)
192192
}
193193

194+
#[cfg(checks_at_least = "balanced")]
194195
pub(crate) fn ensure_object_alive(
195196
instance_id: InstanceId,
196197
old_object_ptr: sys::GDExtensionObjectPtr,
@@ -211,7 +212,7 @@ pub(crate) fn ensure_object_alive(
211212
);
212213
}
213214

214-
#[cfg(debug_assertions)]
215+
#[cfg(checks_at_least = "paranoid")]
215216
pub(crate) fn ensure_object_inherits(derived: ClassId, base: ClassId, instance_id: InstanceId) {
216217
if derived == base
217218
|| base == Object::class_id() // for Object base, anything inherits by definition
@@ -226,7 +227,7 @@ pub(crate) fn ensure_object_inherits(derived: ClassId, base: ClassId, instance_i
226227
)
227228
}
228229

229-
#[cfg(debug_assertions)]
230+
#[cfg(checks_at_least = "paranoid")]
230231
pub(crate) fn ensure_binding_not_null<T>(binding: sys::GDExtensionClassInstancePtr)
231232
where
232233
T: GodotClass + Bounds<Declarer = bounds::DeclUser>,
@@ -254,7 +255,7 @@ where
254255
// Implementation of this file
255256

256257
/// Checks if `derived` inherits from `base`, using a cache for _successful_ queries.
257-
#[cfg(debug_assertions)]
258+
#[cfg(checks_at_least = "paranoid")]
258259
fn is_derived_base_cached(derived: ClassId, base: ClassId) -> bool {
259260
use std::collections::HashSet;
260261

godot-core/src/meta/error/convert_error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ pub(crate) enum FromGodotError {
186186
},
187187

188188
/// Special case of `BadArrayType` where a custom int type such as `i8` cannot hold a dynamic `i64` value.
189-
#[cfg(debug_assertions)]
189+
#[cfg(checks_at_least = "paranoid")]
190190
BadArrayTypeInt {
191191
expected_int_type: &'static str,
192192
value: i64,
@@ -231,7 +231,7 @@ impl fmt::Display for FromGodotError {
231231

232232
write!(f, "expected array of type {exp_class}, got {act_class}")
233233
}
234-
#[cfg(debug_assertions)]
234+
#[cfg(checks_at_least = "paranoid")]
235235
Self::BadArrayTypeInt {
236236
expected_int_type,
237237
value,

godot-core/src/meta/signature.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl<Params: OutParamTuple, Ret: FromGodot> Signature<Params, Ret> {
144144
//$crate::out!("out_class_varcall: {call_ctx}");
145145

146146
// Note: varcalls are not safe from failing, if they happen through an object pointer -> validity check necessary.
147+
#[cfg(checks_at_least = "balanced")]
147148
if let Some(instance_id) = maybe_instance_id {
148149
crate::classes::ensure_object_alive(instance_id, object_ptr, &call_ctx);
149150
}
@@ -304,6 +305,7 @@ impl<Params: OutParamTuple, Ret: FromGodot> Signature<Params, Ret> {
304305
let call_ctx = CallContext::outbound(class_name, method_name);
305306
// $crate::out!("out_class_ptrcall: {call_ctx}");
306307

308+
#[cfg(checks_at_least = "balanced")]
307309
if let Some(instance_id) = maybe_instance_id {
308310
crate::classes::ensure_object_alive(instance_id, object_ptr, &call_ctx);
309311
}

0 commit comments

Comments
 (0)