Skip to content

Commit 1280143

Browse files
committed
Make #[cfg] model for safeguards easier to understand (WIP MISTAKE IN PUBLIC FEATURES)
1 parent 41fb3cb commit 1280143

21 files changed

Lines changed: 89 additions & 85 deletions

File tree

.github/workflows/full-ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ jobs:
326326
artifact-name: linux-nightly
327327
godot-binary: godot.linuxbsd.editor.dev.x86_64
328328
# Important to keep both experimental-threads and codegen-full. Some itests (native_st_audio) require both.
329-
rust-extra-args: --features itest/experimental-threads,itest/codegen-full-experimental,godot/api-custom,godot/serde,itest/register-docs,godot/safeguards-dev-balanced
329+
rust-extra-args: --features itest/experimental-threads,itest/codegen-full-experimental,godot/api-custom,godot/serde,itest/register-docs
330330

331331
# Compiles godot-rust with `api-custom-json` feature against the JSON file generated via `--dump-extension-api`.
332332
# Uses latest 4.x headers, while `extension_api.json` comes from the latest Godot binary.
@@ -350,7 +350,7 @@ jobs:
350350
os: ubuntu-22.04
351351
artifact-name: linux-release-nightly
352352
godot-binary: godot.linuxbsd.template_release.x86_64
353-
rust-extra-args: --release --features itest/codegen-full-experimental,godot/safeguards-release-disengaged
353+
rust-extra-args: --release --features itest/codegen-full-experimental,godot/safeguards-disengaged
354354
rust-cache-key: release-disengaged
355355

356356
# Linux compat:

godot-bindings/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ api-custom-json = ["dep:nanoserde", "dep:bindgen", "dep:regex", "dep:which"]
3434
api-custom-extheader = []
3535

3636
# Safeguard levels (see godot/lib.rs for detailed documentation).
37-
safeguards-dev-balanced = []
38-
safeguards-release-disengaged = []
37+
safeguards-strict = []
38+
safeguards-disengaged = []
3939

4040
[dependencies]
4141
gdextension-api = { workspace = true }

godot-bindings/src/lib.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,21 +269,29 @@ pub fn since_api(major_minor: &str) -> bool {
269269
}
270270

