-
Notifications
You must be signed in to change notification settings - Fork 601
Open
Description
I am not sure whether this is a bug or a feature, but I did not manage to find any explanation behind it.
If an enum is tagged internally and it is flattened in the outer struct, then the tag can be either a string or a number (position in the enum) while deserialization. The serializer always produces a string though.
If the enum is not flattened, then the tag can be only a string.
Please consider the code below:
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
#[serde(rename_all = "snake_case")]
struct A {
name: String,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
struct B {
num: i64,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
#[serde(tag = "tx_type"/* , content = "value" */)]
#[non_exhaustive]
enum Types {
A(A),
B(B),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
struct OuterFlattened {
#[serde(flatten)]
types: Types,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
struct OuterUnFlattened {
types: Types,
}
pub fn main() {
let type_a_num = r#"{"tx_type" :0, "name":"Alice"}"#;
let type_b_num = r#"{"tx_type" :1, "num":42}"#;
let type_a_num: OuterFlattened = serde_json::from_str(&type_a_num).unwrap();
let type_b_num: OuterFlattened = serde_json::from_str(&type_b_num).unwrap();
let type_a_str = r#"{"tx_type": "A", "name":"Alice"}"#;
let type_b_str = r#"{"tx_type": "B", "num":42}"#;
let type_a_str: OuterFlattened = serde_json::from_str(&type_a_str).unwrap();
let type_b_str: OuterFlattened = serde_json::from_str(&type_b_str).unwrap();
assert_eq!(type_a_num, type_a_str);
assert_eq!(type_b_num, type_b_str);
println!("EQUAL!");
let type_a_num_ = r#"{"types":{"tx_type": 0,"name":"Alice"}}"#;
let type_a_str_ = r#"{"types":{"tx_type": "A","name":"Alice"}}"#;
let a_num: OuterUnFlattened = serde_json::from_str(&type_a_num_).unwrap();
let a_str: OuterUnFlattened = serde_json::from_str(&type_a_str_).unwrap();
assert_eq!(a_num, a_str);
}
Output:
cargo r
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/serde_enum_tag_num`
EQUAL!
thread 'main' panicked at src/main.rs:54:70:
called `Result::unwrap()` on an `Err` value: Error("invalid type: integer `0`, expected variant identifier", line: 1, column: 22)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Version:
rustc --version
rustc 1.86.0 (05f9846f8 2025-03-31)
Metadata
Metadata
Assignees
Labels
No labels