Skip to content

Implement support for serde "partially untagged" enums#1521

Open
foxfriends wants to merge 1 commit into
juhaku:masterfrom
foxfriends:master
Open

Implement support for serde "partially untagged" enums#1521
foxfriends wants to merge 1 commit into
juhaku:masterfrom
foxfriends:master

Conversation

@foxfriends
Copy link
Copy Markdown

See here: https://serde.rs/variant-attrs.html#untagged

Irrespective of the enum representation, serialize and deserialize this variant as untagged, i.e. simply as the variant's data with no record of the variant name.

For a simple example:

enum SomeEnum {
    Tagged(u32)
    #[serde(untagged)]
    Untagged(u32)
}

This would serialize to an optionally tagged integer:

{"Tagged": 3}
3

With resulting JSON Schema:

{
    "oneOf": [
        {"type": "object", "properties": {"Tagged": {"type": "integer"} }, "required": ["Tagged"] },
        {"type": "integer"}
    ]
}

Somewhat related, but NOT implemented in this PR (as it seems like it will take some deeper refactoring of the "plain enum" handling):

enum SomeEnum {
    One,
    Two,
    #[serde(untagged)]
    Null
}

For this enum, serde would emit JSON values "One", "Two" and null, but utoipa still generates a JSON schema for an enum:

{
    "enum": ["One", "Two", "Null"],
    "type": "string"
}

See here: https://serde.rs/variant-attrs.html#untagged

> Irrespective of the enum representation, serialize and deserialize this variant as untagged, i.e. simply as the variant's data with no record of the variant name.

For a simple example:

```rust
enum SomeEnum {
    Tagged(u32)
    #[serde(untagged)]
    Untagged(u32)
}
```

This would serialize to an optionally tagged integer:

```json
{"Tagged": 3}
3
```

With resulting JSON Schema:

```json
{
    "oneOf": [
        {"type": "object", "properties": {"Tagged": {"type": "integer"} }, "required": ["Tagged"] },
        {"type": "integer"}
    ]
}
```

---

Somewhat related, but __NOT__ implemented in this PR (as it seems like it will take some deeper refactoring of the "plain enum" handling):

```rust
enum SomeEnum {
    One,
    Two,
    #[serde(untagged)]
    Null
}
```

For this enum, serde would emit JSON values `"One"`, `"Two"` and `null`, but utoipa still generates a JSON schema for an enum:

```json
{
    "enum": ["One", "Two", "Null"],
    "type": "string"
}
```
Comment on lines +1369 to +1371
#[test]
#[ignore = "not implemented"]
fn derive_unit_variants_serde_partially_untagged() {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this ignored test here to bring attention to the unimplemented functionality for plain enums

Comment on lines +1346 to +1367
#[test]
fn mixed_enum_serde_partially_untagged_named_fields_proof() {
#[derive(Serialize)]
enum Foo {
One {
n: i32,
},
#[serde(untagged)]
Two {
m: i32,
},
}

assert_eq!(
serde_json::to_string(&Foo::One { n: 3 }).unwrap(),
r#"{"One":{"n":3}}"#
);
assert_eq!(
serde_json::to_string(&Foo::Two { m: 3 }).unwrap(),
r#"{"m":3}"#
);
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also included these "proof" tests, to validate this behaviour of serde, since it is not as widely known as functionality. Can be removed if not wanted, as this doesn't actually test utoipa functionality, only serde functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant