config-rs icon indicating copy to clipboard operation
config-rs copied to clipboard

Deserializing into a `config::Value` loses `origin`

Open andor-ra2 opened this issue 3 months ago • 1 comments

I've tried searching the issue tracker for similar issues but surprisingly it seems no one has run into this so far.

Parts of my configuration is dynamic, I wanted to support this by using the exposed Value type, e.g:

struct MyConfig {
    foo: String,
    bar: i32,
    qux: HashMap<String, config::Value>,
}

And then using Config::try_deserialize. This works, insofar as I get a correctly deserialized qux field. However, it seems that the origin is lost in this case, it gets initialized to None. If I'm following the code correctly this is because during deserialization the Value type acts as both the deserializer (coming from the root Config object) as well as the target type I'm deserializing to. However, the deserialization implementation works with any generic Deserializer, so even though we're deserializing from a Value the information can't be passed along. As far as I can tell the only proper solution would have to involve specialization which we unfortunately don't have. One workaround I can think of is using Any::downcast, but perhaps that's too heavy for an admittedly niche use-case. Are there any other workarounds that I'm missing?

andor-ra2 avatar Sep 26 '25 14:09 andor-ra2

This is somewhat related to #331.

A related problem is in deserializing relative paths where their base path is the config file.

One solution I've been considering is creating a serde_relpath that is like serde_spanned or tomls Datetime where it checks for deserializing into a special wrapper struct name and then includes the extra fields.

In this case, origin would likely change from a String to an enum { Path(path), Other(description) }. Unsure if an effective base path (e.g. current_dir) should be tracked in Other we just return Option<Path>.

epage avatar Sep 26 '25 14:09 epage