Is there a way to shorten generic type bounds in rust? This is the mess I have to put on a lot of structs impls etc.:
pub struct IncomingClientMessageWithAddress<State, Msg>
where State: AppState + Clone + serde::Serialize + serde::de::DeserializeOwned + std::marker::Unpin + 'static,
Msg: AppEvent + Clone + serde::Serialize + serde::de::DeserializeOwned + std::marker::Unpin + 'static {
...
I am basically looking to do something like this (I know that below doesn't work for traits):
type MyStateAlias = AppState + Clone + serde::Serialize + serde::de::DeserializeOwned + std::marker::Unpin + 'static;
type MyEventAlias = AppEvent + Clone + serde::Serialize + serde::de::DeserializeOwned + std::marker::Unpin + 'static;
pub struct IncomingClientMessageWithAddress<State, Msg>
where State: MyStateAlias,
Msg: MyEventAlias {
...
I sometimes realized that all occurrences of a certain trait are associated with other traits. In your case, if AppState
always occurs with Clone
and Serialize
, you could already require these on top of state:
trait AppState : Clone + Serialize {/*...*/}
If not, you could still define an auxiliary trait
trait AuxAppState: AppState + Clone + Serialize {/*...*/}
and require State : AuxAppState
.
Then, to automatically derive AuxAppState
you'd have to impl
it for every type that also impl
ements State
, Clone
and Serialize
:
impl<T> AuxAppState for T where T: AppState + Clone + Serialize {}
Finally, defining and impl
ementing the AuxAppState
could possibly be done by a macro to save some keystrokes:
macro_rules! auxiliary_trait{
($traitname: ident, $($t:tt)*) => {
trait $traitname : $($t)* {}
impl<T> $traitname for T where T: $($t)* {}
}
}
All of this can possibly be done one day with trait aliases.
Moreover, I started to require trait bounds only where they are actually needed. E.g. in many cases, the struct
-definition itself does not rely on the trait bounds, only the impl
, so I started omitting them on the struct
, only keeping them in the impl
.
You could use new traits with blanket implementations for this:
use serde::Serialize;
use serde::de::DeserializeOwned;
use std::marker::Unpin;
pub trait AppState {}
pub trait AppEvent {}
pub trait StateTrait : AppState + Clone + Serialize + DeserializeOwned + Unpin + 'static {}
impl<T : AppState + Clone + Serialize + DeserializeOwned + Unpin + 'static> StateTrait for T {}
pub trait EventTrait : AppEvent + Clone + Serialize + DeserializeOwned + Unpin + 'static {}
impl<T : AppEvent + Clone + Serialize + DeserializeOwned + Unpin + 'static> EventTrait for T {}
pub struct IncomingClientMessageWithAddress<State, Msg>
where State: StateTrait, Msg: EventTrait
{
...
}
playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With