I prepared a tiny playground where you can see the problem.
I have a trait DeserializeAs<'de, T>
which can be implemented for any type. Now, I can create an implementation of it like
impl<'de, K, KAs, V, VAs> DeserializeAs<'de, Vec<(K, V)>> for BTreeMap<KAs, VAs>
where
KAs: DeserializeAs<'de, K>,
VAs: DeserializeAs<'de, V>,
{...}
The problem now arises, if I want to generalize the Vec
type. The implementation would work for any type Seq: FromIterator<(K, V)>
, because in the end I'm not using the fact that I have a Vec
anywhere.
That mean, I would want to write
impl<'de, Seq, K, KAs, V, VAs> DeserializeAs<'de, Seq> for BTreeMap<KAs, VAs>
where
KAs: DeserializeAs<'de, K>,
VAs: DeserializeAs<'de, V>,
Seq: FromIterator<(K, V)>,
{
fn deserialize_as<D>(_deserializer: D) -> Result<Seq, D::Error>
where
D: Deserializer<'de>,
{
todo!()
}
}
I read the error index, but could not find a good way to address this for my use case.
I cannot put the types K
and V
onto the implementing type, as I do not control that type. Putting it onto the implemented trait would work in principle, but would make using the trait much harder, as now they would always need to be specified, e.g., DeserializeAs<'de, Seq, (K, V)>
. There is also no trait with an associated type I could use.
The problem with a dummy usage in the trait, is that additionally I would like to have a type like this
#[derive(Copy, Clone, Debug, Default)]
pub struct As<T>(PhantomData<T>);
impl<T> As<T> {
pub fn deserialize<'de, D, I>(deserializer: D) -> Result<I, D::Error>
where
T: DeserializeAs<'de, I>,
D: Deserializer<'de>,
{
T::deserialize_as(deserializer)
}
}
which would then need to pass the dummy types through it as well, and any user of the As
type would need to specify them manually since type inference wouldn't work here.
I would be happy to hear some ideas how this could be improved.
As some background for the types/traits. The code was suggested by @markazmierczak for serde#723, which covers improving UX for de/serialize_with inside container types. The proposed code works well for concrete types (like the Vec
) but gets hard when generalizing (like the FromIterator
).