Hi Rust Users,
I am trying to write a generic struct
use serde::*;
struct A;
struct B;
struct Setting<AB, T> {
ab: PhantomData<AB>,
t: T,
}
// Only for Setting<A, _>
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Setting<A, T> {
fn deserialize<D>(_: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
panic!("")
}
}
#[derive(Deserialize)]
struct Config<AB> {
f: Setting<AB, f64>,
}
I want to derive Deserialize
only for the case Config<A>
, where A
implements it's own Deserialize
. I still want to use Config<B>
elsewhere (for example convert Config<A>
to it after it was deserialized), but it itself does not have to be deserializable.
A
and B
are just empty type "tags" to represent states in which Config
and Setting
can be. Imagine Unvalidated
or Validated
where validation can only be done after parsing, something like that. Or imagine an Expression
form of a Setting
with placeholders and templates, and then Final
one where placeholders in a string are filled and type converted. The rest of the code can just use the final form Config<B>
, after initialization has built it from Config<A>
.
This code fails to compile for understandable reasons:
error[E0277]: the trait bound `Setting<AB, f64>: _serde::Deserialize<'_>` is not satisfied
--> src/main.rs:23:8
|
23 | f: Setting<AB, f64>,
| ^^^^^^^^^^^^^^^^ the trait `_serde::Deserialize<'_>` is not implemented for `Setting<AB, f64>`
|
note: required by a bound in `next_element`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.160/src/de/mod.rs:1729:12
|
1729 | T: Deserialize<'de>,
| ^^^^^^^^^^^^^^^^ required by this bound in `SeqAccess::next_element`
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
21 | #[derive(Deserialize, Setting<AB, f64>: _serde::Deserialize<'_>)]
| +++++++++++++++++++++++++++++++++++++++++++
Deserialize tries to derive the implementation for any AB, but it cannot possibly do that. serde(bound(...))
is not quite it, because there is no traits here, it's just structs. Implementing custom Deserialize
for Config<A>
will quickly become unfeasible to maintain as I add 50 fields there with child sub-structures that all internally use Setting<AB, ...>
.
I wonder if there is still a chance for bound
via some non-trivial use of traits.
Or is there a way to use bound
on Config
somehow to narrow down any internal Settings<AB, _>: Deserialize
? Not ideal again, as if Config will start using child structures containing Settings<AB, _>
, they will have to be declared in the bound
too. Ok to declare annotations on their definitions, but not on definitions wherever they are used, that will be too much to maintain.
Thanks, any ideas appreciated!