diff --git a/check.sh b/check.sh index b377bfc3a..44a98926c 100755 --- a/check.sh +++ b/check.sh @@ -142,7 +142,13 @@ function findGodot() { # builtins like `test`. function cmd_fmt() { - run cargo fmt --all -- --check + # Run rustfmt in nightly toolchain if available. + if [[ $(rustup toolchain list) =~ nightly ]]; then + run cargo +nightly fmt --all -- --check + else + log -e "${YELLOW}Warning: nightly toolchain not found; stable rustfmt might not pass CI.${END}" + run cargo fmt --all -- --check + fi } function cmd_clippy() { diff --git a/godot-codegen/src/generator/signals.rs b/godot-codegen/src/generator/signals.rs index c74f382f3..f749fc656 100644 --- a/godot-codegen/src/generator/signals.rs +++ b/godot-codegen/src/generator/signals.rs @@ -10,6 +10,8 @@ // for these signals, and integration is slightly different due to lack of WithBaseField trait. Nonetheless, some parts could potentially // be extracted into a future crate shared by godot-codegen and godot-macros. +// TODO(v0.5): signal parameters are Gd instead of conservatively Option>, which is a bug. + use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; diff --git a/godot-codegen/src/models/domain.rs b/godot-codegen/src/models/domain.rs index a95a515a2..5154bae04 100644 --- a/godot-codegen/src/models/domain.rs +++ b/godot-codegen/src/models/domain.rs @@ -737,19 +737,22 @@ pub enum RustTy { /// C-style raw pointer to a `RustTy`. RawPointer { inner: Box, is_const: bool }, - /// `Array>` + /// `Array>`. Never contains `Option` elements. EngineArray { tokens: TokenStream, - #[allow(dead_code)] // only read in minimal config + + #[allow(dead_code)] // Only read in minimal config. elem_class: String, }, /// `module::Enum` or `module::Bitfield` EngineEnum { tokens: TokenStream, - /// `None` for globals - #[allow(dead_code)] // only read in minimal config + + /// `None` for globals. + #[allow(dead_code)] // Only read in minimal config. surrounding_class: Option, + is_bitfield: bool, }, @@ -794,7 +797,6 @@ impl RustTy { /// Returns tokens without `Option` wrapper, even for nullable engine classes. /// /// For `EngineClass`, always returns `Gd` regardless of nullability. For other types, behaves the same as `ToTokens`. - // TODO(v0.5): only used for signal params, which is a bug. Those should conservatively be Option> as well. // Might also be useful to directly extract inner `gd_tokens` field. pub fn tokens_non_null(&self) -> TokenStream { match self { diff --git a/godot-core/src/builtin/basis.rs b/godot-core/src/builtin/basis.rs index 23bae4563..e8bdcf702 100644 --- a/godot-core/src/builtin/basis.rs +++ b/godot-core/src/builtin/basis.rs @@ -703,22 +703,22 @@ mod test { Basis::from_euler(EulerOrder::XYZ, euler_xyz_from_rotation); let res = to_rotation.inverse() * rotation_from_xyz_computed_euler; + let col_a = res.col_a(); + let col_b = res.col_b(); + let col_c = res.col_c(); assert!( - (res.col_a() - Vector3::new(1.0, 0.0, 0.0)).length() <= 0.1, - "Double check with XYZ rot order failed, due to X {} with {deg_original_euler} using {rot_order:?}", - res.col_a(), - ); + (col_a - Vector3::new(1.0, 0.0, 0.0)).length() <= 0.1, + "Double check with XYZ rot order failed, due to A {col_a} with {deg_original_euler} using {rot_order:?}", + ); assert!( - (res.col_b() - Vector3::new(0.0, 1.0, 0.0)).length() <= 0.1, - "Double check with XYZ rot order failed, due to Y {} with {deg_original_euler} using {rot_order:?}", - res.col_b(), - ); + (col_b - Vector3::new(0.0, 1.0, 0.0)).length() <= 0.1, + "Double check with XYZ rot order failed, due to B {col_b} with {deg_original_euler} using {rot_order:?}", + ); assert!( - (res.col_c() - Vector3::new(0.0, 0.0, 1.0)).length() <= 0.1, - "Double check with XYZ rot order failed, due to Z {} with {deg_original_euler} using {rot_order:?}", - res.col_c(), - ); + (col_c - Vector3::new(0.0, 0.0, 1.0)).length() <= 0.1, + "Double check with XYZ rot order failed, due to C {col_c} with {deg_original_euler} using {rot_order:?}", + ); } #[test] diff --git a/godot-core/src/builtin/callable.rs b/godot-core/src/builtin/callable.rs index 9d174feff..783c6ef93 100644 --- a/godot-core/src/builtin/callable.rs +++ b/godot-core/src/builtin/callable.rs @@ -461,7 +461,7 @@ impl Callable { /// _Godot equivalent: `hash`_ } - #[deprecated = "renamed to hash_u32"] + #[deprecated = "renamed to `hash_u32`"] pub fn hash(&self) -> u32 { self.as_inner().hash().try_into().unwrap() } diff --git a/godot-core/src/builtin/collections/array.rs b/godot-core/src/builtin/collections/array.rs index 4079b7bdc..ba4df6481 100644 --- a/godot-core/src/builtin/collections/array.rs +++ b/godot-core/src/builtin/collections/array.rs @@ -293,7 +293,7 @@ impl Array { /// because different arrays can have identical hash values due to hash collisions. } - #[deprecated = "renamed to hash_u32"] + #[deprecated = "renamed to `hash_u32`"] pub fn hash(&self) -> u32 { self.as_inner().hash().try_into().unwrap() } diff --git a/godot-core/src/builtin/collections/dictionary.rs b/godot-core/src/builtin/collections/dictionary.rs index ebe00e42d..166c48bde 100644 --- a/godot-core/src/builtin/collections/dictionary.rs +++ b/godot-core/src/builtin/collections/dictionary.rs @@ -289,7 +289,7 @@ impl Dictionary { /// Returns a 32-bit integer hash value representing the dictionary and its contents. } - #[deprecated = "renamed to hash_u32"] + #[deprecated = "renamed to `hash_u32`"] #[must_use] pub fn hash(&self) -> u32 { self.as_inner().hash().try_into().unwrap() diff --git a/godot-core/src/builtin/mod.rs b/godot-core/src/builtin/mod.rs index f8d832d72..61227c6d2 100644 --- a/godot-core/src/builtin/mod.rs +++ b/godot-core/src/builtin/mod.rs @@ -118,7 +118,7 @@ pub mod inner { #[macro_export] macro_rules! declare_hash_u32_method { - ($ ($docs:tt)+ ) => { + ( $( $docs:tt )+ ) => { $( $docs )+ pub fn hash_u32(&self) -> u32 { self.as_inner().hash().try_into().expect("Godot hashes are uint32_t") diff --git a/godot-core/src/builtin/string/gstring.rs b/godot-core/src/builtin/string/gstring.rs index ca2470d67..b001d4ce2 100644 --- a/godot-core/src/builtin/string/gstring.rs +++ b/godot-core/src/builtin/string/gstring.rs @@ -160,7 +160,7 @@ impl GString { /// Returns a 32-bit integer hash value representing the string. } - #[deprecated = "renamed to hash_u32"] + #[deprecated = "renamed to `hash_u32`"] pub fn hash(&self) -> u32 { self.as_inner() .hash() diff --git a/godot-core/src/builtin/string/node_path.rs b/godot-core/src/builtin/string/node_path.rs index e57317235..c518da209 100644 --- a/godot-core/src/builtin/string/node_path.rs +++ b/godot-core/src/builtin/string/node_path.rs @@ -118,10 +118,10 @@ impl NodePath { } crate::declare_hash_u32_method! { - /// Returns a 32-bit integer hash value representing the string. + /// Returns a 32-bit integer hash value representing the node path. } - #[deprecated = "renamed to hash_u32"] + #[deprecated = "renamed to `hash_u32`"] pub fn hash(&self) -> u32 { self.as_inner() .hash() diff --git a/godot-core/src/builtin/string/string_name.rs b/godot-core/src/builtin/string/string_name.rs index fd9fe8644..418c29a69 100644 --- a/godot-core/src/builtin/string/string_name.rs +++ b/godot-core/src/builtin/string/string_name.rs @@ -143,7 +143,7 @@ impl StringName { /// Returns a 32-bit integer hash value representing the string. } - #[deprecated = "renamed to hash_u32"] + #[deprecated = "renamed to `hash_u32`"] pub fn hash(&self) -> u32 { self.as_inner() .hash() diff --git a/godot-core/src/builtin/variant/mod.rs b/godot-core/src/builtin/variant/mod.rs index 5d189ca2e..bec3fa10b 100644 --- a/godot-core/src/builtin/variant/mod.rs +++ b/godot-core/src/builtin/variant/mod.rs @@ -311,7 +311,7 @@ impl Variant { /// /// _Godot equivalent : `@GlobalScope.hash()`_ pub fn hash_u32(&self) -> u32 { - // @GlobalScope.hash() actually calls the VariantUtilityFunctions::hash(&Variant) function (cpp). + // @GlobalScope.hash() actually calls the VariantUtilityFunctions::hash(&Variant) function (C++). // This function calls the passed reference's `hash` method, which returns a uint32_t. // Therefore, casting this function to u32 is always fine. unsafe { interface_fn!(variant_hash)(self.var_sys()) } @@ -319,9 +319,9 @@ impl Variant { .expect("Godot hashes are uint32_t") } - #[deprecated = "renamed to hash_u32 and type changed to u32"] + #[deprecated = "renamed to `hash_u32` and type changed to `u32`"] pub fn hash(&self) -> i64 { - unsafe { interface_fn!(variant_hash)(self.var_sys()) } + self.hash_u32().into() } /// Interpret the `Variant` as `bool`. diff --git a/godot-macros/src/class/data_models/inherent_impl.rs b/godot-macros/src/class/data_models/inherent_impl.rs index 2bcd8ac74..e40202538 100644 --- a/godot-macros/src/class/data_models/inherent_impl.rs +++ b/godot-macros/src/class/data_models/inherent_impl.rs @@ -425,7 +425,11 @@ fn add_virtual_script_call( rename: &Option, gd_self_parameter: Option, ) -> String { - assert!(cfg!(since_api = "4.3")); + #[allow(clippy::assertions_on_constants)] + { + // Without braces, clippy removes the #[allow] for some reason... + assert!(cfg!(since_api = "4.3")); + } // Update parameter names, so they can be forwarded (e.g. a "_" declared by the user cannot). let is_params = function.params.iter_mut().skip(1); // skip receiver. diff --git a/godot-macros/src/class/derive_godot_class.rs b/godot-macros/src/class/derive_godot_class.rs index b1696db12..532fe7660 100644 --- a/godot-macros/src/class/derive_godot_class.rs +++ b/godot-macros/src/class/derive_godot_class.rs @@ -52,7 +52,7 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult { let class_name = &class.name; let class_name_str: String = struct_cfg .rename - .map_or_else(|| class.name.clone(), |rename| rename) + .unwrap_or_else(|| class.name.clone()) .to_string(); let class_name_allocation = quote! { ClassId::__alloc_next_unicode(#class_name_str) }; diff --git a/itest/rust/src/builtin_tests/containers/signal_test.rs b/itest/rust/src/builtin_tests/containers/signal_test.rs index 37ccd38b4..6ada19106 100644 --- a/itest/rust/src/builtin_tests/containers/signal_test.rs +++ b/itest/rust/src/builtin_tests/containers/signal_test.rs @@ -15,7 +15,6 @@ use godot::meta::{FromGodot, GodotConvert, ToGodot}; use godot::obj::{Base, Gd, InstanceId, NewAlloc, NewGd}; use godot::prelude::ConvertError; use godot::register::{godot_api, GodotClass}; -use godot::sys; use godot::sys::Global; use crate::framework::itest; diff --git a/itest/rust/src/engine_tests/async_test.rs b/itest/rust/src/engine_tests/async_test.rs index cfbb201f1..e2b80b50f 100644 --- a/itest/rust/src/engine_tests/async_test.rs +++ b/itest/rust/src/engine_tests/async_test.rs @@ -11,7 +11,6 @@ use godot::builtin::{array, vslice, Array, Callable, Signal}; use godot::classes::{Object, RefCounted}; use godot::obj::{Base, Gd, NewAlloc, NewGd}; use godot::prelude::{godot_api, GodotClass}; -use godot::sys; use godot::task::{self, create_test_signal_future_resolver, SignalFuture, TaskHandle}; use crate::framework::{expect_async_panic, itest, TestContext}; @@ -132,6 +131,8 @@ fn async_task_signal_future_panic() -> TaskHandle { #[cfg(feature = "experimental-threads")] #[itest(async)] fn signal_future_non_send_arg_panic() -> TaskHandle { + use godot::sys; + use crate::framework::ThreadCrosser; let mut object = RefCounted::new_gd();