dtolnay / serde-yaml

Strongly typed YAML library for Rust
Apache License 2.0
964 stars 164 forks source link

Unable to deserialize number as string for HashMap if flattened or inside untagged enum #414

Open vallentin opened 8 months ago

vallentin commented 8 months ago

Given the following YAML:

env:
  foo: 123

I understand why. It just feels very inconsistent. It seems that 123 gets deserialized into a number, before the context of interpreting it as a string is known. So that context is lost, and it then fails to deserialize.

Minimal Example

Rust Playground

#![allow(dead_code)]

use serde::Deserialize;
use std::collections::HashMap;

#[derive(Deserialize, Debug)]
struct Data1 {
    env: HashMap<String, String>,
}

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Data2 {
    Data { env: HashMap<String, String> },
}

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Data3 {
    Data(Data1),
}

#[derive(Deserialize, Debug)]
struct Data4 {
    #[serde(flatten)]
    dat: Data1,
}

fn main() {
    let yaml = r#"
    env:
      foo: bar
    "#;

    println!();
    let dat = serde_yaml::from_str::<Data1>(yaml); // Ok
    println!("{:?}", dat);
    let dat = serde_yaml::from_str::<Data2>(yaml); // Ok
    println!("{:?}", dat);
    let dat = serde_yaml::from_str::<Data3>(yaml); // Ok
    println!("{:?}", dat);
    let dat = serde_yaml::from_str::<Data4>(yaml); // Ok
    println!("{:?}", dat);

    let yaml = r#"
    env:
      foo: 123
    "#;

    println!();
    let dat = serde_yaml::from_str::<Data1>(yaml); // Ok
    println!("{:?}", dat);
    let dat = serde_yaml::from_str::<Data2>(yaml); // Err?
    println!("{:?}", dat);
    let dat = serde_yaml::from_str::<Data3>(yaml); // Err?
    println!("{:?}", dat);
    let dat = serde_yaml::from_str::<Data4>(yaml); // Err?
    println!("{:?}", dat);
}