Here's a config file I would like to be able to write:
potential:
- kc-z:
# cutoff: 11
- rebo:
params: lammps
phonons:
eigensolver: dense
Unfortunately, I am instead forced to write:
potential:
- kc-z: {}
# cutoff: 11
- rebo:
params:
lammps: {}
phonons:
eigensolver:
dense: {}
Why? Well:
- Thanks to the commented-out line,
kc-z:actually had no key-value pairs. Empty mappings and empty sequences are inexpressable in YAML block syntax, and so it ends up being equivalent tokc-z: null. -
denseandlammpsare supposed to be unitlike enum variants. However, even though they currently have no fields, there is a remote possibility that I might want to add some optional fields in the future. A struct variant is not capable of deserializing from a string like a unit variant is. Therefore, for future compatibility, I am forced to define the enum variants as empty struct variants with braces.
#[derive(Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum PhononEigensolver {
#[serde(rename_all = "kebab-case")]
Dense {}, // <-- braces in case fields are ever added
// other variants...
}
It would be great if I could somehow get these types to be more permissive in their deserialization:
- Allow
nullto be deserialized as an empty structFoo {}, or as the body for an enum variantEnum::Foo {}. - Allow
nullto be deserialized as an emptyVec<_>. - Allow a string to be deserialized as an empty struct enum variant
Enum::Foo {}.
Unfortunately, I think that all of this behavior is determined by the Deserialize impl, which means that my possible options are either to find a way to do this with #[serde] annotations, or to give up #[derive(Deserialize)]. I'm not sure about the former, and the latter is absolutely infeasible.
Is there a way to do this that I'm not seeing?