feat: implement into serde_json Value for Decimal#790
Conversation
| impl From<Decimal> for serde_json::Value { | ||
| fn from(decimal: Decimal) -> serde_json::Value { | ||
| use num_traits::ToPrimitive; | ||
| decimal.to_f64().unwrap().into() |
There was a problem hiding this comment.
Using as_f64 doesn't need the trait, and doesn't return an Option, so we don't need the unwrap.
There was a problem hiding this comment.
Okay. this was copied from the Serialize implementation. But I can try to remove it if necessary... but if it didn't return an Option, then it wouldn't compile? But it compiles with the unwrap.
My intuition told me that these implementations should be essentially the exact same as the Serialize implementations.
| } | ||
| } | ||
|
|
||
| #[cfg(all(feature = "serde_json", feature = "serde-float", not(feature = "serde-arbitrary-precision")))] |
There was a problem hiding this comment.
Is there deliberately no implementation for serde-float with serde-arbitrary-precision?
There was a problem hiding this comment.
Yes because from what I saw it looked like that combination can potentially error? Which means TryFrom would be needed instead of From?
There was a problem hiding this comment.
Then this should probably implement TryFrom, instead of From, at which point we can just call Serialize directly and not need to worry about parallel implementations.
There was a problem hiding this comment.
Just for the serde-float and serde-arbitrary-precision combination? The others will remain the same? Or use serde_json::to_value for all, and unwrap the other two?
There was a problem hiding this comment.
Ah, I missed that the trait needs From in particular. That's annoying. But yeah, we can't guarantee that we can implement From cleanly, we shouldn't be implementing it with unwrap, and we shouldn't have a From implementation that disappears with additive features.
I'm not sure this really fits if it has to be a From implementation. Maybe you would be better off using a wrapper type for your specific case.
I've not dug into garde though, maybe there's a way to do it with fallible conversions, or without conversions?
There was a problem hiding this comment.
But yeah, we can't guarantee that we can implement From cleanly, we shouldn't be implementing it with unwrap, and we shouldn't have a From implementation that disappears with additive features.
This one makes sense. Having different feature flags change what trait is implemented in std library is a bit awkward. One solution could be to fallback to Value::String if the arbitrary precision fails.
Something like this:
impl From<Decimal> for Value {
fn from(d: Decimal) -> Self {
#[cfg(all(feature = "serde-float", feature = "serde-arbitrary-precision"))]
{
if let Ok(n) = serde_json::Number::from_str(&d.to_string()) {
return Value::Number(n);
}
return Value::String(d.to_string());
}
#[cfg(all(feature = "serde-float", not(feature = "serde-arbitrary-precision")))]
{
return Value::from(d.as_f64());
}
#[cfg(not(feature = "serde-float"))]
{
return Value::String(d.to_string());
}
}
}There was a problem hiding this comment.
With arbitrary precision enabled, serde_json::Number is just String, so I think we should be able to set it infallibly?
There was a problem hiding this comment.
@Tony-Samuels I've pushed a new commit, which is essentially my code above but without trying to parse to serde_json::Number first.
There was a problem hiding this comment.
Sorry for the delay, I went to look into other options and forgot to respond...
The new implementation goes to Value::String isn't consistent with Serialize, so unfortunately you were probably right in that we need to do from_str. I guess the best we can do is an expect explaining that serde_json with arbitrary-percision shouldn't be able to fail the check, as well as some thorough tests written to validate that the behaviour doesn't change in the future.
There was a problem hiding this comment.
Sounds like proptest/quickcheck territory. I see one of those is already a workspace dep.
| rust-fuzz = ["dep:arbitrary"] | ||
| serde = ["dep:serde"] | ||
| serde-arbitrary-precision = ["serde-with-arbitrary-precision"] | ||
| serde-arbitrary-precision = ["serde-json", "serde-with-arbitrary-precision"] |
There was a problem hiding this comment.
serde-with-arbitrary-precision already includes serde-json, including with the arbitrary_precision force enabled.
4c87fdb to
d09ba8d
Compare
210f014 to
505f52e
Compare
|
I fixed up the PR so it would compile + added tests (while keeping it consistent with existing patterns - I think a separate PR can sweep up the Note, this is currently targeting |
This PR implements
From<Decimal> for serde_json::Value, givenserde_jsonfeature flag is enabled (andserde-arbitrary-precisionis disabled).The motivation for this is that my validation with garde has compile errors when used with schemars.