Skip to content
This repository has been archived by the owner on Sep 24, 2022. It is now read-only.

externally tagged enums #225

Closed
dherman opened this issue Feb 9, 2018 · 7 comments
Closed

externally tagged enums #225

dherman opened this issue Feb 9, 2018 · 7 comments

Comments

@dherman
Copy link

dherman commented Feb 9, 2018

When you define an enum and derive Serialize or Deserialize, you might expect it to get the "externally tagged" semantics described by the serde documentation -- where each variant is represented as a table with a key named after the variant name. But AFAICT this representation doesn't work. Here's a simple example, a config format with a [main] section and a plugin field that can be one of { "url" = ...} or { "bin" = ... }:

extern crate toml;
#[macro_use]
extern crate serde_derive;
extern crate serde;

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
    pub main: Option<Main>
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename = "main")]
pub struct Main {
    pub plugin: Option<Plugin>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum Plugin {
    Url(String),
    Bin(String)
}

const SRC: &'static str = "
[main]
plugin = { \"bin\" = \"echo 'hello'\" }
";

fn main() {
    match toml::from_str::<Config>(SRC) {
        Err(e) => { eprintln!("error: {}", e); }
        Ok(result) => { eprintln!("result: {:?}", result); }
    }

}

This fails to deserialize at runtime with the error "expected string for key main.plugin". I'm not sure why.

BTW there are workarounds, e.g. to use the untagged representation:

extern crate toml;
#[macro_use]
extern crate serde_derive;
extern crate serde;

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
    pub main: Option<Main>
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename = "main")]
pub struct Main {
    pub plugin: Option<Plugin>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum Plugin {
    Url { url: String },
    Bin { bin: String }
}

const SRC: &'static str = "
[main]
plugin = { \"bin\" = \"echo 'hello'\" }
";

fn main() {
    match toml::from_str::<Config>(SRC) {
        Err(e) => { eprintln!("error: {}", e); }
        Ok(result) => { eprintln!("result: {:?}", result); }
    }

}
@azriel91
Copy link
Contributor

azriel91 commented Oct 9, 2018

Hiya, so I ran into these use cases in one of my projects, and was wondering if you think this type of usage pattern should be accepted:

For the given types:

#[derive(Debug, Deserialize)]
struct Config {
    plain: MyEnum,
    // tuple: MyEnum,
    #[serde(rename = "struct")]
    structv: MyEnum,
    newtype: MyEnum,
    my_enum: Vec<MyEnum>,
}

#[derive(Debug, Deserialize)]
enum MyEnum {
    Plain,
    Tuple(i64, bool),
    NewType(String),
    Struct { value: i64 },
}

Accept the following:

plain = "Plain"
tuple = { 0 = 123, 1 = true }
struct = { Struct = { value = 123 } }
newtype = { NewType = "value" }
my_enum = [
    { Plain = {} },
    { Tuple = { 0 = 123, 1 = true } },
    { NewType = "value" },
    { Struct = { value = 123 } }
]

So far this is what I've got:

# toml
my_enum = "UnitVariant"                             # works with current toml crate
my_enum = { UnitVariant = {} }                      # implemented on #264
my_enum = { StructVariant = { field = "value" } }   # implemented on #264
my_enum = { NewTypeVariant = { "value" } }          # implemented on #264
my_enum = { TupleVariant = { 0 = 123, 1 = false } } # implemented on #264

# Ignore
my_enum = { TupleVariant = [123, false] }           # invalid TOML

@azriel91
Copy link
Contributor

azriel91 commented Oct 9, 2018

In terms of intuitiveness and "should we support it", I think it's something like this:

# intuitive, should support
my_enum = "UnitVariant"
my_enum = { StructVariant = { field = "value" } }
my_enum = { NewTypeVariant = { "value" } }

# not intuitive, should support
my_enum = { UnitVariant = {} } # necessary for a vector of enums

# not intuitive, maybe support
my_enum = { TupleVariant = { 0 = 123, 1 = false } }

# not intuitive, should not support
my_enum = "value" # for NewTypeVariant

azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 9, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 21, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 21, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 21, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 21, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 21, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 22, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 22, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 22, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Oct 22, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 9, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 9, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 9, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 9, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 9, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 11, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 11, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 16, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 16, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 17, 2018
azriel91 added a commit to azriel91/toml-rs that referenced this issue Nov 17, 2018
@internally-combusted
Copy link

Does this kind of enum currently only work with the inline table syntax?

Given:

// Rust code
struct Vec2 {
    x: f32,
    y: f32,
}

struct TransformData {
    translation: Vec2,
    scaling: Vec2,
    rotation: f32,
}

enum ComponentData {
    Transform {
        transform_data: TransformData, 
    }
}

struct Component {
    data: ComponentData,
}

I can get something like this to deserialize:

# TOML
data = { Transform = { translation = { x = 100.0, y = 100.0 }, scaling = { x = 100.0, y = 100.0}, rotation = 1.0 } }

So the inline table format works, but unless I've misread something, inline tables have to be on a single line, so any non-trivial variant is going to be several screens long.

I've tried about seventeen different ways of using the [brackety] table syntax for the above, but I can't get anything to parse.

@ehuss
Copy link
Collaborator

ehuss commented Mar 14, 2019

@internally-combusted Unfortunately it looks like the enum support only handles inline tables.

@azriel91
Copy link
Contributor

I've tried about seventeen different ways of using the [brackety] table syntax for the above, but I can't get anything to parse.

oh yes, attempted to get the full [table] syntax working, but had trouble understanding the code -- overwhelmed by too much information 🙁

Twey added a commit to hadeaninc/toml-rs that referenced this issue Sep 4, 2019
Add support for deserializing enums from dotted tables à la toml-rs#225.
johansglock added a commit to johansglock/toml-rs that referenced this issue Dec 3, 2019
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
@johansglock
Copy link

Ive opened a PR to get full tables working with enums. Feedback welcome to get this merged in!

jsgf pushed a commit to jsgf/toml-rs that referenced this issue Apr 29, 2020
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
jsgf pushed a commit to jsgf/toml-rs that referenced this issue Dec 15, 2020
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
vgao1996 pushed a commit to vgao1996/toml-rs that referenced this issue Jul 23, 2021
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
dtolnay pushed a commit to fbsource/toml that referenced this issue Oct 21, 2021
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
HarveyHunt pushed a commit to HarveyHunt/toml-rs that referenced this issue Oct 21, 2021
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
brianc118 pushed a commit to brianc118/toml-rs that referenced this issue Oct 21, 2021
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
HarveyHunt pushed a commit to HarveyHunt/toml-rs that referenced this issue Nov 9, 2021
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
HarveyHunt pushed a commit to HarveyHunt/toml-rs that referenced this issue Jun 11, 2022
Use the current referenced table instead of assuming we should only have
1 table, allowing for more complex parsing of enum structures.
Similarly, depending on the context, values can be in either the table
or in the current values context. Take them as appropriate.
@epage
Copy link
Member

epage commented Sep 23, 2022

Maintenance of this crate has moved to the https://github.com/toml-rs/toml repo. As a heads up, we plan to move toml to be on top of toml_edit, see toml-rs/toml#340.

Closing this out. If this is still a problem, feel free to recreate this issue in the new repo.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants