Since all thoughts are welcome, my first thought is that it would help me answer your question if you could reduce the example to its essentials.
My second thought is that it seems like you're using generic associated types to specify a generic "wrapper" type that can be used in type definitions. You could also consider generating multiple specific types through a declarative macro. You could also specify multiple non-generic associative types for each of the values (String
, i64
, Address
, ...) inside of the containers if those are finite.
I've reduced your example and applied some changes. Particularly, I've simplified the Claim
trait to only specify the container and I was able to move the trait bounds from the data type to the generated Serialize
and Deserialize
implementations. This was inspired by @dtolnay 's advice from 2017.
pub trait Claim {
type Container<T>;
}
pub struct ClaimRequest;
impl Claim for ClaimRequest {
type Container<T> = ClaimRequestObject<T>;
}
pub struct ClaimValue;
impl Claim for ClaimValue {
type Container<T> = T;
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct ClaimRequestObject<T> {
pub essential: Option<bool>,
pub value: Option<T>,
pub values: Option<Vec<T>>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct StandardClaims<C: Claim> {
#[serde(bound(serialize = "C::Container<i64>: Serialize", deserialize = "C::Container<i64>: Deserialize<'de>"))]
pub updated_at: Option<C::Container<i64>>,
#[serde(bound(serialize = "C::Container<String>: Serialize", deserialize = "C::Container<String>: Deserialize<'de>"))]
pub email: Option<C::Container<String>>,
#[serde(bound(serialize = "C::Container<bool>: Serialize", deserialize = "C::Container<bool>: Deserialize<'de>"))]
pub email_verified: Option<C::Container<bool>>,
#[serde(bound(serialize = "C::Container<Address<C>>: Serialize", deserialize = "C::Container<Address<C>>: Deserialize<'de>"))]
pub address: Option<C::Container<Address<C>>>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Address<C: Claim> {
#[serde(bound(serialize = "C::Container<String>: Serialize", deserialize = "C::Container<String>: Deserialize<'de>"))]
pub formatted: Option<C::Container<String>>,
}
pub type StandardClaimsRequests = StandardClaims<ClaimRequest>;
pub type StandardClaimsValues = StandardClaims<ClaimValue>;