Skip to content

Override enum variants without using #[serde(tag = "...")]? #147

Description

@watsaig

This may be more of a feature request or question than a bug as I think the current behavior is expected. But I fell into a bit of trap which was to assume that when using merge, later values would necessarily override earlier values.

Basically, I use Figment to merge defaults, user-provided values from a file, and CLI overrides as the docs suggest.

But if my config contains an enum where the default variant is different from the one I specify in the file, then the default one is chosen regardless of the merging strategy -- unless I annotate the enum with #[serde(tag = "...")].

Is it even possible to implement a merging strategy that would allow overriding enum variants that are externally-tagged or untagged? And if so, any plans / desire to include this in Figment?

In case it's not clear, here is some minimal code to explain the situation:

Details
use figment::{
    Figment,
    providers::{Format, Serialized, Toml},
};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
//#[serde(untagged)]
//#[serde(tag = "type")]
enum Either {
    A(A),
    B(B),
}

impl Default for Either {
    fn default() -> Self {
        Either::A(A {
            alpha: "alpha".to_string(),
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
struct A {
    alpha: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct B {
    beta: u32,
}

fn main() {
    // externally tagged (default)
    let toml_string = "b.beta = 42";
    // untagged
    //let toml_string = "beta = 42";
    // internally tagged
    //let toml_string = "type = 'b'\nbeta = 42";

    let config =
        Figment::from(Serialized::defaults(Either::default())).merge(Toml::string(toml_string));
    let config: Either = config.extract().unwrap();
    println!("{:?}", config);
    // output:
    // A(A { alpha: "alpha" })

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions