When I create a game using Bevy, I need to define a lot of components since Bevy uses a entity-component system.
I tried to create a macro to define simple components with the newtype pattern, but I faced a problem.
In the following code, I want to implement the Min
and Default
traits for a component only if its inner type implements Min
.
macro_rules! define_component {
($name:ident, $inner:ty) => {
// a newtype representing a component
pub struct $name(pub $inner);
impl Component for $name {
type Inner = $inner;
}
// I want to implement Min for the component,
// only when the inner type implements Min.
impl Min for $name
where
<Self as Component>::Inner: Min,
{
type Output = Self;
fn min() -> Self {
Self(<<Self as Component>::Inner as Min>::min())
}
}
// I want to implement Default for the component,
// only when Self implements Min.
impl Default for $name
where
Self: Min,
{
fn default() -> Self {
Self::min()
}
}
};
}
// `Inner` is the inner type of the newtype.
trait Component {
type Inner;
}
trait Min {
type Output;
fn min() -> Self;
}
impl Min for u32 {
type Output = Self;
fn min() -> Self {
0
}
}
// These components are OK since the inner or innermost type u32 implements the Min trait.
define_component!(EnemyCount, u32);
define_component!(MaxEnemyCount, EnemyCount);
define_component!(ItemCount, u32);
define_component!(MaxItemCount, ItemCount);
// This impl is commented out to test the behavior when the Min trait is not
// implemented for the inner or innermost type f32.
//
//impl Min for f32 {
// type Output = Self;
// fn min() -> Self {
// 0.0
// }
//}
// These result in compilation errors since the inner type f32 does not implement Min.
define_component!(Speed, f32);
define_component!(Fuel, f32);
// This results in compilation errors since the innermost type f32 does not implement Min.
define_component!(MaxSpeed, Speed);
I get compilation errors like this:
error[E0277]: the trait bound `f32: Min` is not satisfied
--> src/lib.rs:13:13
|
13 | <Self as Component>::Inner: Min,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Min` is not implemented for `f32`
...
72 | define_component!(Speed, f32);
| ----------------------------- in this macro invocation
I want the compiler to avoid implementing traits instead of generating a compilation error when the trait bound for the associated type is not satisfied, is this possible?
For clarity, I'll show the definitions I want;
Components with u32 values should have these definitions since u32 implements Min
.
struct $name
impl Component for $name
impl Min for $name
impl Default for $name
Components with f32 values should have these definitions since f32 doesn't implment Min
.
struct $name
impl Component for $name