I have multiple traits required by some other type, so I just combined them into one trait like this
pub trait SceneSyncBackend
where
<<Self as SceneSyncBackend>::Position as Component>::Storage: Tracked,
<<Self as SceneSyncBackend>::SceneData as Component>::Storage: Tracked,
{
type Position: Position + Component;
type SceneData: SceneData + Component + Send + Sync;
type DropEntity: DropEntity;
}
But the nested trait bounds express is cumbersome, I have to add it everywhere, Is there any simpler way to express this?
This is indeed hard or impossible to do in a nice way in Rust. One workaround Iโm aware of is the following, but itโs usefulness depends a bit on your particular use case.
pub trait IsEqual {
type To: ?Sized;
}
impl<T: ?Sized> IsEqual for T {
type To = Self;
}
trait ComponentWithTrackedStorage: Component {
type TrackedStorage: Tracked + IsEqual<To = Self::Storage>;
}
impl<T: ?Sized> ComponentWithTrackedStorage for T
where
T: Component,
T::Storage: Tracked,
{
type TrackedStorage = Self::Storage;
}
pub trait SceneSyncBackend {
type Position: Position + ComponentWithTrackedStorage;
type SceneData: SceneData + ComponentWithTrackedStorage + Send + Sync;
type DropEntity: DropEntity;
}
There are โtricksโ to convince the rust compiler that T::TrackedStorage and T::Storage are indeed the same type using this IsEqual<To=โฆ> trait bound when thatโs needed. If you like this workaround and your code requires such a trick in a few places, feel free to share more details and I can give you some more details on how that โtrickโ works.
This thread so far clearly demonstrates that Rust still lacks all of the following:
the ability to โpack upโ more complicated where clauses / constraints / bounds involving a type Foo as a trait or trait alias that can be used as a bound Foo: ๐บ๐๐๐๐๐๐๐๐
good compiler support for type equality
macros expanding to (the contents of) where clauses
Iโm positive that weโll eventually get support for all of the above in the who-knows-how-distant future