Serde_json + rust_decimal

Hi,

so I hope this is the right place. I have this now:

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Input {
    #[serde(flatten)]
    pub detail: Map<String, serde_json::Value>,

    #[serde(default)]
    pub items: HashMap<String, Vec<Input>>,
}

However what I want is that integeral numbers are stored as i64 and anything with a dot as a rust_decimal::Decimal.

I can try defining my own Value class, but that sounds a bit of an undertaking due to how it must be serialized/deserialized, so I'm wondering, does anyone know a way to make this possible in an easier way?

The only straightforward way I know of (and I can't say it's an "easier way", unfortunately) is to do the String or Struct example from the official docs, except in your case it's "i64 or Decimal" (where you forward based on float and int instead of map and string).

You could try

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum Number {
    Integer(i64),
    Decimal(Decimal),
}

I think it will work but not positive

I tested it :

use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Number {
    Integer(i64),
    Decimal(Decimal),
}

fn main() {
    let input = "[1, 2, 3.14]";
    let input: Vec<Number> = serde_json::from_str(&input).unwrap();
    println!("{:?}", input);
}

It does seem to work. Output is :

[Integer(1), Integer(2), Decimal(3.14)]

@kii what kind of json objects are you expecting ? if you were able to type it more strictly than the rough "map of numbers" you'd probably get better simpler results.

This looks very promising yes. This is exactly what I wanted.

FYI, Decimals should probably be serialized and deserialized from json strings not from json numbers. Any conversion to json will lose precision (from Decimal to f64).

2 Likes