Skip to content

Commit 91e9f7c

Browse files
fix: reject type aliases in define_multi_property! (#852)
Fixes #843
1 parent 980bde8 commit 91e9f7c

2 files changed

Lines changed: 51 additions & 2 deletions

File tree

src/entity/property.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,36 @@ pub enum PropertyInitializationKind {
3939
pub trait AnyProperty: Copy + Debug + PartialEq + Serialize + 'static {}
4040
impl<T> AnyProperty for T where T: Copy + Debug + PartialEq + Serialize + 'static {}
4141

42+
/// `const fn` string equality — `==` on `&str` isn't `const` on stable.
43+
#[must_use]
44+
pub const fn const_str_eq(a: &str, b: &str) -> bool {
45+
if a.len() != b.len() {
46+
return false;
47+
}
48+
let a = a.as_bytes();
49+
let b = b.as_bytes();
50+
let mut i = 0;
51+
while i < a.len() {
52+
if a[i] != b[i] {
53+
return false;
54+
}
55+
i += 1;
56+
}
57+
true
58+
}
59+
4260
/// All properties must implement this trait using one of the `define_property` macros.
4361
pub trait Property<E: Entity>: AnyProperty {
4462
/// Some properties might store a transformed version of the value in the index. This is the
4563
/// type of the transformed value. For simple properties this will be the same as `Self`.
4664
type CanonicalValue: AnyProperty;
4765

66+
/// Source-level name, set by the macros to `stringify!($property)`. Used by
67+
/// `define_multi_property!` to reject type aliases (see issue #843).
68+
const NAME: &'static str;
69+
4870
fn name() -> &'static str {
49-
let full = std::any::type_name::<Self>();
50-
full.rsplit("::").next().unwrap()
71+
Self::NAME
5172
}
5273

5374
/// The kind of initialization this property has.

src/macros/property_impl.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ macro_rules! impl_property {
450450
impl $crate::entity::property::Property<$entity> for $property {
451451
type CanonicalValue = $canonical_value;
452452

453+
const NAME: &'static str = stringify!($property);
454+
453455
fn initialization_kind() -> $crate::entity::property::PropertyInitializationKind {
454456
$initialization_kind
455457
}
@@ -726,6 +728,17 @@ macro_rules! impl_derived_property {
726728
/// reordering of the component properties. The querying subsystem is able to detect when its multiple
727729
/// component properties are equivalent to an indexed multi-property and use that index to perform the
728730
/// query.
731+
///
732+
/// Components must be the underlying property type, not a type alias (see issue #843):
733+
///
734+
/// ```compile_fail
735+
/// use ixa::{define_entity, define_property, define_multi_property};
736+
/// define_entity!(Person);
737+
/// define_property!(struct Age(u8), Person, default_const = Age(0));
738+
/// define_property!(struct Height(u8), Person, default_const = Height(0));
739+
/// type Years = Age;
740+
/// define_multi_property!((Years, Height), Person);
741+
/// ```
729742
#[macro_export]
730743
macro_rules! define_multi_property {
731744
(
@@ -735,6 +748,21 @@ macro_rules! define_multi_property {
735748
$crate::paste::paste! {
736749
type [<$($dependency)*>] = ( $($dependency),+ );
737750

751+
// Reject type aliases; see issue #843.
752+
$(
753+
const _: () = assert!(
754+
$crate::entity::property::const_str_eq(
755+
stringify!($dependency),
756+
<$dependency as $crate::entity::property::Property<$entity>>::NAME,
757+
),
758+
concat!(
759+
"define_multi_property!: `",
760+
stringify!($dependency),
761+
"` is a type alias; use the underlying property type (see issue #843)."
762+
),
763+
);
764+
)+
765+
738766
$crate::impl_property!(
739767
[<$($dependency)*>],
740768
$entity,

0 commit comments

Comments
 (0)