michalmuskala / jason

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

Support for canonical JSON #69

Closed njouanin closed 5 years ago

njouanin commented 5 years ago

Hi, Matrix specifications defines canonical JSON as JSON where JSON encoding with dictionary keys lexicographically sorted by unicode codepoint. Does Jason support key ordering when rendering a JSON struct ?

michalmuskala commented 5 years ago

Jason supports encoding arbitrary Elixir structs in an arbitrary way. In particular, you could define a struct representing an ordered set of key-value pairs and make it encode in order.

I don't think supporting this specification directly in Jason makes much sense. The requirement of sorting strings codepoint-by-codepoint makes the sorting excruciatingly expensive and slow in the context of a simple bytestream representation of Elixir strings. Compared to the cost of that sorting, the cost of allocating additional structs and any additional protocol dispatch inside the encoder is completely negligible.

As a solution, I would propose creating a third-party package that would define that struct for ordered key-value pairs and a function to decode and sort simple maps into this structs recursively. The encoder for such a struct, assuming it's defined as defstruct pairs: [], where pairs is a simple list of tuples would be just:

defimpl Jason.Encoder, for: OrderedMap do
  def encode(%{pairs: pairs}, opts) do
    Jason.Encode.keyword(pairs, opts)
  end
end