Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vendor Jason to prevent conflicts #110

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Jason
# JasonVendored

A blazing fast JSON parser and generator in pure Elixir.

The parser and generator are at least twice as fast as other Elixir/Erlang libraries
(most notably `Poison`).
The performance is comparable to `jiffy`, which is implemented in C as a NIF.
Jason is usually only twice as slow.
JasonVendored is usually only twice as slow.

Both parser and generator fully conform to
[RFC 8259](https://tools.ietf.org/html/rfc8259) and
Expand All @@ -26,10 +26,10 @@ end
## Basic Usage

``` elixir
iex(1)> Jason.encode!(%{"age" => 44, "name" => "Steve Irwin", "nationality" => "Australian"})
iex(1)> JasonVendored.encode!(%{"age" => 44, "name" => "Steve Irwin", "nationality" => "Australian"})
"{\"age\":44,\"name\":\"Steve Irwin\",\"nationality\":\"Australian\"}"

iex(2)> Jason.decode!(~s({"age":44,"name":"Steve Irwin","nationality":"Australian"}))
iex(2)> JasonVendored.decode!(~s({"age":44,"name":"Steve Irwin","nationality":"Australian"}))
%{"age" => 44, "name" => "Steve Irwin", "nationality" => "Australian"}
```

Expand All @@ -39,17 +39,17 @@ Full documentation can be found at [https://hexdocs.pm/jason](https://hexdocs.pm

### Postgrex

Versions starting at 0.14.0 use `Jason` by default. For earlier versions, please refer to
Versions starting at 0.14.0 use `JasonVendored` by default. For earlier versions, please refer to
[previous versions of this document](https://github.com/michalmuskala/jason/tree/v1.1.2#postgrex).

### Ecto

Versions starting at 3.0.0 use `Jason` by default. For earlier versions, please refer to
Versions starting at 3.0.0 use `JasonVendored` by default. For earlier versions, please refer to
[previous versions of this document](https://github.com/michalmuskala/jason/tree/v1.1.2#ecto).

### Plug (and Phoenix)

Phoenix starting at 1.4.0 uses `Jason` by default. For earlier versions, please refer to
Phoenix starting at 1.4.0 uses `JasonVendored` by default. For earlier versions, please refer to
[previous versions of this document](https://github.com/michalmuskala/jason/tree/v1.1.2#plug-and-phoenix).

### Absinthe
Expand All @@ -60,12 +60,12 @@ You need to pass the `:json_codec` option to `Absinthe.Plug`
# When called directly:
plug Absinthe.Plug,
schema: MyApp.Schema,
json_codec: Jason
json_codec: JasonVendored

# When used in phoenix router:
forward "/api",
to: Absinthe.Plug,
init_opts: [schema: MyApp.Schema, json_codec: Jason]
init_opts: [schema: MyApp.Schema, json_codec: JasonVendored]
```

## Benchmarks
Expand All @@ -85,24 +85,24 @@ A HTML report of the benchmarks (after their execution) can be found in

## Differences to Poison

Jason has a couple feature differences compared to Poison.
JasonVendored has a couple feature differences compared to Poison.

* Jason follows the JSON spec more strictly, for example it does not allow
* JasonVendored follows the JSON spec more strictly, for example it does not allow
unescaped newline characters in JSON strings - e.g. `"\"\n\""` will
produce a decoding error.
* no support for decoding into data structures (the `as:` option).
* no built-in encoders for `MapSet`, `Range` and `Stream`.
* no support for encoding arbitrary structs - explicit implementation
of the `Jason.Encoder` protocol is always required.
of the `JasonVendored.Encoder` protocol is always required.
* different pretty-printing customisation options (default `pretty: true` works the same)

If you require encoders for any of the unsupported collection types, I suggest
adding the needed implementations directly to your project:

```elixir
defimpl Jason.Encoder, for: [MapSet, Range, Stream] do
defimpl JasonVendored.Encoder, for: [MapSet, Range, Stream] do
def encode(struct, opts) do
Jason.Encode.list(Enum.to_list(struct), opts)
JasonVendored.Encode.list(Enum.to_list(struct), opts)
end
end
```
Expand All @@ -112,7 +112,7 @@ if you own the struct, you can derive the implementation specifying
which fields should be encoded to JSON:

```elixir
@derive {Jason.Encoder, only: [....]}
@derive {JasonVendored.Encoder, only: [....]}
defstruct # ...
```

Expand All @@ -121,21 +121,21 @@ used carefully to avoid accidentally leaking private information
when new fields are added:

```elixir
@derive Jason.Encoder
@derive JasonVendored.Encoder
defstruct # ...
```

Finally, if you don't own the struct you want to encode to JSON,
you may use `Protocol.derive/3` placed outside of any module:

```elixir
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(Jason.Encoder, NameOfTheStruct)
Protocol.derive(JasonVendored.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(JasonVendored.Encoder, NameOfTheStruct)
```

## License

Jason is released under the Apache License 2.0 - see the [LICENSE](LICENSE) file.
JasonVendored is released under the Apache License 2.0 - see the [LICENSE](LICENSE) file.

Some elements of tests and benchmarks have their origins in the
[Poison library](https://github.com/devinus/poison) and were initially licensed under [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
24 changes: 12 additions & 12 deletions bench/decode.exs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
decode_jobs = %{
"Jason" => fn {json, _} -> Jason.decode!(json) end,
"JasonVendored" => fn {json, _} -> JasonVendored.decode!(json) end,
"Poison" => fn {json, _} -> Poison.decode!(json) end,
"JSX" => fn {json, _} -> JSX.decode!(json, [:strict]) end,
"Tiny" => fn {json, _} -> Tiny.decode!(json) end,
"jsone" => fn {json, _} -> :jsone.decode(json) end,
"jiffy" => fn {json, _} -> :jiffy.decode(json, [:return_maps, :use_nil]) end,
"JSON" => fn {json, _} -> JSON.decode!(json) end,
"JSX" => fn {json, _} -> JSX.decode!(json, [:strict]) end,
"Tiny" => fn {json, _} -> Tiny.decode!(json) end,
"jsone" => fn {json, _} -> :jsone.decode(json) end,
"jiffy" => fn {json, _} -> :jiffy.decode(json, [:return_maps, :use_nil]) end,
"JSON" => fn {json, _} -> JSON.decode!(json) end
# "binary_to_term/1" => fn {_, etf} -> :erlang.binary_to_term(etf) end,
}

Expand All @@ -19,32 +19,32 @@ decode_inputs = [
"JSON Generator (Pretty)",
"UTF-8 escaped",
"UTF-8 unescaped",
"Issue 90",
"Issue 90"
]

read_data = fn (name) ->
read_data = fn name ->
file =
name
|> String.downcase
|> String.downcase()
|> String.replace(~r/([^\w]|-|_)+/, "-")
|> String.trim("-")

json = File.read!(Path.expand("data/#{file}.json", __DIR__))
etf = :erlang.term_to_binary(Jason.decode!(json))
etf = :erlang.term_to_binary(JasonVendored.decode!(json))

{json, etf}
end

inputs = for name <- decode_inputs, into: %{}, do: {name, read_data.(name)}

Benchee.run(decode_jobs,
# parallel: 4,
# parallel: 4,
warmup: 5,
time: 30,
memory_time: 1,
inputs: inputs,
formatters: [
{Benchee.Formatters.HTML, file: Path.expand("output/decode.html", __DIR__)},
Benchee.Formatters.Console,
Benchee.Formatters.Console
]
)
40 changes: 20 additions & 20 deletions bench/encode.exs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
encode_jobs = %{
"Jason" => &Jason.encode_to_iodata!/1,
"Jason strict" => &Jason.encode_to_iodata!(&1, maps: :strict),
"Poison" => &Poison.encode_to_iodata!/1,
"JSX" => &JSX.encode!/1,
"Tiny" => &Tiny.encode!/1,
"jsone" => &:jsone.encode/1,
"jiffy" => &:jiffy.encode/1,
"JSON" => &JSON.encode!/1,
"JasonVendored" => &JasonVendored.encode_to_iodata!/1,
"JasonVendored strict" => &JasonVendored.encode_to_iodata!(&1, maps: :strict),
"Poison" => &Poison.encode_to_iodata!/1,
"JSX" => &JSX.encode!/1,
"Tiny" => &Tiny.encode!/1,
"jsone" => &:jsone.encode/1,
"jiffy" => &:jiffy.encode/1,
"JSON" => &JSON.encode!/1
# "term_to_binary" => &:erlang.term_to_binary/1,
}

Expand All @@ -18,31 +18,31 @@ encode_inputs = [
"Pokedex",
"JSON Generator",
"UTF-8 unescaped",
"Issue 90",
"Issue 90"
]

read_data = fn (name) ->
read_data = fn name ->
name
|> String.downcase
|> String.downcase()
|> String.replace(~r/([^\w]|-|_)+/, "-")
|> String.trim("-")
|> (&"data/#{&1}.json").()
|> Path.expand(__DIR__)
|> File.read!
|> File.read!()
end


Benchee.run(encode_jobs,
# parallel: 4,
# parallel: 4,
warmup: 5,
time: 30,
memory_time: 1,
inputs: for name <- encode_inputs, into: %{} do
name
|> read_data.()
|> Jason.decode!()
|> (&{name, &1}).()
end,
inputs:
for name <- encode_inputs, into: %{} do
name
|> read_data.()
|> JasonVendored.decode!()
|> (&{name, &1}).()
end,
formatters: [
{Benchee.Formatters.HTML, file: Path.expand("output/encode.html", __DIR__)},
Benchee.Formatters.Console
Expand Down
4 changes: 2 additions & 2 deletions bench/mix.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule JasonBench.MixProject do
defmodule JasonVendoredBench.MixProject do
use Mix.Project

def project do
Expand Down Expand Up @@ -30,7 +30,7 @@ defmodule JasonBench.MixProject do
{:tiny, "~> 1.0"},
{:jsone, "~> 1.4"},
{:jiffy, "~> 0.14"},
{:json, "~> 1.0"},
{:json, "~> 1.0"}
]
end
end
10 changes: 5 additions & 5 deletions dialyzer.ignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Unknown function 'Elixir.Jason.Encoder.Function':'__impl__'/1
Unknown function 'Elixir.Jason.Encoder.PID':'__impl__'/1
Unknown function 'Elixir.Jason.Encoder.Port':'__impl__'/1
Unknown function 'Elixir.Jason.Encoder.Reference':'__impl__'/1
Unknown function 'Elixir.Jason.Encoder.Tuple':'__impl__'/1
Unknown function 'Elixir.JasonVendored.Encoder.Function':'__impl__'/1
Unknown function 'Elixir.JasonVendored.Encoder.PID':'__impl__'/1
Unknown function 'Elixir.JasonVendored.Encoder.Port':'__impl__'/1
Unknown function 'Elixir.JasonVendored.Encoder.Reference':'__impl__'/1
Unknown function 'Elixir.JasonVendored.Encoder.Tuple':'__impl__'/1
14 changes: 7 additions & 7 deletions lib/codegen.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Jason.Codegen do
defmodule JasonVendored.Codegen do
@moduledoc false

alias Jason.{Encode, EncodeError}
alias JasonVendored.{Encode, EncodeError}

def jump_table(ranges, default) do
ranges
Expand Down Expand Up @@ -93,12 +93,12 @@ defmodule Jason.Codegen do
defp ranges_to_orddict(ranges) do
ranges
|> Enum.flat_map(fn
{int, value} when is_integer(int) ->
[{int, value}]
{int, value} when is_integer(int) ->
[{int, value}]

{enum, value} ->
Enum.map(enum, &{&1, value})
end)
{enum, value} ->
Enum.map(enum, &{&1, value})
end)
|> :orddict.from_list()
end

Expand Down
Loading