-
Notifications
You must be signed in to change notification settings - Fork 129
Description
Given the following nested structure (small extract from a user config):
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
struct Config {
backend: BackendConfig,
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
enum BackendConfig {
Imap(ImapConfig),
Smtp(SmtpConfig),
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
struct ImapConfig {
auth: ImapAuthConfig,
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
enum ImapAuthConfig {
Password(PasswordConfig),
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
struct SmtpConfig {
auth: SmtpAuthConfig,
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
enum SmtpAuthConfig {
Password(PasswordConfig),
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
struct PasswordConfig {
cmd: String,
}
With externally tagged enums
The following TOML string is properly parsed:
backend.imap.auth.password.cmd = "pass show password"
But this structure "allows" users to declare multiple backends, which is not possible:
backend.imap.auth.password.cmd = "pass show password"
backend.smtp.auth.password.cmd = "pass show password"
TOML parse error at line 2, column 1
|
2 | backend.imap.auth.password.cmd = "pass show password"
| ^^^^^^^
wanted exactly 1 element, more than 1 element
This representation is too permissive, it is too misleading for users and the error message is not explicit.
With internally tagged enums
By adding a #[serde(tag = "type")]
, the following string can be parsed:
backend.type = "imap"
backend.auth.type = "password"
backend.auth.cmd = "pass show password"
But the following wrong string gives a bad information about the error position: it always points to the first enum:
backend.type = "imap"
backend.auth.type = "wrong" # < wrong type
backend.auth.cmd = "pass show password"
TOML parse error at line 2, column 1
|
2 | backend.type = "imap"
| ^^^^^^^
unknown variant `wrong`, expected `password` or `oauth2`
This representation is perfect for users, and is the one I would like to keep. But the error line seems broken.
With adjacently tagged enums
By adding a #[serde(tag = "type", content = "content")]
, the following string can be parsed:
backend.type = "imap"
backend.content.auth.type = "password"
backend.content.auth.content.cmd = "pass show password"
And the previous mistake is now well reported:
backend.type = "imap"
backend.content.auth.type = "wrong"
backend.content.auth.content.cmd = "pass show password"
TOML parse error at line 3, column 29
|
3 | backend.content.auth.type = "wrong"
| ^^^^^^^
unknown variant `wrong`, expected `password` or `oauth2`
This representation reports well wrong information, but is way too verbose for users.
To summarize, I would like to keep the internally tagged enum representation but the reporting seems broken. Any idea what is going on?