0

I've been trying to deserialize a JSON containing an object which values can only be a String, a Boolean or a Number.

Here is the code I use for that:

use serde::{Deserialize, Serialize};
use serde_json::Number;
use std::collections::HashMap;

#[derive(Deserialize, Debug, Serialize, Clone)]
pub enum OtherValue {
  Bool(bool),
  Number(Number),
  Text(String),
}

#[derive(Deserialize, Debug, Serialize)]
pub struct Item {
  numbers: HashMap<String, Number>,
  others: HashMap<String, OtherValue>,
}

Here are the tests I put in place if you want to try it

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_deserialize_with_numbers() {
    let input_str = r#"
      {
        "numbers": {
          "key": 12.34
        },
        "others": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str).unwrap();
    assert_eq!(output.numbers.keys().len(), 1);
    assert_eq!(output.others.keys().len(), 0);
  }

  #[test]
  fn test_deserialize_with_strings() {
    let input_str = r#"
      {
        "numbers": {
          "key": "trololo"
        },
        "others": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str);
    assert_eq!(output.is_err(), true);
  }

  #[test]
  fn test_deserialize_with_boolean_field() {
    let input_str = r#"
      {
        "numbers": {
          "key": true
        },
        "others": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str);
    assert_eq!(output.is_err(), true);
  }

  #[test]
  fn test_deserialize_with_array_field() {
    let input_str = r#"
      {
        "numbers": {
          "key": ["trollo", true, 42]
        },
        "others": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str);
    assert_eq!(output.is_err(), true);
  }

  #[test]
  fn test_deserialize_with_number_tag() {
    let input_str = r#"
      {
        "others": {
          "key": 42
        },
        "numbers": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str).unwrap();
    assert_eq!(output.others.contains_key("key"), true);
  }

  #[test]
  fn test_deserialize_with_string_tag() {
    let input_str = r#"
      {
        "others": {
          "key": "trololo"
        },
        "numbers": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str).unwrap();
    assert_eq!(output.others.contains_key("key"), true);
  }

  #[test]
  fn test_deserialize_with_boolean_tag() {
    let input_str = r#"
      {
        "others": {
          "key": true
        },
        "numbers": {}
      }
    "#;
    let output = serde_json::from_str::<Item>(input_str).unwrap();
    assert_eq!(output.others.contains_key("key"), true);
  }
}

But apparently that doesn't work properly, I cannot deserialize the OtherValue.

Do you have any idea of how I could do that?

Here is a playground if you want to try it https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=67b43cfd4d12efc6641f5b7fba02889a

Jeremie
  • 378
  • 1
  • 3
  • 15
  • Does this answer your question? [Rust: Deserialize a JSON array into a very simple custom table](https://stackoverflow.com/questions/59873674/rust-deserialize-a-json-array-into-a-very-simple-custom-table) – Jmb Apr 02 '20 at 06:40
  • You want to add the tag [`#[serde(transparent)]`](https://serde.rs/container-attrs.html#transparent) to `OtherValue`. – Jmb Apr 02 '20 at 06:41
  • @Jmb this doesn't help. I get other problems now... – Jeremie Apr 02 '20 at 07:04
  • @Jmb apparently transparent is not allowed on `enums` – Jeremie Apr 02 '20 at 07:07
  • 1
    Sorry, this is the correct duplicate: https://stackoverflow.com/questions/52034764/how-do-i-serialize-an-enum-without-including-the-name-of-the-enum-variant/52035083#52035083 – Jmb Apr 02 '20 at 07:14
  • @Jmb except the link says nothing about *deserialization*, only serialisation. Sure `untagged` does work but that seems like way too eager a closing for duplication. – Masklinn Apr 02 '20 at 07:15