Reputation: 8069
The official JSON spec doesn't support IEEE 754, and instead has its own convention of null (not "null") or normal numbers.
In many languages and use cases people ignore this and deviate from the spec to support IEEE754 floats. For example in python
>>> json.dumps(dict(a = np.inf, b = -np.inf, c = np.nan), allow_nan=True)
'{"a": Infinity, "b": -Infinity, "c": NaN}'
The allow_nan defaults to True in this case.
Likewise in C# we can set the number handling to AllowNamedFloatingPointLiterals to get the same behaviour
So, how can we get rust/serde_json to do the same thing - is there a flag somewhere in serde_json to do this, and if not, what would be the simplest way to add this feature? (I mean achieve this feature as a user, not by updating the serde_json source or forking it or anything).
Edit: Following some of the comments, suppose we agree that JSON is at fault, is there a format that could be used in place of JSON, that fully support floats.
Alternatively, how could one implement a JSON valid alternative like using "Infinity" as a string. As far as I know this would affect all other serialisations, so if you serialise the struct to BSON, CBOR, msgpack etc.
Edit again
So my own research has thrown up a couple of possibles:
Upvotes: 5
Views: 510
Reputation: 13934
Can serde_json
be made to handle these special floats? No, because it adheres strictly to the JSON spec. However, JSON5 supports these funky floats, and serde_json5
faithfully implements JSON5:
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let map = HashMap::<_, _>::from_iter([
("a", 1.0),
("b", f64::NAN),
("c", f64::INFINITY),
("d", f64::NEG_INFINITY),
]);
let j = serde_json5::to_string(&map)?;
let o = serde_json5::from_str::<HashMap<String, f64>>(&j)?;
println!("JSON5: {}", j);
println!("HashMap: {:?}", o);
Ok(())
}
Output:
JSON5: {"a":1,"b":NaN,"d":-Infinity,"c":Infinity}
HashMap: {"a": 1.0, "d": -inf, "c": inf, "b": NaN}
Upvotes: 5
Reputation: 42572
It is unsupported.
The maintainer's answer is not entirely clear as I don't think serde_json exposes deserializer hooks through which you could add a fallback, and I would think the usual solution (deserialize_with
) would be too late for that.
So you might want to ask for precisions, but at first glance it looks like you'd have to maintain a customised vendoring / fork of serde_json to support non-standard extensions.
Upvotes: 1