271271
pub fn emit_safeguard_levels() {
272-
let safeguard_modes = ["disengaged", "balanced", "strict"];
272+
// Determine safeguard level:
273+
// - Disengaged (0): no runtime checks, maximum performance
274+
// - Balanced (1): essential safety checks, good balance (default for release)
275+
// - Strict (2): all checks including expensive ones (default for debug)
273276
let mut safeguards_level = if cfg!(debug_assertions) { 2 } else { 1 };
274-
#[cfg(debug_assertions)]
275-
if cfg!(feature = "safeguards-dev-balanced") {
276-
safeguards_level = 1;
277+
278+
// Features can override the default level
279+
if cfg!(feature = "safeguards-strict") {
280+
safeguards_level = 2;
277281
}
278-
#[cfg(not(debug_assertions))]
279-
if cfg!(feature = "safeguards-release-disengaged") {
282+
if cfg!(feature = "safeguards-disengaged") {
280283
safeguards_level = 0;
281284
}
282285

283-
for mode in safeguard_modes.iter() {
284-
println!(r#"cargo:rustc-check-cfg=cfg(safeguards_at_least, values("{mode}"))"#);
286+
// Emit cfg checks for rustc
287+
println!(r#"cargo:rustc-check-cfg=cfg(safeguards_balanced)"#);
288+
println!(r#"cargo:rustc-check-cfg=cfg(safeguards_strict)"#);
289+
290+
// Emit cfgs cumulatively: strict builds get both balanced and strict
291+
if safeguards_level >= 1 {
292+
println!(r#"cargo:rustc-cfg=safeguards_balanced"#);
285293
}
286-
for mode in safeguard_modes.iter().take(safeguards_level + 1) {
287-
println!(r#"cargo:rustc-cfg=safeguards_at_least="{mode}""#);
294+
if safeguards_level >= 2 {
295+
println!(r#"cargo:rustc-cfg=safeguards_strict"#);
288296
}
289297
}

godot-codegen/src/generator/classes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
195195
fn __checked_id(&self) -> Option<crate::obj::InstanceId> {
196196
// SAFETY: only Option due to layout-compatibility with RawGd<T>; it is always Some because stored in Gd<T> which is non-null.
197197
let rtti = unsafe { self.rtti.as_ref().unwrap_unchecked() };
198-
#[cfg(safeguards_at_least = "strict")]
198+
#[cfg(safeguards_strict)]
199199
rtti.check_type::<Self>();
200200
Some(rtti.instance_id())
201201
}

godot-codegen/src/generator/native_structures.rs

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

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

222-
#[cfg(safeguards_at_least = "balanced")]
222+
#[cfg(safeguards_balanced)]
223223
assert!(obj.is_instance_valid(), "provided node is dead");
224224

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

godot-core/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ api-4-5 = ["godot-ffi/api-4-5"]
3939
# ]]
4040

4141
# Safeguard levels (see godot/lib.rs for detailed documentation).
42-
safeguards-dev-balanced = ["godot-ffi/safeguards-dev-balanced"]
43-
safeguards-release-disengaged = ["godot-ffi/safeguards-release-disengaged"]
42+
safeguards-strict = ["godot-ffi/safeguards-strict"]
43+
safeguards-disengaged = ["godot-ffi/safeguards-disengaged"]
4444

4545
[dependencies]
4646
godot-ffi = { path = "../godot-ffi", version = "=0.4.1" }

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

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

970970
/// Validates that all elements in this array can be converted to integers of type `T`.
971-
#[cfg(safeguards_at_least = "strict")]
971+
#[cfg(safeguards_strict)]
972972
pub(crate) fn debug_validate_int_elements(&self) -> Result<(), ConvertError> {
973973
// SAFETY: every element is internally represented as Variant.
974974
let canonical_array = unsafe { self.assume_type_ref::<Variant>() };
@@ -990,7 +990,7 @@ impl<T: ArrayElement> Array<T> {
990990
}
991991

992992
// No-op in Release. Avoids O(n) conversion checks, but still panics on access.
993-
#[cfg(not(safeguards_at_least = "strict"))]
993+
#[cfg(not(safeguards_strict))]
994994
pub(crate) fn debug_validate_int_elements(&self) -> Result<(), ConvertError> {
995995
Ok(())
996996
}
@@ -1233,7 +1233,7 @@ impl<T: ArrayElement> Clone for Array<T> {
12331233
let copy = unsafe { self.clone_unchecked() };
12341234

12351235
// Double-check copy's runtime type in Debug mode.
1236-
if cfg!(safeguards_at_least = "strict") {
1236+
if cfg!(safeguards_strict) {
12371237
copy.with_checked_type()
12381238
.expect("copied array should have same type as original array")
12391239
} else {

godot-core/src/classes/class_runtime.rs

Lines changed: 6 additions & 6 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(safeguards_at_least = "strict")]
11+
#[cfg(safeguards_strict)]
1212
use crate::classes::{ClassDb, Object};
1313
use crate::meta::CallContext;
14-
#[cfg(safeguards_at_least = "strict")]
14+
#[cfg(safeguards_strict)]
1515
use crate::meta::ClassId;
1616
use crate::obj::{bounds, Bounds, Gd, GodotClass, InstanceId, RawGd, Singleton};
1717
use crate::sys;
@@ -191,7 +191,7 @@ where
191191
Gd::<T>::from_obj_sys(object_ptr)
192192
}
193193

194-
#[cfg(safeguards_at_least = "balanced")]
194+
#[cfg(safeguards_balanced)]
195195
pub(crate) fn ensure_object_alive(
196196
instance_id: InstanceId,
197197
old_object_ptr: sys::GDExtensionObjectPtr,
@@ -212,7 +212,7 @@ pub(crate) fn ensure_object_alive(
212212
);
213213
}
214214

215-
#[cfg(safeguards_at_least = "strict")]
215+
#[cfg(safeguards_strict)]
216216
pub(crate) fn ensure_object_inherits(derived: ClassId, base: ClassId, instance_id: InstanceId) {
217217
if derived == base
218218
|| base == Object::class_id() // for Object base, anything inherits by definition
@@ -227,7 +227,7 @@ pub(crate) fn ensure_object_inherits(derived: ClassId, base: ClassId, instance_i
227227
)
228228
}
229229

230-
#[cfg(safeguards_at_least = "strict")]
230+
#[cfg(safeguards_strict)]
231231
pub(crate) fn ensure_binding_not_null<T>(binding: sys::GDExtensionClassInstancePtr)
232232
where
233233
T: GodotClass + Bounds<Declarer = bounds::DeclUser>,
@@ -255,7 +255,7 @@ where
255255
// Implementation of this file
256256

257257
/// Checks if `derived` inherits from `base`, using a cache for _successful_ queries.
258-
#[cfg(safeguards_at_least = "strict")]
258+
#[cfg(safeguards_strict)]
259259
fn is_derived_base_cached(derived: ClassId, base: ClassId) -> bool {
260260
use std::collections::HashSet;
261261

godot-core/src/init/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -535,14 +535,12 @@ unsafe fn ensure_godot_features_compatible() {
535535
out!("Check Godot precision setting...");
536536

537537
#[cfg(feature = "debug-log")] // Display safeguards level in debug log.
538-
let safeguards_level = if cfg!(safeguards_at_least = "strict") {
538+
let safeguards_level = if cfg!(safeguards_strict) {
539539
"strict"
540-
} else if cfg!(safeguards_at_least = "balanced") {
540+
} else if cfg!(safeguards_balanced) {
541541
"balanced"
542-
} else if cfg!(safeguards_at_least = "disengaged") {
543-
"disengaged"
544542
} else {
545-
"unknown"
543+
"disengaged"
546544
};
547545
out!("Safeguards: {safeguards_level}");
548546

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

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

191191
/// Special case of `BadArrayType` where a custom int type such as `i8` cannot hold a dynamic `i64` value.
192-
#[cfg(safeguards_at_least = "strict")]
192+
#[cfg(safeguards_strict)]
193193
BadArrayTypeInt {
194194
expected_int_type: &'static str,
195195
value: i64,
@@ -234,7 +234,7 @@ impl fmt::Display for FromGodotError {
234234

235235
write!(f, "expected array of type {exp_class}, got {act_class}")
236236
}
237-
#[cfg(safeguards_at_least = "strict")]
237+
#[cfg(safeguards_strict)]
238238
Self::BadArrayTypeInt {
239239
expected_int_type,
240240
value,

0 commit comments

Comments
 (0)