I have a struct with several states:
struct Select;
struct Insert;
struct Delete;
// ...more states
struct Query<T> {
// ... some non-generic fields
marker: PhantomData<T>
}
I have some functionality which I would like to implement for some, but not all of states. I imagine it should look something like this:
impl Query<T> for T: Select | Update | Delete {
// implement only once
fn foo() -> Query<T>;
}
Is this possible and if so, how?
There are two main methods you could do that. With trait guards, as Chayim suggested, or with a macro. Let's see how each of those solutions work and what are their trade-offs.
Trait guard
This is a pretty easy concept, however it has a subtle nuances. We want to define some kind of
Guardtrait, implement it for some types and then leverage generic implementation. For example:This however has an important drawback. Since
Guardis a public trait if someone would implement it for some other typeOtherthenimpl<T: Guard>would apply toOthertype as well. This could be undesired, as depending on your project's requirements this could lead to broken invariants.We could try making
Guarda private trait, but this currently (rustc 1.70.0,2021 Edition) results in a warning and will become an error in the future.We can solve it by using a sealed trait:
This however doubles number of implementations we have to write and results in slightly uglier API (since we "leak" private seal to public API). It could also result in less readable documentation, since reader must check which types implement
Guardin the first place.Macros
Alternatively you could use a declarative macro. This would result in a very similar syntax to what you described.
This has a couple of advantages:
If you on the other hand like better solution with traits you can still write a macro that would automatically implement guard and it's seal for your types.