ron-rs / ron

Rusty Object Notation
https://docs.rs/ron
Apache License 2.0
3.34k stars 123 forks source link

Custom Implicit Enums #542

Open TheDudeFromCI opened 3 months ago

TheDudeFromCI commented 3 months ago

One feature that would be extremely nice to have is the ability to define custom enums to automatically unwrap as newtypes on a specific variant unless otherwise specified. By this, I mean sometime similar to how the #![enable(implicit_some)] works, but with my own enum.

Something like:

#[derive(Deserialize)]
enum Calculation {
  #[ron(implicit_value)]
  Number(i32),
  Expr(String)
}

#[derive(Deserialize)]
struct Calculator {
  a: Calculation,
  b: Calculation
}

So in the Ron file, both of these fields would be valid.

Calculator(
  a: 13,
  b: Expr("10 * 20")
)

I am requesting this feature as a way to reduce some of the verbosity of types that frequently use a specific enum variant. This is actually something I've encountered in one of my own projects. I am using a Ron file to design a config file, but almost all of the fields in the file have a wrapper that lets the value either be defined directly or load the value from a parent file at a specific path.

If this feature isn't practical to implement, is there an easy way I can write my own extension for Ron to support this?

juntyr commented 3 months ago

Thank you for the question! While it would be nice to extend the functionality that implicit Options get in RON, they are currently tied to Options being special in serde. It probably could be done similarly to how the existing feature works (checking if there is a known enum ident first before trying to parse the data as an implicit inner value as a fallback - if enabled), but I'm unsure as to how we would inform RON about the implicit variant (other than by making its name e.g. Number__ron_implicit) since RON cannot parse attributes by itself.

The more likely avenue here would be to split the enum into two parts. The first would be an untagged enum that contains the implicit variant and another newtype variant that wraps the second (externally tagged) enum, which would contain all non-implicit variants. This would have some quirks, however, as untagged enums have fun interactions in serde (see the growing list of limitations in the README).

I hope this helps! If you do come up with a nice idea for how to mark a single newtype variant as implicit, I'd be happy to review a PR that would add an extension to properly support it.