Skip to content

Commit

Permalink
Allow #[cfg] to be used with #[constant]
Browse files Browse the repository at this point in the history
  • Loading branch information
PgBiel committed Oct 13, 2023
1 parent 81fd6d0 commit 1b635d5
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
11 changes: 11 additions & 0 deletions godot-macros/src/class/godot_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
.map(|func_def| make_method_registration(&class_name, func_def));

let consts = process_godot_constants(&mut decl)?;
let mut integer_constant_cfg_attrs = Vec::new();
let mut integer_constant_names = Vec::new();
let mut integer_constant_values = Vec::new();

Expand All @@ -146,6 +147,15 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {

let name = &constant.name;

// Unlike with #[func] and #[signal], we don't remove the attributes from Constant
// signatures within 'process_godot_constants'.
let cfg_attrs = util::extract_cfg_attrs(&constant.attributes)
.into_iter()
.collect::<Vec<_>>();

// Transport #[cfg] attrs to the FFI glue to ensure constants which were conditionally
// removed from compilation don't cause errors.
integer_constant_cfg_attrs.push(cfg_attrs);
integer_constant_names.push(constant.name.to_string());
integer_constant_values.push(quote! { #class_name::#name });
}
Expand All @@ -157,6 +167,7 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
use ::godot::builtin::StringName;

#(
#(#integer_constant_cfg_attrs)*
ExportConstant::new(
#class_name_obj,
ConstantKind::Integer(
Expand Down
42 changes: 41 additions & 1 deletion itest/rust/src/register_tests/constant_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,45 @@ impl HasConstants {
#[constant]
#[cfg(all())]
const CONSTANT_RECOGNIZED_WITH_SIMPLE_PATH_ATTRIBUTE_BELOW_CONST_ATTR: bool = true;

// The three identically-named definitions below should be mutually exclusive thanks to #[cfg].
#[constant]
const CFG_REMOVES_DUPLICATE_CONSTANT_DEF: i64 = 5;

#[cfg(any())]
#[constant]
const CFG_REMOVES_DUPLICATE_CONSTANT_DEF: i64 = compile_error!("Removed by #[cfg]");

#[constant]
#[cfg(any())]
const CFG_REMOVES_DUPLICATE_CONSTANT_DEF: i64 = compile_error!("Removed by #[cfg]");

// The constant below should end up not being defined at all.
#[cfg(any())]
#[constant]
const CFG_REMOVES_CONSTANT: bool = compile_error!("Removed by #[cfg]");

#[constant]
#[cfg(any())]
const CFG_REMOVES_CONSTANT: bool = compile_error!("Removed by #[cfg]");
}

/// Checks at runtime if a class has a given integer constant through [ClassDb].
fn class_has_integer_constant<T: GodotClass>(name: &str) -> bool {
ClassDb::singleton().class_has_integer_constant(T::class_name().to_string_name(), name.into())
}

#[itest]
fn constants_correct_value() {
const CONSTANTS: [(&str, i64); 4] = [
const CONSTANTS: [(&str, i64); 5] = [
("A", HasConstants::A),
("B", HasConstants::B as i64),
("C", HasConstants::C as i64),
("D", HasConstants::D as i64),
(
"CFG_REMOVES_DUPLICATE_CONSTANT_DEF",
HasConstants::CFG_REMOVES_DUPLICATE_CONSTANT_DEF,
),
];

let constants = ClassDb::singleton()
Expand All @@ -72,6 +102,16 @@ fn constants_correct_value() {
static_assert!(HasConstants::CONSTANT_RECOGNIZED_WITH_SIMPLE_PATH_ATTRIBUTE_BELOW_CONST_ATTR);
}

#[itest]
fn cfg_removes_or_keeps_constants() {
assert!(class_has_integer_constant::<HasConstants>(
"CFG_REMOVES_DUPLICATE_CONSTANT_DEF"
));
assert!(!class_has_integer_constant::<HasConstants>(
"CFG_REMOVES_CONSTANT"
));
}

#[derive(GodotClass)]
struct HasOtherConstants {}

Expand Down

0 comments on commit 1b635d5

Please sign in to comment.