Support partially tagged enums - #1585
Conversation
Based on juhaku#1521 - merge conflicts resolved. 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" } ```
Set EnumSchemaType to Mixed rather than Plain for partially untagged unit variant enums; this ensures schema is oneOf [enum, null] rather than a flat enum list.
|
Hi, thanks for contribution - https://github.com/fnimick/utoipa/blob/58eb1dbda4a04831e899eadd1be943e6d03296cb/utoipa-gen/src/lib.rs#L489 would you mind changing this? Plus please add the changelog :) |
| { | ||
| .map(|variant| { | ||
| Ok(matches!(variant.fields, Fields::Unit) | ||
| && !serde::parse_value(&variant.attrs)?.untagged) |
There was a problem hiding this comment.
suggestion: I read the whole related code more carefully so from what I understood https://github.com/fnimick/utoipa/blob/58eb1dbda4a04831e899eadd1be943e6d03296cb/utoipa-gen/src/component/schema/enums.rs#L63C13-L63C70 is executed the duplicated per-variant parse. Do you think we can eliminate this? If not, we can keep it as it is.
Remove duplicate serde::parse_value Filter skipped enums before determining whether enum is all unit and non untagged - simplifies output
|
@Drifter-J I realized a potential issue in the output. An enum with the format: generates an openapi schema of: Is this an issue, that the untagged string branch is duplicated? A similar issue happens with partially untagged unit enums, where there are duplicate |
Yes, it doesn't look like a valid schema and it seems like Three is collapsed as well. I would suggest fixing duplication at codegen time |
Heavily based on #1521 - merge conflicts fixed, with additional tests added for the internally tagged and adjacently tagged serde options.
In addition, this now supports untagged members on plain enums, which were not implemented in the initial PR.
Original PR Message
See here: https://serde.rs/variant-attrs.html#untagged
For a simple example:
This would serialize to an optionally tagged integer:
{"Tagged": 3} 3With 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):
For this enum, serde would emit JSON values
"One","Two"andnull, but utoipa still generates a JSON schema for an enum:{ "enum": ["One", "Two", "Null"], "type": "string" }