michalmuskala / jason

A blazing fast JSON parser and generator in pure Elixir.
Other
1.6k stars 170 forks source link

Callbacks for handling int and float conversion #130

Closed klittlepage closed 2 years ago

klittlepage commented 3 years ago

Hi @michalmuskala, thank you jason! I have a use case that necessitates special handling for json number types. The python json module handles this elegantly via the parse_float and parse_int callbacks. I've patched jason to do the same and wanted to know if you're open to a PR.

These callbacks are different from #124 and structural decoding in that they operates on primitive types. It's impossible to get at what I (and presumably others?) need to do higher in the decoding stack, given that there isn't a bijection between numeric types and the strings from which they originated. For example, assert parse!("-0") == 0 is true numerically, but an application computing a structural hash on the concrete syntax tree of parsed json needs to know that the original string was -0, lexed as ['-', '0'].

The change shouldn't be breaking; decode_opt would be expanded to accept callbacks for parse_float, parse_int, and parse_constant for handling true, false, and null. The changes to the decoder are minor surgery.

I'd need to do a touch of work to port this back to jason, so I wanted to check with you before opening a PR. Thanks!

michalmuskala commented 2 years ago

With #115 merged we have float to decimal parsing.

TBH I'm not convinced about supporting this for integers by the reasoning of decode -> encode roundtrip being lossless. There are other issues that might cause lossy encoding in a case like that, which would prevent that from working. For example:

iex(2)> Jason.decode!(~S'"\ud83d\ude05"')
"😅"
iex(3)> Jason.encode!(v())
"\"😅\""

If you need to compute hash of JSON data, the only reliable way is to do it before decoding.