`arbitrary_precision` breaks float deserialisation in untagged enum
Without arbitrary_precision the following runs without error:
#[derive(Debug, PartialEq, serde::Deserialize)]
#[serde(untagged)]
pub enum Num {
Float(f64),
}
fn main() {
assert_eq!(serde_json::from_str::<Num>(r#"1.0"#).unwrap(), Num::Float(1f64));
}
With arbitrary_precision, serde_json::from_str::<Num>(r#"1.0"#) fails with Error("data did not match any variant of untagged enum Num", line: 0, column: 0).
This issue is similar.
See here also that the arbitary_precision feature in this case will cause the float to be parsed as a BTreeMap<String, Value> if one is available in the untagged enum: #1278
There's a similar problem with enums using #[serde(tag = "..")]:
#![allow(unused)]
#[derive(serde::Deserialize)]
#[serde(tag = "type")]
enum Outer {
A { inner: f64 },
}
fn main() {
let raw = r#"
{
"type": "A",
"inner": 0.5
}
"#;
let parsed: Outer = serde_json::from_str(raw).unwrap();
}
Output:
thread 'main' panicked at src\main.rs:17:51:
called `Result::unwrap()` on an `Err` value: Error("invalid type: map, expected f64", line: 0, column: 0)
The major problem with this is not so much that the feature is broken when combined with a variety of enum formats (although it is), but that any crate in the dependency tree that enables it can cause sudden inexplicable errors in what was previously perfect working code.
We've added a simple CI check to introspect the dependency tree for the feature, so that we can avoid production breakages like we had when we first encountered this. Replicating here in case anyone finds it useful:
if cargo tree --edges features --invert serde_json --depth 1 --prefix none |
rg 'serde_json feature "arbitrary_precision"'
then
echo "found arbitrary_precision feature: figure out how to remove from dependencies"
exit 1
else
echo "...no serde_json arbitrary_precision found!"
fi